SpringCloud - 新版淘汰 Ribbon,在 OpenFeign 中整合 LoadBalancer 负载均衡

目录

一、LoadBalancer 负载均衡

1.1、前言

1.2、LoadBalancer 负载均衡底层实现原理

二、整合 OpenFeign + LoadBalancer

2.1、所需依赖

2.2、具体实现

 2.3、自定义负载均衡策略


一、LoadBalancer 负载均衡


1.1、前言

在 2020 年以前的 SpringCloud 采用 Ribbon 作为负载均衡,但是 2020 年之后,SpringCloud 吧 Ribbon 移除了,而是使用自己编写的 LoadBalancer 替代.

因此,如果在没有加入 LoadBalancer 依赖的情况下,使用 RestTemplate 或 OpenFeign 远程调用,就会报以下错误:

这就是在告诉你 LoadBalancing是未定义的(OpenFeign 中引入的依赖会使用 LoadBalancing),然后问你是不是忘记加入 spring-cloud-starter-loadbalancer 依赖.

<think>我们正在使用SpringCloud LoadBalancer来实现自定义的负载均衡策略,并将其应用于OpenFeign。根据引用[2],我们可以通过配置类来定义负载均衡策略,并且可以通过注解将其设置为全局或特定服务的策略。步骤:1.创建一个实现了`ReactorLoadBalancer`接口的类,或者继承`RoundRobinLoadBalancer`等现有类来修改行为。2.定义配置类,返回自定义的`ReactorLoadBalancer`。3.通过注解(全局或局部)应用这个配置。具体实现:第一步:创建自定义负载均衡器例如,我们创建一个随机负载均衡器(虽然已有随机策略,这里作为示例)或者可以创建其他策略。第二步:创建配置类,用于提供自定义负载均衡器的实例。第三步:在启动类上使用`@LoadBalancerClients`注解(全局)或者在具体的Feign客户端上使用`@LoadBalancerClient`注解(针对特定服务)来指定配置。示例代码:1.自定义负载均衡器(这里以随机负载均衡为例,实际上可以更复杂):注意:Spring CloudLoadBalancer默认提供了`RoundRobinLoadBalancer`和`RandomLoadBalancer`,我们可以参考这些实现来编写自己的策略。2.创建配置类,例如`CustomLoadBalancerConfiguration`:3.在启动类上应用全局配置,或者为特定服务指定。详细步骤:1.自定义负载均衡器实现:我们可以实现`ReactorLoadBalancer`接口,或者继承`RandomLoadBalancer`(如果我们只是稍微修改)。这里我们实现一个简单的随机负载均衡器。注意:从Spring Cloud2020.0.0开始,移除了对Ribbon的支持,使用`SpringCloud LoadBalancer`作为客户端负载均衡器。2.配置类:3.应用配置:下面给出一个示例:自定义负载均衡器(随机选择): ```javaimport org.springframework.cloud.client.ServiceInstance;import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer; importorg.springframework.cloud.loadbalancer.core.ReactorLoadBalancer; importorg.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration; importreactor.core.publisher.Mono;import java.util.List; importjava.util.Random; publicclass MyRandomLoadBalancerimplements ReactorLoadBalancer<ServiceInstance>{private finalString serviceId;privatefinal ObjectProvider<ServiceInstanceListSupplier>serviceInstanceListSupplierProvider;publicMyRandomLoadBalancer(StringserviceId, ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider) {this.serviceId= serviceId;this.serviceInstanceListSupplierProvider =serviceInstanceListSupplierProvider;}@OverridepublicMono<Response<ServiceInstance>> choose(Request request) {ServiceInstanceListSupplier supplier= serviceInstanceListSupplierProvider.getIfAvailable();returnsupplier.get().next().map(this::getInstanceResponse);}privateResponse<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {if(instances.isEmpty()) {returnnew EmptyResponse();}//随机选择一个实例Random random= newRandom();ServiceInstance instance= instances.get(random.nextInt(instances.size()));returnnew DefaultResponse(instance);}} ```配置类:```javaimportorg.springframework.beans.factory.ObjectProvider; importorg.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration; @Configurationpublic classMyLoadBalancerConfiguration{@Beanpublic ReactorLoadBalancer<ServiceInstance>reactorServiceInstanceLoadBalancer(ObjectProvider<ServiceInstanceListSupplier>serviceInstanceListSupplierProvider){//这里我们使用自定义的负载均衡器,并传入serviceId(这里用null,实际会通过自动配置注入)//注意:在实际中,我们需要为每个服务创建一个负载均衡器实例,因此这里需要知道服务ID,但Spring会自动处理。returnnew MyRandomLoadBalancer(null,serviceInstanceListSupplierProvider);}} ```注意:上面的配置类中,我们创建了一个`ReactorLoadBalancer`的Bean。但是,在SpringCloud LoadBalancer中,每个服务都会有一个负载均衡器实例,因此我们需要确保这个配置类被应用到特定的服务上。4.应用配置:全局配置:在启动类上添加`@LoadBalancerClients`注解,指定默认配置。```java@SpringBootApplication@EnableFeignClients@LoadBalancerClients(defaultConfiguration= MyLoadBalancerConfiguration.class)publicclass ConsumerApplication {publicstatic voidmain(String[] args) {SpringApplication.run(ConsumerApplication.class, args);}}```或者,针对特定服务(例如服务名为"order-service"):```java@SpringBootApplication@EnableFeignClients//为order-service指定负载均衡配置@LoadBalancerClient(name= "order-service", configuration= MyLoadBalancerConfiguration.class)publicclass ConsumerApplication {publicstatic voidmain(String[] args) {SpringApplication.run(ConsumerApplication.class, args);}}```另外,我们也可以使用配置文件的方式(如引用[1]所示)来设置负载均衡策略,但是配置文件方式通常用于设置内置的策略(如round-robin, random等)。对于自定义策略,我们需要通过编程方式实现。注意:在自定义负载均衡器中,我们使用了`ServiceInstanceListSupplier`来获取服务实例列表。这个列表可能来自服务发现(如Eureka、Consul等)。我们不需要自己实现服务发现,Spring Cloud已经提供了集成。总结:通过以上步骤,我们就可以为OpenFeign实现自定义的负载均衡策略,并基于spring-cloud-loadbalancer进行配置。注意:在SpringCloud2020.0.0及以上版本,Ribbon已被移除,因此我们使用spring-cloud-loadbalancer。引用说明:引用[2]中提到了如何通过注解设置全局的负载均衡策略,我们这里采用了类似的方式。引用[3]提到OpenFeign整合负载均衡的能力,而我们现在使用spring-cloud-loadbalancer作为其负载均衡器。因此,按照上述步骤,即可实现自定义负载均衡策略。</think>### 基于 Spring Cloud LoadBalancer 自定义 OpenFeign 负载均衡策略 以下是实现自定义负载均衡策略的完整步骤: #### 1. **创建自定义负载均衡器** 实现 `ReactorLoadBalancer` 接口,重写核心选择逻辑: ```java import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer; import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier; import reactor.core.publisher.Mono; public class CustomLoadBalancer implements ReactorLoadBalancer<ServiceInstance> { private final String serviceId; private final ServiceInstanceListSupplier supplier; public CustomLoadBalancer(String serviceId, ServiceInstanceListSupplier supplier) { this.serviceId = serviceId; this.supplier = supplier; } @Override public Mono<Response<ServiceInstance>> choose(Request request) { return supplier.get().next() .map(instances -> { // 自定义选择逻辑示例:权重随机算法 int totalWeight = instances.stream().mapToInt(i -> Integer.parseInt(i.getMetadata().getOrDefault("weight", "1")) ).sum(); int random = new Random().nextInt(totalWeight); int sum = 0; for (ServiceInstance instance : instances) { int weight = Integer.parseInt(instance.getMetadata().getOrDefault("weight", "1")); if ((sum += weight) >= random) { return new DefaultResponse(instance); // 返回选中的实例 } } return new EmptyResponse(); // 无可用实例 }); } } ``` #### 2. **创建负载均衡配置类** 定义配置类注册自定义负载均衡器: ```java import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClientConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class CustomLoadBalancerConfig { @Bean public ReactorLoadBalancer<ServiceInstance> customLoadBalancer( Environment environment, LoadBalancerClientFactory loadBalancerClientFactory ) { String serviceId = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME); return new CustomLoadBalancer( serviceId, loadBalancerClientFactory.getLazyProvider(serviceId, ServiceInstanceListSupplier.class) ); } } ``` #### 3. **应用负载均衡配置** ##### 方式1:全局配置(所有服务生效) ```java @SpringBootApplication @EnableFeignClients @LoadBalancerClients(defaultConfiguration = CustomLoadBalancerConfig.class) // 全局生效 public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` [^2] ##### 方式2:指定服务配置(仅对特定服务生效) ```java @Configuration @LoadBalancerClient( value = "order-service", // 服务名称 configuration = CustomLoadBalancerConfig.class // 指定配置类 ) public class OrderServiceLoadBalancerConfig {} ``` #### 4. **配置元数据(Nacos示例)** 在注册中心添加实例元数据(如权重): ```yaml # application.yml spring: cloud: nacos: discovery: metadata: weight: "3" # 设置权重值 ``` #### 关键注意事项 1. **依赖要求**: ```xml <!-- 确保禁用Ribbon --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency> ``` ```yaml # application.yml spring: cloud: loadbalancer: ribbon: enabled: false # 禁用Ribbon[^1] ``` 2. **OpenFeign 集成**: - 自定义负载均衡器会自动应用于所有 `@FeignClient` 接口 - 无需修改 Feign 客户端定义[^3] 3. **扩展点**: - 可重写 `ServiceInstanceListSupplier` 实现实例过滤 - 通过 `@LoadBalancerClient` 的 `qualifiers` 属性实现多策略共存 ### 验证方法 1. 启动多个服务实例并设置不同权重 2. 观察 Feign 请求的实例分布情况 3. 使用 Spring Boot Actuator 的 `/actuator/loadbalancer` 端点检查状态 > **性能建议**:在 `choose()` 方法中缓存实例列表,避免每次请求都重新计算权重总和[^2]。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈亦康

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值