• 如何使用springcloud LoadBalancer代替ribbon


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

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

    1. com.alibaba.cloud
    2. spring-cloud-starter-alibaba-nacos-discovery
    3. org.springframework.cloud
    4. spring-cloud-netflix-ribbon
    5. org.springframework.cloud
    6. spring-cloud-starter-openfeign
    7. org.springframework.cloud
    8. spring-cloud-netflix-ribbon

    2.引入scl依赖

    1. org.springframework.cloud
    2. spring-cloud-starter-loadbalancer

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

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

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

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

    1. //这里不用加 @Configuration 注解
    2. public class LoadBalancerConfig {
    3. //将官方提供的 RandomLoadBalancer 注册为Bean
    4. @Bean
    5. public ReactorLoadBalancer randomLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory){
    6. String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
    7. return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
    8. }
    9. }

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

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

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

    1. /**
    2. * Description:
    3. * 自定义灰度
    4. * 通过给请求头添加Version 与 Service Instance 元数据属性进行对比
    5. * @author Jam
    6. * @date 2021/6/1 17:26
    7. */
    8. @Log4j2
    9. public class VersionGrayLoadBalancer implements ReactorServiceInstanceLoadBalancer {
    10. private final ObjectProvider serviceInstanceListSupplierProvider;
    11. private final String serviceId;
    12. private final AtomicInteger position;
    13. public VersionGrayLoadBalancer(ObjectProvider serviceInstanceListSupplierProvider, String serviceId) {
    14. this(serviceInstanceListSupplierProvider,serviceId,new Random().nextInt(1000));
    15. }
    16. public VersionGrayLoadBalancer(ObjectProvider serviceInstanceListSupplierProvider,
    17. String serviceId, int seedPosition) {
    18. this.serviceId = serviceId;
    19. this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
    20. this.position = new AtomicInteger(seedPosition);
    21. }
    22. @Override
    23. public Mono> choose(Request request) {
    24. ServiceInstanceListSupplier supplier = this.serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
    25. return supplier.get(request).next()
    26. .map(serviceInstances -> processInstanceResponse(serviceInstances,request));
    27. }
    28. private Response processInstanceResponse(List instances, Request request) {
    29. if (instances.isEmpty()) {
    30. log.warn("No servers available for service: " + this.serviceId);
    31. return new EmptyResponse();
    32. } else {
    33. DefaultRequestContext requestContext = (DefaultRequestContext) request.getContext();
    34. RequestData clientRequest = (RequestData) requestContext.getClientRequest();
    35. HttpHeaders headers = clientRequest.getHeaders();
    36. // get Request Header
    37. String reqVersion = headers.getFirst("version");
    38. if(StringUtils.isEmpty(reqVersion)){
    39. return processRibbonInstanceResponse(instances);
    40. }
    41. log.info("request header version : {}",reqVersion );
    42. // filter service instances
    43. List serviceInstances = instances.stream()
    44. .filter(instance -> reqVersion.equals(instance.getMetadata().get("version")))
    45. .collect(Collectors.toList());
    46. if(serviceInstances.size() > 0){
    47. return processRibbonInstanceResponse(serviceInstances);
    48. }else{
    49. return processRibbonInstanceResponse(instances);
    50. }
    51. }
    52. }
    53. /**
    54. * 负载均衡器
    55. * 参考 org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer#getInstanceResponse
    56. * @author javadaily
    57. */
    58. private Response processRibbonInstanceResponse(List instances) {
    59. int pos = Math.abs(this.position.incrementAndGet());
    60. ServiceInstance instance = instances.get(pos % instances.size());
    61. return new DefaultResponse(instance);
    62. }
    63. }
    1. /**
    2. * Description:
    3. * 自定义负载均衡器配置实现类
    4. * @author javadaily
    5. * @date 2021/6/3 16:02
    6. */
    7. public class VersionLoadBalancerConfiguration {
    8. @Bean
    9. ReactorLoadBalancer versionGrayLoadBalancer(Environment environment,
    10. LoadBalancerClientFactory loadBalancerClientFactory) {
    11. String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
    12. return new VersionGrayLoadBalancer(
    13. loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
    14. }
    15. }

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

    在网关启动类使用注解@LoadBalancerClient指定哪些服务使用自定义负载均衡算法    
       
    通过@LoadBalancerClient(value = "auth-service", configuration = VersionLoadBalancerConfiguration.class),对于auth-service启用自定义负载均衡算法;
    或通过@LoadBalancerClients(defaultConfiguration = VersionLoadBalancerConfiguration.class)为所有服务启用自定义负载均衡算法。

  • 相关阅读:
    str.c_str() 补充C中没有string类型的问题
    YC-Framework版本更新:V1.0.9
    2年开发经验去面试,吊打面试官,即将面试的程序员这些笔记建议复习
    Dubbo底层网络连接模型
    mmlab花朵分类结果展示(1)
    Python进阶:猴子补丁
    Java设计模式-建造者模式(Builder)
    Linux platform子系统【2】-PLATFORM注册(struct device)platform_bus
    OKR高效落地的四个关键要素
    《算法通关村——不简单的字符串转换问题》
  • 原文地址:https://blog.csdn.net/weixin_59244784/article/details/137266487