【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

    結果:返回結果以達到輪詢的目的

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM