Spring Cloud LoadBalancer原理講解及自定義負載均衡器


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

https://blog.csdn.net/qq_31142237/article/details/90486836


免責聲明!

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



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