Spring Cloud LoadBalancer自定义负载均衡策略

2023-05-16

由于原有的负载均衡组件Ribbon停止维护,而完美的Spring生态怎能允许缺少负载均衡组件呢?Spring Cloud官方自己造出了Spring Cloud LoadBalancer来代替原有的Ribbon。由于是官方自己写的组件,所以并没有像eureka、Feign那样抽出一个单独的组件包出来。而放入到Spring Cloud Commons规范包中。

正文:

Spring Cloud LoadBalancer 帮开发者已经实现了RoundRobinLoadBalancer、RandomLoadBalancer,分别是轮训和随机,默认实现为轮训。

即让是负载均衡组件,那必然有默认实现,也必然有扩展接口暴露给开发者。所以第一步肯定是介绍抽象接口。

// 负载均衡的标志性接口,继承ReactorLoadBalancer接口
// 本接口无任何接口增强,仅仅作为一个标志性接口。
public interface ReactorServiceInstanceLoadBalancer extends ReactorLoadBalancer<ServiceInstance> 

// 在Spring Cloud高版本中大部分组件采用了Reacotr框架(有一说一,阅读性极差!!)
// 这里定义了一个选择的抽象方法。
public interface ReactorLoadBalancer<T> extends ReactiveLoadBalancer<T> {

	Mono<Response<T>> choose(Request request);

	default Mono<Response<T>> choose() {
		return choose(REQUEST);
	}

}

这里有涉及到Reactor框架,不过完全可以当黑盒使用。接口非常的简单就一个choose方法,所以接下来我们只需要实现此接口。

public class MyLB implements ReactorServiceInstanceLoadBalancer {

    private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;

    public MyLB(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider) {
        this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
    }

    @Override
    public Mono<Response<ServiceInstance>> choose(Request request) {
        ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
                .getIfAvailable(NoopServiceInstanceListSupplier::new);
        return supplier.get(request).next()
                .map(serviceInstances -> processInstanceResponse(supplier, serviceInstances));
    }

    private Response<ServiceInstance> processInstanceResponse(ServiceInstanceListSupplier supplier,
                                                              List<ServiceInstance> serviceInstances) {
        Response<ServiceInstance> serviceInstanceResponse = getInstanceResponse(serviceInstances);
        return serviceInstanceResponse;
    }
    
    // ServiceInstance作为注册表中的实例
    // 此方法写入自己的负载均衡策略逻辑即可。
    private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> serviceInstances) {
        if(serviceInstances.isEmpty()){
            return new EmptyResponse();
        }

        for (ServiceInstance serviceInstance : serviceInstances) {
            // 只返回8001。
            if (serviceInstance.getPort() == 8001) {
                return new DefaultResponse(serviceInstance);
            }
        }
        return new EmptyResponse();
    }
}

这里有部分逻辑,读者完全可以当作黑盒暂时不需要去理解。只需要明白从注册中心拿到注册表以后会执行getInstanceResponse方法,只需要实现自定义负载均衡策略的逻辑即可,好比我这里的逻辑是永远只调用一个服务(当然,这完全扯淡,仅仅是Demo无须太关心)

既然我们把自定义负载均衡策略写好了,那么,怎么告诉Spring呢?肯定需要注入给Spring。

@LoadBalancerClient(value = "deptmanagecloud-provider", configuration = MyConfig.class)
public class MyConfig {

    // 配置负载均衡策略
    @Bean
    public ReactorLoadBalancer<ServiceInstance> myLB(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new MyLB(
                loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class));
    }
}

这里需要➕上@LoadBalancerClient注解,value为调用方的服务名,configuration为配置类

到此,大功告成~!

总结:

相比以前的Ribbon的IRule方式这个要复杂一些,不过大部分都是造轮子,开发者只需要关心自定义的负载均衡逻辑即可~!

最后,如果本帖对您有一定的帮助,希望能点赞+关注+收藏!您的支持是给我最大的动力,后续会一直更新各种框架的使用和框架的源码解读~!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring Cloud LoadBalancer自定义负载均衡策略 的相关文章

随机推荐