SpringCloud 负载均衡 spring-cloud-starter-loadbalancer

简述

spring-cloud-starter-loadbalancer 是 Spring Cloud 中的一个组件,它提供了客户端负载均衡的功能。在 Spring Cloud 的早期版本中,Netflix Ribbon 被广泛用作客户端负载均衡器,但随着时间推移和 Netflix Ribbon 进入维护模式,Spring Cloud 社区开始转向更灵活、更易于维护的替代方案。

spring-cloud-starter-loadbalancer 是基于 Spring 5 的 WebClient 构建的,并使用了 Reactor(Spring 5 的反应式编程模型的核心库)来实现异步非阻塞的负载均衡请求。它与 Spring Cloud 的服务发现和配置结合得非常好,可以很容易地与 Eureka、Consul、Nacos 等服务发现组件一起使用。

当将 spring-cloud-starter-loadbalancer 添加到Spring Boot 应用程序中时,可以使用 WebClient.Builder 的 loadBalancer 方法来创建一个具有负载均衡功能的 WebClient 实例。这个 WebClient 实例会自动从服务发现中获取服务实例列表,并使用内置的负载均衡算法(如轮询、随机等)来选择一个服务实例来发送请求。

例如,如果正在使用 Eureka 作为服务发现,并且想要发送一个 GET 请求到名为 “my-service” 的服务,可以这样做:

import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.cloud.client.loadbalancer.LoadBalanced;  
import org.springframework.context.annotation.Bean;  
import org.springframework.stereotype.Service;  
import org.springframework.web.reactive.function.client.WebClient;  @Service  
public class MyServiceClient {  @Autowired  private WebClient.Builder webClientBuilder;  @Bean  @LoadBalanced  public WebClient.Builder loadBalancedWebClientBuilder() {  return WebClient.builder();  }  public String getSomethingFromMyService() {  // 注意这里我们直接使用了 "my-service" 作为 URI,而不是具体的服务实例地址  return webClientBuilder.build()  .get()  .uri("http://my-service/some-endpoint")  .retrieve()  .bodyToMono(String.class)  .block(); // 注意:block() 方法会阻塞当前线程,通常只在非反应式上下文中使用  }  
}

主要特点

  • 基于 WebClient:与 Spring 5 的 WebClient 紧密集成,提供了反应式(Reactive)的 HTTP 客户端功能。
  • 服务发现集成:与 Spring Cloud 的服务发现组件(如 Eureka、Consul、Nacos 等)集成,可以自动获取服务实例列表。
  • 内置负载均衡算法:提供了内置的负载均衡算法,如轮询(Round Robin)、随机(Random)等。
  • 反应式编程:支持反应式编程模型,允许非阻塞的 I/O 操作和异步处理。
  • 灵活性:与 Ribbon 相比,提供了更多的灵活性和扩展性,可以更容易地定制负载均衡行为。
  • 与 Spring Cloud Gateway 集成:与 Spring Cloud Gateway 紧密集成,为其提供了负载均衡功能。

使用

  1. 添加依赖:在 Maven 或 Gradle 项目中添加 spring-cloud-starter-loadbalancer 依赖。
		<!-- SpringCloud Loadbalancer --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency>
  1. 配置 WebClient:使用 @LoadBalanced 注解来标记一个 WebClient.Builder Bean,以便将其配置为支持负载均衡。
  2. 发送请求:通过 WebClient 发送请求时,使用服务名称(而不是具体的服务实例地址)作为 URI 的主机部分。
  3. 自定义负载均衡算法:如果需要,可以自定义负载均衡算法,并通过配置或编程方式将其应用到 WebClient 上。

注意事项

  1. 阻塞调用:虽然 WebClient 是反应式的,但在某些情况下(如与同步代码交互时),可能需要使用 block() 方法来阻塞当前线程并等待响应。但应尽量避免在反应式上下文中使用 block()。
  2. 配置:负载均衡器的行为可以通过配置进行定制,包括选择负载均衡算法、设置超时时间等。
  3. 服务发现:确保应用程序已经正确配置了服务发现组件(如 Eureka、Consul 等),以便 spring-cloud-starter-loadbalancer 能够获取服务实例列表。
  4. 版本兼容性:注意 spring-cloud-starter-loadbalancer 与其他 Spring Cloud 组件的版本兼容性,确保它们能够协同工作。

负载均衡算法

1. 轮询负载均衡策略(Round Robin)

