Spring Cloud LoadBalancer原理
LoadBalancerClient作為負載均衡客戶端,用於進行負載均衡邏輯,從服務列表中選擇出一個服務地址進行調用,其內部方法為下圖顯示:
(圖1-1)
在LoadBalancerClient種存在兩個execute()方法,均是用來執行請求的,reconstructURI()是用來重構URL。對於LoadBalancerClient在Spring Cloud LoadBalancer中實現類則是BlockingLoadBalancerClient。BlockingLoadBalancerClient存在兩個choose()方法,其實現的是圖1-1中的ServiceInstanceChooser接口種的兩個choose()方法(圖1-2):
(圖1-2)
在上述圖片中通過通過工廠類LoadBalancerClientFactory獲取具體的負載均衡器實例,后面的loadBalancer.choose(request)調用(圖1-3)接口choose()方法實現根據負載均衡算法選擇下一個服務器完成負載均衡。
(圖1-3)
圖1-3可以看出ReactorLoadBalancer接口繼承ReactiveLoadBalancer接口,ReactorLoadBalancer接口后續又被ReactorServiceInstanceLoadBalancer繼承且其實現了兩個方法,分別是:RandomLoadBalancer(隨機負載均衡器)和RoundRobinLoadBalancer(輪詢負載均衡器)。
(圖1-4)
LoadBalancer自定義負載均衡器
根據圖1-4類圖顯示,我們只需要在自定義配置輪詢方法時重定義ReactorServiceInstanceLoadBalancer接口即可,如下例子:
@Configuration public class MyLoadBalancerConfig { @Bean public ReactorServiceInstanceLoadBalancer reactorServiceInstanceLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) { String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME); //返回隨機輪詢負載均衡方式 return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name); } }
但是如果我們要自定義輪詢算法該如何做呢?根據上面可以知道LoadBalancerClientFactory是創建客戶機、負載均衡器和客戶機配置實例的工廠。它根據客戶端名稱創建一個Spring ApplicationContext,並從中提取所需的bean(官方解釋)。因此我們進入到LoadBalancerClientFactory類中:
(圖1-5)
我們需要去實現它的子接口ReactorServiceInstanceLoadBalancer,因為去獲取負載均衡器實例的時候,是通過去容器中查找ReactorServiceInstanceLoadBalancer類型的bean來實現的,參照RandomLoadBalancer我們進行仿寫
public class CustomRandomLoadBalancerClient implements ReactorServiceInstanceLoadBalancer { // 服務列表 private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider; public CustomRandomLoadBalancerClient(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider) { this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider; } @Override public Mono<Response<ServiceInstance>> choose(Request request) { ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider.getIfAvailable(); return supplier.get().next().map(this::getInstanceResponse); } /** * 使用隨機數獲取服務 * @param instances * @return */ private Response<ServiceInstance> getInstanceResponse( List<ServiceInstance> instances) { System.out.println("進來了"); if (instances.isEmpty()) { return new EmptyResponse(); } System.out.println("進行隨機選取服務"); // 隨機算法 int size = instances.size(); Random random = new Random(); ServiceInstance instance = instances.get(random.nextInt(size)); return new DefaultResponse(instance); } }
自定義配置類:
@Configuration public class MyLoadBalancerConfig { // 參數 serviceInstanceListSupplierProvider 會自動注入 @Bean public ReactorServiceInstanceLoadBalancer customLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider) { return new CustomRandomLoadBalancerClient(serviceInstanceListSupplierProvider); } }
在項目啟動類上添加@LoadBalancerClient注解:name值一定要使用服務端配置的服務名(spring.application.name),通過configuration指定自定義的配置
@SpringBootApplication @LoadBalancerClient(name = "myServer", configuration = MyLoadBalancerConfig.class) public class BlockClientApplication { public static void main(String[] args) { SpringApplication.run(BlockClientApplication.class, args); } }
以上內容參考借鑒總結得出,如有其他疑問可去一下地址查看詳情:
https://blog.csdn.net/weixin_50518271/article/details/111449560