Ribbon的使用

  • 本地集群环境说明

    consumer服务order(80)、 provider服务payment(8001、8002)、Eureka服务端(7001、7002)

  • Ribbon简介

    Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。
    简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们很容易使用Ribbon实现自定义的负载均衡算法。

  • 架构说明

    Ribbon在工作时分成两步:

    1. 第一步先选择 EurekaServer ,它优先选择在同一个区域内负载较少的server.

    2. 第二步再根据用户指定的策略,在从server取到的服务注册列表中选择一个地址。

    其中Ribbon提供了多种策略:比如轮询、随机和根据响应时间加权。

  • Ribbon的使用

    单独引入依赖

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

    其他组件自动引入
    spring-cloud-starter-netflix-eureka-client自带了spring-cloud-starter-ribbon引用。

  • 核心组件IRule

    规则实现类

    规则说明:

    规则替换

    官方文档明确给出了警告:
    这个自定义配置类不能放在@ComponentScan所扫描的当前包下以及子包下,
    否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享,达不到特殊化定制的目的了。

    1. 80服务中新建包myrule

    2. 80服务中创建规则类MyselfRule.class

      @Configuration
      public class MyselfRule {
          @Bean
          public IRule myRule() {
              return new RandomRule();//定义为随机
          }
      }
      
    3. 80服务中修改启动配置类,增加@RibbonClient注解,并标明规则类MyselfRule.class

      @SpringBootApplication
      @EnableEurekaClient
      @RibbonClient(name = "cloud-payment-service",configuration = MyselfRule.class)
      public class OrderMain80 {
          public static void main(String[] args) {
              SpringApplication.run(OrderMain80.class, args);
          }
      }
      
      
    4. 重新启动服务,发送请求验证负载均衡规则替换是否生效。

  • 规则算法

    1. 轮询算法

      负载均衡算法:rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标 ,每次服务重启动后rest接口计数从1开始。

      List instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");

      如: List [0] instances = 127.0.0.1:8002
         List [1] instances = 127.0.0.1:8001

      8001+ 8002 组合成为集群,它们共计2台机器,集群总数为2, 按照轮询算法原理:

      当总请求数为1时: 1 % 2 =1 对应下标位置为1 ,则获得服务地址为127.0.0.1:8001

      当总请求数位2时: 2 % 2 =0 对应下标位置为0 ,则获得服务地址为127.0.0.1:8002

      当总请求数位3时: 3 % 2 =1 对应下标位置为1 ,则获得服务地址为127.0.0.1:8001

      当总请求数位4时: 4 % 2 =0 对应下标位置为0 ,则获得服务地址为127.0.0.1:8002

      如此类推......

  • 自定义规则

    1. 在8001、8002中新增接口方法,用于测试

      @GetMapping(value = "/payment/lb")
          public String getPaymentLB()
          {
              return serverPort;
          }
      
    2. 80服务中的ApplicationContextConfig.class中去除@LoadBalanced注解,以保证最终执行的是我们自定义的负载均衡算法。

      @Configuration
      public class ApplicationContextConfig {
          @Bean
          //@LoadBalanced//开启负载均衡
          public RestTemplate getRestTemplate(){
              return new RestTemplate();
          }
      }
      
    3. 80服务新增LoadBalancer接口

      public interface LoadBalancer {
          ServiceInstance instances(List<ServiceInstance> serviceInstances);
      }
      
      
    4. 80服务新增LoadBalancer接口实现类MyLB

      @Component
      public class MyLB implements LoadBalancer {
          private  AtomicInteger atomicInteger=new AtomicInteger(0);
              //获取接口访问次数
          public final int getAndIncrement(){
              int current;
              int next;
              do{
                  current=this.atomicInteger.get();
                  next=current>=2147483647 ? 0:current+1;
              }while (!this.atomicInteger.compareAndSet(current,next));
              System.out.println("***第几次访问,次数next:"+next);
              return next;
          }
          //根据算法获取对应服务实例
          @Override
          public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
              int index=getAndIncrement() % serviceInstances.size();
              return  serviceInstances.get(index);
          }
      
      }
      
      
    5. 80服务controller中添加以下代码

        @Resource
        private DiscoveryClient discoveryClient;
        @Resource
        private LoadBalancer loadBalancer;
        @GetMapping(value = "/consumer/payment/lb")
        public String getPaymentLb(){
            List<ServiceInstance> instances = discoveryClient.getInstances("cloud-payment-service");
            if(instances == null || instances.size()<=0){
                return null;
            }
            ServiceInstance serviceInstance=loadBalancer.instances(instances);
            URI uri = serviceInstance.getUri();
            return restTemplate.getForObject(uri+"/payment/lb",String.class);
        }
      
    6. 依次启动服务,发送请求http://localhost/consumer/payment/lb验证
      前端返回对应服务的端口号,后端日志如下:


      即自定义算法运行成功。

posted @ 2023-05-12 14:05  kaizhengMan  阅读(75)  评论(0编辑  收藏  举报