zoukankan      html  css  js  c++  java
  • springcloud 的loadbalancer 轮询算法切换方法 2021.4.3

    loadbalancer修改轮询方法

    在做练习,整合springboot springcloud springcloud alibab中发现,最新的eureka client集成的负载均衡已经替换为spring 的loadbalancer
    在此整理下基本的替换轮询算法的方法
    整合的框架版本如下

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-dependencies</artifactId>
      <version>2.4.2</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-dependencies</artifactId>
      <version>2020.0.0</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
    <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-alibaba-dependencies</artifactId>
      <version>2020.0.RC1</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
    

    看了下代码,目前好像只有两种轮询算法
    RandomLoadBalancer 随机
    RoundRobinLoadBalancer 轮询

    • 参考 https://docs.spring.io/spring-cloud-commons/docs/current/reference/html/#spring-cloud-loadbalancer

      • 在@SpringBootApplication 能扫描的外边设置配置类

        参考

        The classes you pass as @LoadBalancerClient or @LoadBalancerClients configuration arguments should either not be annotated with @Configuration or be outside component scan scope.
        
      • 配置类为

        public class CustomLoadBalancerConfiguration {
        
            @Bean
            ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,
                                                                    LoadBalancerClientFactory loadBalancerClientFactory) {
                String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
                //return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
                return new MyRandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
            }
        }
        
      • 可以自己定制化自己的轮询算法

        import java.util.List;
        import java.util.concurrent.ThreadLocalRandom;
        import org.apache.commons.logging.Log;
        import org.apache.commons.logging.LogFactory;
        import org.springframework.beans.factory.ObjectProvider;
        import org.springframework.cloud.client.ServiceInstance;
        import org.springframework.cloud.client.loadbalancer.DefaultResponse;
        import org.springframework.cloud.client.loadbalancer.EmptyResponse;
        import org.springframework.cloud.client.loadbalancer.Request;
        import org.springframework.cloud.client.loadbalancer.Response;
        import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
        import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
        import org.springframework.cloud.loadbalancer.core.SelectedInstanceCallback;
        import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
        import reactor.core.publisher.Mono;
        
        public class MyRandomLoadBalancer implements ReactorServiceInstanceLoadBalancer {
            private static final Log log = LogFactory.getLog(org.springframework.cloud.loadbalancer.core.RandomLoadBalancer.class);
            private final String serviceId;
            private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;
        
            public MyRandomLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId) {
                this.serviceId = serviceId;
                this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
            }
        
            public MyRandomLoadBalancer(String serviceId) {
                this.serviceId = serviceId;
            }
        
            @Override
            public Mono<Response<ServiceInstance>> choose(Request request) {
                ServiceInstanceListSupplier supplier = (ServiceInstanceListSupplier)this.serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
                return supplier.get(request).next().map((serviceInstances) -> {
                    return this.processInstanceResponse(supplier, serviceInstances);
                });
            }
        
            private Response<ServiceInstance> processInstanceResponse(ServiceInstanceListSupplier supplier, List<ServiceInstance> serviceInstances) {
                Response<ServiceInstance> serviceInstanceResponse = this.getInstanceResponse(serviceInstances);
                if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) {
                    ((SelectedInstanceCallback)supplier).selectedServiceInstance((ServiceInstance)serviceInstanceResponse.getServer());
                }
        
                return serviceInstanceResponse;
            }
        
            private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {
                if (instances.isEmpty()) {
                    if (log.isWarnEnabled()) {
                        log.warn("No servers available for service: " + this.serviceId);
                    }
        
                    return new EmptyResponse();
                } else {
                    /*int index = ThreadLocalRandom.current().nextInt(instances.size());
                    ServiceInstance instance = (ServiceInstance)instances.get(index);
                    return new DefaultResponse(instance);*/
                    return new DefaultResponse(instances.get(0));
                }
            }
        }
        这个方法中本人没做什么修改,只是把instance实例返回锁定为第一个,用于验证切换轮询策略是否成功
        
      • 在@SpringBootApplication 能扫描的范围内设置配置resttemplate的配置类

        @Configuration
        @LoadBalancerClient(name = "CLOUD-PAYMENT-SERVICE", configuration = CustomLoadBalancerConfiguration.class)
        public class RestTEmplateConfig {
        
            @Bean
            // 开启负载均衡 配合 eureka 通过服务名称调用服务
            // 使用LoadBalanced注解赋予resttemplate负载均衡的能力
            @LoadBalanced
            public RestTemplate getTestTemplate(){
                return new RestTemplate();
            }
        }
        

        注意项:

        • LoadBalancerClient(name = "CLOUD-PAYMENT-SERVICE" 名称为eureka注册的服务的名称
        • @LoadBalancerClient中的configuration = CustomLoadBalancerConfiguration.class)为扫描范围外的配置类
      • controller配置

        @RestController
        @RequestMapping("/loadbalancer")
        public class TestLoadBalancerController {
            /*集群版本,从eureka中查询指定服务*/
            public static final String paymentUrl = "http://CLOUD-PAYMENT-SERVICE";
        
            @Resource
            private RestTemplate restTemplate;
        
            @GetMapping("/payment/get/{id}")
            public CommonResult<Payment> getPaymentbyId(@PathVariable("id") String id){
                return restTemplate.getForObject(paymentUrl + "/payment/get/" + id, CommonResult.class);
            }
        }
        

        注意项:

  • 相关阅读:
    android游戏开发框架libgdx的使用(十二)—TiledMap地图的使用
    android游戏开发框架libgdx的使用(十一)—Skin和UI配置文件的使用
    子句判断、启动强度和去模糊化AForge.NET框架的使用(三)
    分享从网上收集的一些游戏资源,以RPG类为主
    android游戏开发框架libgdx的使用(十六)—使用TexturePacker工具加快开发速度
    android游戏开发框架libgdx的使用(十三)—TiledMap中的角色和角色移动
    Ajax实现评论的顶和踩功能
    Jelastic支持java的PaaS
    真心好用的VS扩展NuGet
    分享几篇文章(PDF版)
  • 原文地址:https://www.cnblogs.com/fb010001/p/14613428.html
Copyright © 2011-2022 走看看