10、SpringCloud Alibaba - openFeign默认使用RoundRobinLoadBalancer负载均衡
前言
openFeign默认是通过 RoundRobinLoadBalancer 实现负载均衡。
一、默认配置
1、 LoadBalancerClientFactory;
负载均衡客户端工厂LoadBalancerClientFactory的创建是在LoadBalancerAutoConfiguration中
@ConditionalOnMissingBean
@Bean
public LoadBalancerClientFactory loadBalancerClientFactory() {
//创建 LoadBalancerClientFactory
LoadBalancerClientFactory clientFactory = new LoadBalancerClientFactory();
//使用LoadBalancerClientSpecification来扩展负载均衡
clientFactory.setConfigurations(this.configurations.getIfAvailable(Collections::emptyList));
return clientFactory;
}
2、 LoadBalancerClient;
负载均衡客户端LoadBalancerClient 默认实现是BlockingLoadBalancerClient,创建是在 BlockingLoadBalancerClientAutoConfiguration中
@Bean
@ConditionalOnBean(LoadBalancerClientFactory.class)
@ConditionalOnMissingBean
public LoadBalancerClient blockingLoadBalancerClient(LoadBalancerClientFactory loadBalancerClientFactory,
LoadBalancerProperties properties) {
return new BlockingLoadBalancerClient(loadBalancerClientFactory, properties);
}
3、 ServiceInstanceListSupplier;
服务列表提供者,默认创建是在ReactiveSupportConfiguration中
@Bean
@ConditionalOnBean(ReactiveDiscoveryClient.class)
@ConditionalOnMissingBean
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.configurations", havingValue = "default",
matchIfMissing = true)
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder().withDiscoveryClient().withCaching().build(context);
}
4、 ReactorLoadBalancer;
负载均衡接口,默认实现类创建是在LoadBalancerClientConfiguration中,使用的是 RoundRobinLoadBalancer
@Bean
@ConditionalOnMissingBean
public ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
//传入ClientFactoryObjectProvider,包含远程服务名称等
return new RoundRobinLoadBalancer(
loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
}
5、 FeignBlockingLoadBalancerClient;
它是feign 客户端的默认实现,创建是在DefaultFeignLoadBalancerConfiguration中,传入了LoadBalancerClientFactory、LoadBalancerClient等参数
@Bean
@ConditionalOnMissingBean
@Conditional(OnRetryNotEnabledCondition.class)
public Client feignClient(LoadBalancerClient loadBalancerClient, LoadBalancerProperties properties,
LoadBalancerClientFactory loadBalancerClientFactory) {
return new FeignBlockingLoadBalancerClient(new Client.Default(null, null), loadBalancerClient, properties,
loadBalancerClientFactory);
}
二、负载均衡流程
在FeignBlockingLoadBalancerClient中,执行远程服务之前,会先从服务列表中根据负载均衡算法选择合适的服务,下面针对服务的选择过程进行分析。
在FeignBlockingLoadBalancerClient 类的 execute( ) 方法中
ServiceInstance instance = loadBalancerClient.choose(serviceId, lbRequest);
这里的是loadBalancerClient 是 BlockingLoadBalancerClient
1、 choose();
public <T> ServiceInstance choose(String serviceId, Request<T> request) {
//获取默认的 RoundRobinLoadBalancer
ReactiveLoadBalancer<ServiceInstance> loadBalancer = loadBalancerClientFactory.getInstance(serviceId);
if (loadBalancer == null) {
return null;
}
//负载均衡
Response<ServiceInstance> loadBalancerResponse = Mono.from(loadBalancer.choose(request)).block();
if (loadBalancerResponse == null) {
return null;
}
//返回负载均衡选择的服务
return loadBalancerResponse.getServer();
}
2、 负载均衡;
loadBalancer.choose(request)
public Mono<Response<ServiceInstance>> choose(Request request) {
//获取服务列表提供者 CachingServiceInstanceListSupplier
ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
.getIfAvailable(NoopServiceInstanceListSupplier::new);
//封装获取服务逻辑
return supplier.get(request).next()
.map(serviceInstances -> processInstanceResponse(supplier, serviceInstances));
}
三、负载均衡实现
1、 CachingServiceInstanceListSupplier的创建;
带缓存的服务列表提供者,它实现了 ServiceInstanceListSupplier 接口,上面已经提到过,下面看一下它的创建过程:
ServiceInstanceListSupplier.builder().withDiscoveryClient().withCaching().build(context);
1、builder( )
创建builder 对象
static ServiceInstanceListSupplierBuilder builder() {
return new ServiceInstanceListSupplierBuilder();
}
2、withDiscoveryClient( )
定义了baseCreator 对象,用于创建DiscoveryClientServiceInstanceListSupplier对象CompositeDiscoveryClient
public ServiceInstanceListSupplierBuilder withDiscoveryClient() {
if (baseCreator != null && LOG.isWarnEnabled()) {
LOG.warn("Overriding a previously set baseCreator with a ReactiveDiscoveryClient baseCreator.");
}
this.baseCreator = context -> {
//获取到容器中的ReactiveDiscoveryClient ,这里是 CompositeDiscoveryClient,它是服务发现的核心类,下面还会提到
ReactiveDiscoveryClient discoveryClient = context.getBean(ReactiveDiscoveryClient.class);
return new DiscoveryClientServiceInstanceListSupplier(discoveryClient, context.getEnvironment());
};
return this;
}
3、withCaching( )
定义了cachingCreator ,用于创建带缓存功能的 CachingServiceInstanceListSupplier
public ServiceInstanceListSupplierBuilder withCaching() {
if (cachingCreator != null && LOG.isWarnEnabled()) {
LOG.warn(
"Overriding a previously set cachingCreator with a CachingServiceInstanceListSupplier-based cachingCreator.");
}
this.cachingCreator = (context, delegate) -> {
ObjectProvider<LoadBalancerCacheManager> cacheManagerProvider = context
.getBeanProvider(LoadBalancerCacheManager.class);
if (cacheManagerProvider.getIfAvailable() != null) {
return new CachingServiceInstanceListSupplier(delegate, cacheManagerProvider.getIfAvailable());
}
if (LOG.isWarnEnabled()) {
LOG.warn("LoadBalancerCacheManager not available, returning delegate without caching.");
}
return delegate;
};
return this;
}
4、build(context)
创建出CachingServiceInstanceListSupplier
public ServiceInstanceListSupplier build(ConfigurableApplicationContext context) {
Assert.notNull(baseCreator, "A baseCreator must not be null");
//获取 DiscoveryClientServiceInstanceListSupplier
ServiceInstanceListSupplier supplier = baseCreator.apply(context);
//使用 creators 进行包装
for (DelegateCreator creator : creators) {
supplier = creator.apply(context, supplier);
}
//获取 CachingServiceInstanceListSupplier
if (this.cachingCreator != null) {
supplier = this.cachingCreator.apply(context, supplier);
}
return supplier;
}
2、 DiscoveryClientServiceInstanceListSupplier;
1、构造方法
public DiscoveryClientServiceInstanceListSupplier(DiscoveryClient delegate, Environment environment) {
this.serviceId = environment.getProperty(PROPERTY_NAME);
resolveTimeout(environment);
//获取服务列表,delegate.getInstances(serviceId),其中delegate 是 CompositeDiscoveryClient
this.serviceInstances = Flux.defer(() -> Flux.just(delegate.getInstances(serviceId)))
.subscribeOn(Schedulers.boundedElastic()).timeout(timeout, Flux.defer(() -> {
logTimeout();
return Flux.just(new ArrayList<>());
})).onErrorResume(error -> {
logException(error);
return Flux.just(new ArrayList<>());
});
}
2、CompositeDiscoveryClient
在CompositeDiscoveryClientAutoConfiguration 中 ,创建 compositeDiscoveryClient对象,传入的参数是根据容器中的discoveryClients,容器中的DiscoveryClient 有NacosDiscoveryClient、SimpleDiscoveryClient
@Configuration(proxyBeanMethods = false)
@AutoConfigureBefore(SimpleDiscoveryClientAutoConfiguration.class)
public class CompositeDiscoveryClientAutoConfiguration {
@Bean
@Primary
public CompositeDiscoveryClient compositeDiscoveryClient(List<DiscoveryClient> discoveryClients) {
return new CompositeDiscoveryClient(discoveryClients);
}
}
3、DiscoveryClient
创建NacosDiscoveryClient,里面包含了 NacosServiceDiscovery
public class NacosDiscoveryClientConfiguration {
@Bean
public DiscoveryClient nacosDiscoveryClient(
NacosServiceDiscovery nacosServiceDiscovery) {
return new NacosDiscoveryClient(nacosServiceDiscovery);
}
}
4、NacosServiceDiscovery
在NacosDiscoveryAutoConfiguration 中 创建了 NacosServiceDiscovery ,传入的参数有NacosDiscoveryProperties 和 NacosServiceManager
@Configuration(proxyBeanMethods = false)
@ConditionalOnDiscoveryEnabled
@ConditionalOnNacosDiscoveryEnabled
public class NacosDiscoveryAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public NacosDiscoveryProperties nacosProperties() {
return new NacosDiscoveryProperties();
}
@Bean
@ConditionalOnMissingBean
public NacosServiceDiscovery nacosServiceDiscovery(
NacosDiscoveryProperties discoveryProperties,
NacosServiceManager nacosServiceManager) {
return new NacosServiceDiscovery(discoveryProperties, nacosServiceManager);
}
}
流程好像封装的有些复杂,现在理一下类之间的关系,从前到后依次是包含关系:
a)服务发现关键类之间的关系:
CompositeDiscoveryClient-》NacosDiscoveryClient-》NacosServiceDiscovery-》NacosServiceManager -》NacosNamingService -》hostReactor-》serviceInfoMap
其中最里面的 serviceInfoMap 包含了远程服务信息,也就是将 CompositeDiscoveryClient 与服务列表联系了起来。
b)服务列表提供者关键类之间的关系:
CachingServiceInstanceListSupplier -》DiscoveryClientServiceInstanceListSupplier -》CompositeDiscoveryClient
c)这样 ServiceInstanceListSupplier 与 CompositeDiscoveryClient 就关联了起来,而 CompositeDiscoveryClient 与 serviceInfoMap 又关联了起来。
3、 获取服务列表;
从delegate.getInstances(serviceId) 开始分析,也就是 CompositeDiscoveryClient 类中的getInstances( ) 方法
CompositeDiscoveryClient.java
@Override
public List<ServiceInstance> getInstances(String serviceId) {
if (this.discoveryClients != null) {
for (DiscoveryClient discoveryClient : this.discoveryClients) {
//调用 NacosDiscoveryClient 的 getInstances()
List<ServiceInstance> instances = discoveryClient.getInstances(serviceId);
if (instances != null && !instances.isEmpty()) {
return instances;
}
}
}
return Collections.emptyList();
}
@Override
public List<ServiceInstance> getInstances(String serviceId) {
try {
//调用 NacosServiceDiscovery 的 getInstances()
return serviceDiscovery.getInstances(serviceId);
}
catch (Exception e) {
throw new RuntimeException(
"Can not get hosts from nacos server. serviceId: " + serviceId, e);
}
}
public List<ServiceInstance> getInstances(String serviceId) throws NacosException {
String group = discoveryProperties.getGroup();
//获取服务列表
List<Instance> instances = namingService().selectInstances(serviceId, group,
true);
return hostToServiceInstanceList(instances, serviceId);
}
进入服务发现的流程,最终获取到对应 serviceId 的服务列表信息
4、 负载均衡实现;
获取到服务列表以后,回到 RoundRobinLoadBalancer 类中 processInstanceResponse 方法
private Response<ServiceInstance> processInstanceResponse(ServiceInstanceListSupplier supplier,
List<ServiceInstance> serviceInstances) {
//从服务列表中选择一个服务
Response<ServiceInstance> serviceInstanceResponse = getInstanceResponse(serviceInstances);
if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) {
((SelectedInstanceCallback) supplier).selectedServiceInstance(serviceInstanceResponse.getServer());
}
return serviceInstanceResponse;
}
具体的负载均衡算法,这里使用的是轮询
private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {
if (instances.isEmpty()) {
if (log.isWarnEnabled()) {
log.warn("No servers available for service: " + serviceId);
}
return new EmptyResponse();
}
// TODO: enforce order?
//位置加1
int pos = Math.abs(this.position.incrementAndGet());
//获取对应位置的服务
ServiceInstance instance = instances.get(pos % instances.size());
return new DefaultResponse(instance);
}