  • 描述:这是默认的负载均衡策略,它会按照顺序依次将请求发送到服务实例列表中的每个服务实例。
  • 特点
    • 简单易实现。
    • 每个服务实例接收到的请求数量大致相等(在理想情况下)。
    • 不考虑服务实例的当前负载状态或性能。

2. 随机负载均衡策略(Random)

  • 描述:该策略会随机选择一个服务实例来发送请求。
  • 特点
    • 在多次请求中,每个服务实例都有可能被选中。
    • 与轮询策略相比,它增加了随机性,但每个服务实例接收到的请求数量可能不均等。
    • 同样不考虑服务实例的当前负载状态或性能。

3. 自定义负载均衡策略

  • 描述:除了内置的负载均衡策略外,spring-cloud-starter-loadbalancer 还支持自定义负载均衡策略。
  • 特点
    • 开发者可以根据实际需求实现自己的负载均衡算法。
    • 可以考虑服务实例的当前负载状态、性能、地理位置等多种因素来做出决策。
    • 提供了更高的灵活性和定制性。

4. Nacos 权重负载均衡器

  • 描述:当与 Nacos 服务发现组件一起使用时,可以使用 Nacos 提供的权重负载均衡器。
  • 特点
    • 服务实例可以配置权重值,权重值越高的实例接收到的请求越多。
    • 权重值可以根据服务实例的性能、资源使用情况等因素进行动态调整。
    • 提供了更细粒度的控制,可以根据实际需求进行灵活配置。

5. 自定义算法

通过实现自定义的 ReactorLoadBalancer 来定义自己的负载均衡算法。

  1. 定义自定义的负载均衡器:需要实现 ReactorLoadBalancer 接口或扩展现有的实现(如 RoundRobinLoadBalancer)。
  2. 实现 choose 方法:这是负载均衡算法的核心,它接收一个请求(通常是一个 Request 对象)和一个服务实例列表(ServiceInstanceListSupplier),并返回一个 Mono,表示选定的服务实例。
  3. 配置自定义的负载均衡器:需要将自定义的负载均衡器配置为 Spring Cloud 的默认负载均衡器。这通常是通过注册一个 ReactorLoadBalancer 的 Bean 来完成的。
    示例:
import org.springframework.cloud.client.ServiceInstance;  
import org.springframework.cloud.client.loadbalancer.DefaultRequest;  
import org.springframework.cloud.client.loadbalancer.ReactiveLoadBalancer;  
import org.springframework.cloud.client.loadbalancer.ReactiveLoadBalancerFactory;  
import org.springframework.cloud.client.ServiceInstanceChooser;  
import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  
import reactor.core.publisher.Mono;  import java.util.List;  @Configuration  
public class CustomLoadBalancerConfig {  @Bean  public ReactiveLoadBalancer<ServiceInstance> customLoadBalancer(  ReactiveLoadBalancerFactory<ServiceInstance> factory,  ObjectProvider<List<ServiceInstance>> serviceInstances) {  return new ReactiveLoadBalancer<ServiceInstance>() {  @Override  public Mono<Response<ServiceInstance>> choose(Request request) {  // 这里是自定义的负载均衡算法实现  // 例如,我们可以简单地返回服务实例列表中的第一个实例  return Mono.justOrEmpty(serviceInstances.getIfAvailable())  .flatMapMany(List::stream)  .firstElement() // 或者可以实现自己的选择逻辑  .map(Response::just);  }  // 其他必要的方法(如 recordStats, filter, etc.)可以根据需要进行实现  };  }  // 如果想要为特定的服务配置自定义的负载均衡器,  // 可以通过 ServiceId 来区分并返回不同的 ReactiveLoadBalancer 实例  // 例如,public ReactiveLoadBalancer<ServiceInstance> customLoadBalancerForServiceX(...) {...}  
}

spring-cloud-starter-loadbalancer 提供了多种负载均衡算法,包括轮询、随机和自定义策略等。这些算法可以根据实际需求进行选择和配置,以满足不同的负载均衡需求。同时,与 Nacos 服务发现组件的集成还提供了权重负载均衡器的功能,进一步增加了负载均衡的灵活性和可定制性。开发者可以根据自己的业务场景和需求选择适合的负载均衡算法,并对其进行适当的配置和优化,以实现更高效、更可靠的微服务调用。

反应式编程

从 Spring Cloud Greenwich 版本开始,Spring Cloud 引入了对 Project Reactor 的支持,并将负载均衡器从传统的阻塞式(基于 Ribbon)转变为反应式(基于 spring-cloud-starter-loadbalancer)。

反应式编程是一种异步、非阻塞的编程范式,它使用数据流(streams)和变化传播(propagation of change)来处理数据。在反应式编程中,数据不是通过传统的调用和返回机制来传递的,而是通过异步数据流在组件之间传递。

在 spring-cloud-starter-loadbalancer 中,反应式编程主要体现在以下几个方面:

