如何使用springcloud LoadBalancer代替ribbon

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

1.排除客户端和openfeign中的ribbon包

java 复制代码
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-netflix-ribbon</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

       
              <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-netflix-ribbon</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

2.引入scl依赖

java 复制代码
 <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>

到这里已经可以使用了,默认的负载方式就是轮询,那么如何自定义负载均衡策略呢

LoadBalancer默认提供了两种负载均衡策略:

  • RandomLoadBalancer - 随机分配策略
  • (默认) RoundRobinLoadBalancer - 轮询分配策略

现在希望修改默认的负载均衡策略为随机分配策略,就需要创建随机分配策略的配置类(不用加 @Configuration):

java 复制代码
//这里不用加 @Configuration 注解
public class LoadBalancerConfig {
    //将官方提供的 RandomLoadBalancer 注册为Bean
    @Bean
    public ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory){
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
    }
}

通过 @LoadBalancerClient(value = "服务名", configuration = LoadBalancerConfig.class) 指定负载均衡策略为随机.

java 复制代码
@FeignClient("article")
@LoadBalancerClient(value = "article", configuration = LoadBalancerConfig.class) //指定负载均衡策略为随机
public interface ArticleClient {
 
//    @LoadBalanced(可以写,也可以不用写,默认所有方法都自动加 @LoadBalanced)
    @GetMapping("/article/start")
    String userStart();
 
}

自定义负载均衡策略:可用于灰度发布

java 复制代码
/**
 * Description:
 * 自定义灰度
 * 通过给请求头添加Version 与 Service Instance 元数据属性进行对比
 * @author Jam
 * @date 2021/6/1 17:26
 */
@Log4j2
public class VersionGrayLoadBalancer implements ReactorServiceInstanceLoadBalancer {
 
    private final ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;
    private final String serviceId;
 
    private final AtomicInteger position;
 
    public VersionGrayLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId) {
        this(serviceInstanceListSupplierProvider,serviceId,new Random().nextInt(1000));
    }
 
    public VersionGrayLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider,
                                   String serviceId, int seedPosition) {
        this.serviceId = serviceId;
        this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
        this.position = new AtomicInteger(seedPosition);
    }
 
    @Override
    public Mono<Response<ServiceInstance>> choose(Request request) {
        ServiceInstanceListSupplier supplier = this.serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
 
        return supplier.get(request).next()
                .map(serviceInstances -> processInstanceResponse(serviceInstances,request));
 
    }
 
 
    private Response<ServiceInstance> processInstanceResponse(List<ServiceInstance> instances, Request request) {
        if (instances.isEmpty()) {
            log.warn("No servers available for service: " + this.serviceId);
            return new EmptyResponse();
        } else {
            DefaultRequestContext requestContext = (DefaultRequestContext) request.getContext();
            RequestData clientRequest = (RequestData) requestContext.getClientRequest();
            HttpHeaders headers = clientRequest.getHeaders();
 
            // get Request Header
            String reqVersion = headers.getFirst("version");
 
            if(StringUtils.isEmpty(reqVersion)){
                return processRibbonInstanceResponse(instances);
            }
 
            log.info("request header version : {}",reqVersion );
   // filter service instances
            List<ServiceInstance> serviceInstances = instances.stream()
                    .filter(instance -> reqVersion.equals(instance.getMetadata().get("version")))
                    .collect(Collectors.toList());
 
            if(serviceInstances.size() > 0){
                return processRibbonInstanceResponse(serviceInstances);
            }else{
                return processRibbonInstanceResponse(instances);
            }
        }
    }
 
    /**
     * 负载均衡器
     * 参考 org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer#getInstanceResponse
     * @author javadaily
     */
    private Response<ServiceInstance> processRibbonInstanceResponse(List<ServiceInstance> instances) {
        int pos = Math.abs(this.position.incrementAndGet());
        ServiceInstance instance = instances.get(pos % instances.size());
        return new DefaultResponse(instance);
    }
 
}
java 复制代码
/**
 * Description:
 * 自定义负载均衡器配置实现类
 * @author javadaily
 * @date 2021/6/3 16:02
 */
public class VersionLoadBalancerConfiguration {
    @Bean
    ReactorLoadBalancer<ServiceInstance> versionGrayLoadBalancer(Environment environment,
                                                                 LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new VersionGrayLoadBalancer(
                loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
    }
 
}

VersionLoadBalancerConfiguration配置类不能添加@Configuration注解。

在网关启动类使用注解@LoadBalancerClient指定哪些服务使用自定义负载均衡算法

通过@LoadBalancerClient(value = "auth-service", configuration = VersionLoadBalancerConfiguration.class),对于auth-service启用自定义负载均衡算法;

或通过@LoadBalancerClients(defaultConfiguration = VersionLoadBalancerConfiguration.class)为所有服务启用自定义负载均衡算法。

相关推荐
weixin_460443563 小时前
2026年新修订《网络安全法》实施:Java私有化考试系统如何做好SBOM、漏洞治理与安全升级?
java·开发语言·在线考试系统·企业培训考试系统·宏远培训考试系统·国企培训考试系统·国产化培训系统
海鸥-w6 小时前
什么是AOP
java
Cc.Y6 小时前
Java零基础入门:可变字符串与包装类:StringBuilder、StringBuffer 与 通讯录管理系统实战
java·开发语言·python
paopaokaka_luck6 小时前
基于springboot+vue的智慧家政管理系统(AI问答、 WebSocket实时沟通、ECharts运营分析、订单规则与服务追踪)
java·javascript·spring boot·数据分析·echarts·mybatis
sm_926787056 小时前
RFID 标签打印的技术实现要点与二次开发实践
java·大数据·前端·c++·编辑器
阿森_dev6 小时前
2027 届毕设选题怎么选:30 个 Java 方向选题的实现难度排序
java·开发语言·spring boot·毕业设计·课程设计
Sarvartha6 小时前
Lambda 表达式和函数式接口
java·开发语言
计算机毕业设计杰瑞7 小时前
【计算机毕设精品】基于SpringBoot的一体化教务与学业质量管理系统的设计与实现,附源码_增删改查_java项目_可完美运行部署_网站项目
java·spring boot·课程设计
colinu7 小时前
C++ 异步任务与线程生命周期:`std::async`、`future`、`thread`、`jthread` 与协作式退出
java·jvm·c++
蜗牛互联网7 小时前
Python + JSON Schema 实现工单结构化输出与本地复核
java·人工智能·后端