zoukankan      html  css  js  c++  java
  • 【SpringCloud】自定义Ribbon均衡策略(七)

      本章介绍Ribbon自定义规则

    Ribbon自带随机均衡策略

      1、搭建项目,参考:【SpringCloud】服务提供者集群与服务发现Discovery(三) 

      2、新增配置类,配置类中注入IRule的实现类

        在调用者项目(test-springcloud-order8000)中,新增一个配置类com.test.myrule.MySelfRule

     1 package com.test.myrule;
     2 
     3 import com.netflix.loadbalancer.IRule;
     4 import com.netflix.loadbalancer.RandomRule;
     5 import org.springframework.context.annotation.Bean;
     6 import org.springframework.context.annotation.Configuration;
     7 
     8 @Configuration
     9 public class MySelfRule {
    10 
    11     @Bean
    12     public IRule myRule(){
    13         // 定义随机规则
    14         return new RandomRule();
    15     }
    16 }

       注意,官方文档明确给出警告:

        这个自定义配置类不能放在@Configuration所扫描的当前包及子包下,否则我们自定义的这个配置类就会被所有Ribbon客户端共享,达不到特殊化定制的目的了

        如果想要Ribbon客户端共享,那边就放在@Configuration所扫描的地方

        

      3、使用新增的配置类对“CLOUD-PAYMENT-SERVICE”服务生效,在启动类com.test.springcloud.Application上增加注解

        @RibbonClient(name = "CLOUD-PAYMENT-SERVICE", configuration = MySelfRule.class)

        name指定针对哪个服务 进行负载均衡,而configuration指定负载均衡的算法具体实现类。

     1 package com.test.springcloud;
     2 
     3 import com.test.myrule.MySelfRule;
     4 import org.springframework.boot.SpringApplication;
     5 import org.springframework.boot.autoconfigure.SpringBootApplication;
     6 import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
     7 import org.springframework.cloud.netflix.ribbon.RibbonClient;
     8 
     9 @EnableEurekaClient
    10 @SpringBootApplication
    11 @RibbonClient(name = "CLOUD-PAYMENT-SERVICE", configuration = MySelfRule.class)
    12 public class OrderMain80 {
    13     public static void main(String[] args) {
    14         SpringApplication.run(OrderMain80.class, args);
    15     }
    16 }

      4、启动项目,测试项目

        使用地址:http://localhost:8000/consumer/payment/get/1

        可以看到,的到的响应内容是从提供者的2个节点中,随机的到的。

    自定义Ribbon均衡策略

      1、新增一个IRule的实现类

     1 package com.test.myrule;
     2 
     3 import com.netflix.client.config.IClientConfig;
     4 import com.netflix.loadbalancer.AbstractLoadBalancerRule;
     5 import com.netflix.loadbalancer.ILoadBalancer;
     6 import com.netflix.loadbalancer.Server;
     7 
     8 import java.util.List;
     9 
    10 public class MyCustomeRule extends AbstractLoadBalancerRule {
    11 
    12     private int total = 0;             // 总共被调用的次数,目前要求每台被调用5次
    13     private int currentIndex = 0;    // 当前提供服务的下标
    14 
    15     public Server choose(ILoadBalancer loadBalancer, Object key) {
    16 
    17         if (loadBalancer == null) {
    18             return null;
    19         }
    20         Server server = null;
    21 
    22         while (server == null) {
    23             if (Thread.interrupted()) {
    24                 return null;
    25             }
    26             List<Server> upList = loadBalancer.getReachableServers(); //当前存活的服务
    27             List<Server> allList = loadBalancer.getAllServers();  //获取全部的服务
    28 
    29             int serverCount = allList.size();
    30             if (serverCount == 0) {
    31                 return null;
    32             }
    33 
    34             //int index = rand.nextInt(serverCount);
    35             //server = upList.get(index);
    36             if(total < 5)
    37             {
    38                 server = upList.get(currentIndex);
    39                 total++;
    40             }else {
    41                 total = 0;
    42                 currentIndex++;
    43                 if(currentIndex >= upList.size())
    44                 {
    45                     currentIndex = 0;
    46                 }
    47             }
    48 
    49             if (server == null) {
    50                 Thread.yield();
    51                 continue;
    52             }
    53 
    54             if (server.isAlive()) {
    55                 return (server);
    56             }
    57 
    58             // Shouldn't actually happen.. but must be transient or a bug.
    59             server = null;
    60             Thread.yield();
    61         }
    62         return server;
    63     }
    64 
    65     public Server choose(Object key) {
    66         return choose(getLoadBalancer(), key);
    67     }
    68     public void initWithNiwsConfig(IClientConfig clientConfig) {
    69 
    70     }
    71 }
    View Code

      2、修改配置类,在配置类中注入新编写的实现类,同上

      @RibbonClient(name = "CLOUD-PAYMENT-SERVICE", configuration =MyCustomeRule.class)

      3、启动项目,测试

      使用地址:http://localhost:8000/consumer/payment/get/1

      结果:每5次访问,之后切换节点

    自定义均衡器

      流程:使用DiscoveryClient发现服务—》通过自定义均衡器筛选服务—》使用RestTemplate调用

      1、自定义均衡器接口

    1 public interface LoadBalancer {
    2 
    3     // 筛选出服务
    4     ServiceInstance instances(List<ServiceInstance> serviceInstances);
    5 }

      2、编写接口实现类

     1 @Component
     2 public class MyLB implements  LoadBalancer {
     3 
     4     private AtomicInteger atomicInteger = new AtomicInteger(0);
     5 
     6     public final int getAndIncrement(){
     7         int current;
     8         int next;
     9         do {
    10             current = this.atomicInteger.getAndIncrement();
    11             next = current >= Integer.MAX_VALUE ? 0 : current + 1;
    12         } while (this.atomicInteger.compareAndSet(current, next));
    13         System.out.println("=======next:" + next);
    14         return next;
    15     }
    16 
    17     public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
    18 
    19         int index = getAndIncrement() % serviceInstances.size();
    20         return serviceInstances.get(index);
    21     }
    22 }

      3、编写controller方法

     1 @RestController
     2 @Slf4j
     3 public class OrderController {
     4 
     5     @Autowired
     6     private LoadBalancer loadBalancer;
     7 
     8     @Autowired
     9     private DiscoveryClient discoveryClient;
    10 
    11     // 未使用Ribbon包装restTemplate
    12     private RestTemplate restTemplate = new RestTemplate();
    13 
    14 
    15     @GetMapping("/consumer/payment/get/{id}/lb")
    16     public CommonResult<Payment> getPaymentLB(@PathVariable("id") Long id){
    17         List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
    18         if(instances == null || instances.size() == 0) {
    19             return null;
    20         }
    21 
    22         ServiceInstance instance = loadBalancer.instances(instances);
    23         URI uri = instance.getUri();
    24 
    25         return restTemplate.getForObject(uri + "/payment/get/" + id, CommonResult.class);
    26     }
    27 }

        注意:

        1)restTemplate对象,未被Ribbon包装

        2)此处的instance.getUri()获取的url地址,可能是主机名称+端口,需要改成是IP+端口。而要获取到的是IP+端口,需要服务提供者,在Eureka注册的时候,使用ip注册

        服务端注册增加配置如下:

    1 eureka:
    2   instance:
    3     #  instance:
    4     instance-id: ${spring.cloud.client.ip-address}:${server.port}
    5     # 访问路径可以显示IP地址
    6     prefer-ip-address: true

      4、启动项目,测试

        访问地址:http://localhost:8000/consumer/payment/get/1/lb

        结果:返回结果以达到轮询的目的

  • 相关阅读:
    PHP保留小数的相关方法
    ASP.NET Core MVC 之过滤器(Filter)
    ASP.NET Core MVC 之控制器(Controller)
    ASP.NET Core MVC 之视图组件(View Component)
    ASP.NET Core MVC 之局部视图(Partial Views)
    标签助手(TagHelper)
    ASP.NET Core MVC 之布局(Layout)
    ASP.NET Core MVC 之视图(Views)
    ASP.NET Core MVC 之模型(Model)
    九卷读书:淘宝从小到大的发展 -重读《淘宝技术这十年》
  • 原文地址:https://www.cnblogs.com/h--d/p/12687015.html
Copyright © 2011-2022 走看看