  1. 非阻塞调用:与传统的基于 Ribbon 的阻塞式负载均衡器不同,spring-cloud-starter-loadbalancer 使用反应式编程模型来执行非阻塞的负载均衡请求。这意味着它不会阻塞线程等待响应,而是异步地处理请求和响应。
  2. 响应式类型:负载均衡器的 API 使用了反应式类型,如 Mono 和 Flux,它们是 Project Reactor 提供的反应式类型。Mono 用于表示 0 或 1 个元素的异步序列,而 Flux 用于表示 0 到 N 个元素的异步序列。
  3. 背压(Backpressure):反应式编程支持背压机制,即消费者可以控制生产者生成数据的速度。这在处理大量并发请求时非常有用,可以避免因生产者过快生成数据而导致消费者处理不过来。
  4. 错误处理:反应式编程提供了丰富的错误处理机制,如 onErrorResume、retry 等操作符,可以在发生错误时优雅地处理异常情况。
  5. 组合和转换:Mono 和 Flux 提供了丰富的操作符,用于组合和转换异步数据流。这使得可以灵活地处理负载均衡请求和响应,满足各种复杂的业务需求。
    简单的示例:
import org.springframework.cloud.client.ServiceInstance;  
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;  
import org.springframework.web.bind.annotation.GetMapping;  
import org.springframework.web.bind.annotation.RestController;  
import org.springframework.web.reactive.function.client.WebClient;  import reactor.core.publisher.Mono;  @RestController  
public class MyController {  private final LoadBalancerClient loadBalancerClient;  public MyController(LoadBalancerClient loadBalancerClient) {  this.loadBalancerClient = loadBalancerClient;  }  @GetMapping("/call-service")  public Mono<String> callService() {  // 获取服务实例  ServiceInstance serviceInstance = loadBalancerClient.choose("my-service").block();  // 使用 WebClient 发起反应式请求  WebClient webClient = WebClient.builder()  .baseUrl(serviceInstance.getUri().toString())  .build();  return webClient.get()  .uri("/some-endpoint")  .retrieve()  .bodyToMono(String.class);  }  
}

注意:上面的示例中使用了 block() 方法来同步获取服务实例,这在实际应用中可能不是最佳实践。通常,应该在整个调用链中保持反应式编程的异步特性。但是,为了简化示例,这里使用了 block() 方法。在实际应用中,应该将服务实例的获取和请求的发起都转换为反应式操作。

与 OpenFeign 集成

Spring Cloud 应用程序中,spring-cloud-starter-loadbalancer 通常与 spring-cloud-starter-openfeign 或其他 HTTP 客户端(如 WebClient)一起使用,以支持对服务发现的客户端进行负载均衡的调用。
当使用 OpenFeign 声明式 HTTP 客户端时,spring-cloud-starter-loadbalancer 会自动集成以提供负载均衡功能。只需在 pom.xml 或 build.gradle 文件中包含相应的依赖,并在 Feign 客户端接口上使用 @FeignClient 注解指定服务名。
Maven 依赖

<dependencies>  <!-- ... 其他依赖 ... -->  <dependency>  <groupId>org.springframework.cloud</groupId>  <artifactId>spring-cloud-starter-openfeign</artifactId>  </dependency>  <dependency>  <groupId>org.springframework.cloud</groupId>  <artifactId>spring-cloud-starter-loadbalancer</artifactId>  </dependency>  <!-- ... 其他依赖 ... -->  
</dependencies>

Feign 客户端

@FeignClient(name = "my-service")  
public interface MyServiceClient {  // 定义 HTTP 方法  @GetMapping("/some-endpoint")  Mono<String> getSomething();  
}

WebClient 集成

使用 WebClient 作为 HTTP 客户端,可以通过 spring-cloud-starter-loadbalancer 来实现服务间的负载均衡调用。需要创建一个 WebClient.Builder bean,并使用 LoadBalancerExchangeFilterFunction 来自动处理服务发现和负载均衡。
配置 WebClient Bean

@Bean  
public WebClient.Builder webClientBuilder(LoadBalancerClient loadBalancerClient) {  return WebClient.builder()  .baseUrl("lb://my-service") // 使用 'lb://' 前缀启用负载均衡  .filter(new LoadBalancerExchangeFilterFunction(loadBalancerClient));  
}

使用 WebClient 发起请求

@Autowired  
private WebClient.Builder webClientBuilder;  public Mono<String> callService() {  WebClient webClient = webClientBuilder.build();  return webClient.get()  .uri("/some-endpoint")  .retrieve()  .bodyToMono(String.class);  
}

注意事项

