Spring Cloud负载均衡概述
在不同的Spring Cloud版本中,采用了不同的负载均衡组件。
具体来说,在Spring Cloud 2020.0版本之前,默认负载均衡器为Netflix推出的Ribbon,自Spring Cloud 2020.0版本起,Ribbon已经被标记为过时,官方推荐使用Spring Cloud LoadBalancer。
在本文中阐述的是如何自定义Spring Cloud LoadBalancer默认实现,对应的框架版本信息如下:
- Spring Cloud版本:2021.0.5
- Spring Cloud Aliaba版本:2021.0.5.0
- Spring Boot版本:2.6.13
自定义Spring Cloud LoadBalancer默认实现
在Spring Cloud LoadBalancer组件中,默认的负载均衡器配置是通过org.springframework.cloud.loadbalancer.annotation.LoadBalancerClientConfiguration.reactorServiceInstanceLoadBalancer()方法实现的。
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Configuration(proxyBeanMethods = false) @ConditionalOnDiscoveryEnabled public class LoadBalancerClientConfiguration { @Bean @ConditionalOnMissingBean public ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) { String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME); return new RoundRobinLoadBalancer( loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name); } }
|
从源码来看,Spring Cloud LoadBalancer组件的默认负载均衡器为org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer,它通过轮训方式为服务消费者路由服务提供者。
值得注意的是,org.springframework.cloud.loadbalancer.annotation.LoadBalancerClientConfiguration.reactorServiceInstanceLoadBalancer()方法只会在首次调用RPC服务提供者时才会被调用,不同的RPC服务提供者首次访问都会调用,可以根据该机制为不通的服务提供者定制不同的负载均衡策略。
如果需要自定义配置负载均衡器,需要通过注解@LoadBalancerClients的defaultConfiguration属性指定才会生效。
自定义负载均衡路由器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
|
public class ShardBasedLoadBalancer implements ReactorServiceInstanceLoadBalancer { private static final Logger logger = LoggerFactory.getLogger(ShardBasedLoadBalancer.class); private final String serviceId; private final ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplier; private final Random random = new Random();
public ShardBasedLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplier, String serviceId) { this.serviceInstanceListSupplier = serviceInstanceListSupplier; this.serviceId = serviceId; }
@Override public Mono<Response<ServiceInstance>> choose(Request request) { ServiceInstanceListSupplier supplier = serviceInstanceListSupplier.getIfAvailable(NoopServiceInstanceListSupplier::new); return supplier.get().next().map(instances -> { if (instances.isEmpty()) { if (logger.isWarnEnabled()) { logger.warn("No servers available for service:{}", serviceId); } return new EmptyResponse(); }
int shardTotal = 0; int shardIndex = 0; ServiceInstance targetInstance; if ((shardIndex == 0 && shardTotal == 0) || (shardTotal > instances.size())) { targetInstance = instances.get(random.nextInt(instances.size())); } else { targetInstance = instances.get(shardIndex); } return new DefaultResponse(targetInstance); }); } }
|
在配置类中加载自定义负载均衡器(注意:不要在在配置类上使用@Configuration注解):
1 2 3 4 5 6 7 8 9 10 11
| public class LoadBalancerConfig { @Bean @ConditionalOnMissingBean public ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer( Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) { String serviceName = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME); return new ShardBasedLoadBalancer(loadBalancerClientFactory.getLazyProvider(serviceName, ServiceInstanceListSupplier.class), serviceName); } }
|
通过@LoadBalancerClients注解指定负载均衡配置类:
1 2 3 4 5 6 7 8 9
| @EnableDiscoveryClient @EnableFeignClients @SpringBootApplication @LoadBalancerClients(defaultConfiguration = LoadBalancerConfig.class) public class SampleAppApplication { public static void main(String[] args) { SpringApplication.run(SampleAppApplication.class, args); } }
|
【参考】
Spring Cloud Alibaba全家桶(三)——微服务负载均衡器Ribbon与LoadBalancer
LoadBalancer和Ribbon的区别是什么?
Spring Cloud:负载均衡 - Spring Cloud Loadbalancer原理