  • 确保 Spring Cloud 版本支持 spring-cloud-starter-loadbalancer。
  • 从使用 Ribbon 迁移到 spring-cloud-starter-loadbalancer,请注意两者之间的配置差异和 API 更改。
  • 在使用 WebClient 时,确保使用了正确的 URL 前缀(lb://)来启用负载均衡。
  • 在自定义负载均衡器时,确保实现是线程安全的,并且能够处理并发请求。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/23695.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

iOS Hook 崩溃

0x00 崩溃重现 被 Hook 的类&#xff0c;是这样的&#xff1a; interface ViewController : UIViewController endimplementation ViewController - (void)loadView {[super loadView];NSLog("%s", __func__); }- (void)test {NSLog("%s", __func__); }-…

Python第二语言(四、Python数据容器)

目录 一、 数据容器&#xff08;list、tuple、str、map、dict&#xff09; 1. 数据容器概念 2. 列表list&#xff08; [] &#xff09; 2.1 定义方式 2.2 嵌套列表 2.3 list通过获取下标索引获取值 2.4 下标使用概念 2.5 list列表的使用&#xff08;列表的方法&#xff…

​在 The Sandbox 元宇宙的 CU 超商中寻找Milk币!

CU&#xff08;韩国领先的便利店&#xff09;和 MiL.k&#xff08;基于区块链的忠诚度整合平台&#xff09;合作在 The Sandbox 推出了首款元宇宙游戏&#xff0c;通过独家活动在 Web2 和 Web3 之间建立联系。 在元宇宙中玩转 “Play CU X MiL.k” 体验 通过引人入胜的游戏内容…

Apple开发者证书创建完整过程

1.创建CSR文件: 打开钥匙串访问程序 选择从证书颁发机构请求 创建证书 保存CSR文件到桌面 成功如下: 开始创建证书: 选择

每天一道大厂SQL题【Day32】按消息量给广东省qq打标记

文章目录 每天一道大厂SQL题【Day32】按消息量给广东省qq打标记每日语录第32题 需求三&#xff1a;按消息量给广东省qq打标记思路分析附表 答案获取加技术群讨论文末SQL小技巧 后记 每天一道大厂SQL题【Day32】按消息量给广东省qq打标记 大家好&#xff0c;我是Maynor。相信大…

vue3引入cesium和olcs

首先引入包 pnpm i olcs; pnpm i -D vite-plugin-cesium pnpm i -S cesium在vite.config.js中配置&#xff0c;参考这位大佬的笔记 添加链接描述 import { defineConfig } from vite import vue from vitejs/plugin-vue import cesium from vite-plugin-cesium; // https://…

芝麻IP好用吗?来测试了!

作为老牌代理IP服务厂商&#xff0c;芝麻IP和青果网络代理IP都做的不错&#xff0c;市场上几乎可以是有口皆碑了&#xff0c;上次测试了青果网络的代理IP&#xff0c;效果表现得还挺不错&#xff0c;和他们自己宣传的以及客户对他们的评价大差不差。 总的来说&#xff0c;他们家…

交易中的预测和跟随

任何的交易决策&#xff0c;一定是基于某种推理关系的&#xff0c;这种推理关系是基于t时刻之前的状态&#xff0c;得到t时刻之后的结果&#xff0c;我们基于这种推理关系&#xff0c;根据当前的状态&#xff0c;形成了未来结果的某种预期&#xff0c;然后基于这种预期采取相应…

开机弹窗找不到opencl.dll怎么办,教你几种有效的修复方法

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“找不到opencl.dll文件”。这个问题可能会影响到我们的正常使用&#xff0c;因此了解其原因和解决方法是非常必要的。本文将从多个方面对“找不到opencl.dll文件”这一问题进行详细分析和解…

如何修复d3dcompiler43.dll丢失问题,这三种方法可轻松解决

在计算机使用过程中&#xff0c;我们常常会遇到一些错误提示&#xff0c;其中之一就是“计算机缺失d3dcompiler43.dll”。这个问题可能会影响到计算机的正常运行&#xff0c;让我们无法正常使用某些软件或者游戏。那么&#xff0c;究竟什么是d3dcompiler43.dll&#xff1f;为什…

极光公布2024年第一季度财报

2024年6月6日&#xff0c;中国深圳——中国领先的客户互动和营销科技服务商极光&#xff08;Aurora Mobile&#xff0c;纳斯达克股票代码&#xff1a;JG&#xff09;&#xff08;以下称“极光”或“公司”&#xff09;公布截至2024年3月31日第一季度未经审计的财报。 2024年第…

Ubuntu22.04显卡驱动与内核版本不一致解决方案

有时候在使用 GPU 服务器时执行 nvidia-smi 会遇到以下报错&#xff1a; Failed to initialize NVML: Driver/library version mismatch NVML library version: 535.161这说明 Nvidia 显卡驱动与内核版本不一致&#xff0c;我们可以查看一下内核版本&#xff1a; cat /proc/d…

netty-学习

Netty Netty 的核心概念Netty 的主要特性Netty 的应用场景Netty 的基本使用服务器端处理器 总结 代码分析1.心跳检测代码解析类和成员变量userEventTriggered方法总结 4.参数详解ChannelHandlerContext ctxObject evt 事件来源示例&#xff1a;配置 IdleStateHandler事件处理示…

Linux上的电子邮件服务器安装教程

&#x1f341; 作者&#xff1a;知识浅谈&#xff0c;CSDN签约讲师&#xff0c;CSDN博客专家&#xff0c;华为云云享专家&#xff0c;阿里云专家博主 &#x1f4cc; 擅长领域&#xff1a;全栈工程师、爬虫、ACM算法&#xff0c;大数据&#xff0c;深度学习 &#x1f492; 公众号…

浏览器内置对象 window 用法集锦,看这篇就够了

文章导读&#xff1a;AI 辅助学习前端&#xff0c;包含入门、进阶、高级部分前端系列内容&#xff0c;当前是 javascript 的部分&#xff0c;瑶琴会持续更新&#xff0c;适合零基础的朋友&#xff0c;已有前端工作经验的可以不看&#xff0c;也可以当作基础知识回顾。 上面文章…

[网鼎杯 2020 青龙组]singal

记录下angr初使用 这道题是很简单的逻辑 32位 我们提取opcode (你可以用convert) 我是用的IDApython\ import idc adr0x00403040 step4#距离 op[] n10#多少个数据 while(n):op.append(hex(idc.get_wide_dword(adr)))adrstepn-1 print(op)然后我又下断点,提取每个"i&q…

持续总结中!2024年面试必问 20 道 Kafka面试题(十)

上一篇地址&#xff1a;持续总结中&#xff01;2024年面试必问 20 道 Kafka面试题&#xff08;九&#xff09;-CSDN博客 十九、Kafka的ACK机制是什么&#xff1f; Kafka的ACK&#xff08;Acknowledgement&#xff0c;确认&#xff09;机制是确保消息被成功发送和接收的重要部分…

MySQL—多表查询—内连接

一、引言 &#xff08;1&#xff09;内连接查询语法 内连接查询的是两张表的交集部分的数据。&#xff08;也就是绿色部分展示的数据&#xff09; &#xff08;2&#xff09;内连接有两种形式&#xff1a; 1、隐式内连接 语法结构&#xff1a; 2、显示内连接 语法结构&#xf…

pycharm FuncAnimation画动态图不显示, 以及画图

网上的一些方法给出了解决措施&#xff0c;如&#xff1a;https://blog.csdn.net/qq_41725313/article/details/122048864?spm1001.2101.3001.6650.2&utm_mediumdistribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogOpenSearchComplete%7ERate-2-122048864-blog-139…

红酒:如何避免红酒过度氧化

红酒过度氧化是影响其品质的重要因素&#xff0c;尤其是在储存和运输过程中。过度氧化的红酒会失去原有的果香和口感&#xff0c;变得平淡无味。因此&#xff0c;避免红酒过度氧化至关重要。以下是一些进一步的措施&#xff0c;可以帮助您保护云仓酒庄雷盛红酒的品质&#xff1…