SpringCloud 微服务客户端服务列表缓存优化. nacos2.0.2 与 spring-cloud-loadbalancer
获取所有服务列表com.alibaba.cloud.nacos.discovery.NacosDiscoveryClient#getServices发一个grpc请求获取服务列表根据serviceId获取服务列表com.alibaba.nacos.client.naming.NacosNamingService#selectInstances()com.alibaba.nacos.client.n
·
获取所有服务列表
- com.alibaba.cloud.nacos.discovery.NacosDiscoveryClient#getServices
- 发一个grpc请求获取服务列表
根据serviceId获取服务列表
- com.alibaba.nacos.client.naming.NacosNamingService#selectInstances()
- com.alibaba.nacos.client.naming.cache.ServiceInfoHolder#getServiceInfo
- com.alibaba.nacos.client.naming.cache.ServiceInfoHolder#serviceInfoMap
- nacos 客户端缓存(serviceInfoMap)维护方式
- com.alibaba.nacos.client.naming.cache.ServiceInfoHolder#processServiceInfo(o)
- com.alibaba.nacos.client.naming.core.PushReceiver#run
- UDP 方式接收服务列表
- com.alibaba.nacos.client.naming.cache.ServiceInfoHolder#processServiceInfo(java.lang.String)
- com.alibaba.nacos.client.naming.core.ServiceInfoUpdateService.UpdateTask#run
- 定时刷新本地服务列表
- com.alibaba.nacos.client.naming.remote.NamingClientProxyDelegate#subscribe
- grpc 订阅服务.
- com.alibaba.nacos.client.naming.remote.gprc.NamingPushRequestHandler#requestReply
- com.alibaba.nacos.common.remote.client.grpc.GrpcClient#bindRequestStream
- grpc 客户端方式接收注册中心推送然后更新服务列表
- 如果想要拿到这个事件,必须先订阅.意思是在本地至少调用过目标的微服务.
- com.alibaba.nacos.client.naming.core.ServiceInfoUpdateService.UpdateTask#run
- com.alibaba.nacos.client.naming.cache.ServiceInfoHolder#processServiceInfo(o)
- nacos 客户端的服务列表维护使用的服务端push的方式来维护. 所以服务列表都是最新的
spring cloud loadbalancer 服务列表缓存
- 服务间调用时 负载均衡器是从自己维护的缓存列表中拿service列表
- org.springframework.cloud.loadbalancer.annotation.LoadBalancerClientConfiguration.ReactiveSupportConfiguration
- 针对webflux 应用服务提供的客户端服务实例提供者的配置
- org.springframework.cloud.loadbalancer.annotation.LoadBalancerClientConfiguration.BlockingSupportConfiguration
- 针对webmvc 应用服务提供的客户端服务实例提供者的配置
- default
- 缓存的服务列表提供者
- zone-preference
- 可用区隔离服务列表提供者+cache
- health-check
- 基于健康检查的服务列表提供者
- request-based-sticky-session
- 粘性会话 + 健康检查
- same-instance-preference
- 它选择先前选择的实例(如果可用)
- org.springframework.cloud.loadbalancer.annotation.LoadBalancerClientConfiguration.ReactiveSupportConfiguration
- default方式服务列表缓存的维护.
spring cloud loadbalancer 中的LoadBalancerClientFactory
- 父类中的NamedContextFactory
protected AnnotationConfigApplicationContext getContext(String name) {
if (!this.contexts.containsKey(name)) {
synchronized (this.contexts) {
if (!this.contexts.containsKey(name)) {
this.contexts.put(name, createContext(name));
}
}
}
return this.contexts.get(name);
}
protected AnnotationConfigApplicationContext createContext(String name) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
if (this.configurations.containsKey(name)) {
for (Class<?> configuration : this.configurations.get(name).getConfiguration()) {
context.register(configuration);
}
}
for (Map.Entry<String, C> entry : this.configurations.entrySet()) {
if (entry.getKey().startsWith("default.")) {
for (Class<?> configuration : entry.getValue().getConfiguration()) {
context.register(configuration);
}
}
}
context.register(PropertyPlaceholderAutoConfiguration.class, this.defaultConfigType);
context.getEnvironment().getPropertySources().addFirst(new MapPropertySource(this.propertySourceName,
Collections.<String, Object>singletonMap(this.propertyName, name)));
if (this.parent != null) {
// Uses Environment from parent as well as beans
context.setParent(this.parent);
// jdk11 issue
// https://github.com/spring-cloud/spring-cloud-netflix/issues/3101
context.setClassLoader(this.parent.getClassLoader());
}
context.setDisplayName(generateDisplayName(name));
context.refresh();
return context;
}
- 会根据每一个serviceId生成一个子的AnnotationConfigApplicationContext 容器
- 例如gateway的filter中获取此 ReactiveLoadBalancer 获取的就是某个服务的负载均衡器.其中包含了
ServiceInstanceListSupplier
类
private Mono<Response<ServiceInstance>> choose(Request<RequestDataContext> lbRequest, String serviceId,
Set<LoadBalancerLifecycle> supportedLifecycleProcessors) {
ReactorLoadBalancer<ServiceInstance> loadBalancer = this.clientFactory.getInstance(serviceId,
ReactorServiceInstanceLoadBalancer.class);
if (loadBalancer == null) {
throw new NotFoundException("No loadbalancer available for " + serviceId);
}
supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStart(lbRequest));
return loadBalancer.choose(lbRequest);
}
优化.
- 以上我们知道nacos客户端的缓存可以直接用. 不想再用 LoadBalancer 的缓存了(因为不是实时的). 可以修改下
ServiceInstanceListSupplier
的bean实现 - 配置:
@Configuration(proxyBeanMethods = false)
@ConditionalOnReactiveDiscoveryEnabled
public static class ReactiveSupportConfiguration {
@Bean
@ConditionalOnBean(ReactiveDiscoveryClient.class)
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
//使用nacos client的ServiceInfoHolder缓存而不使用 LoadBalancer 的缓存
return ServiceInstanceListSupplier.builder().withDiscoveryClient().build(context);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnBlockingDiscoveryEnabled
public static class BlockingSupportConfiguration {
@Bean
@ConditionalOnBean(DiscoveryClient.class)
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
//使用nacos client 的ServiceInfoHolder 缓存而不使用 LoadBalancer 的缓存
return ServiceInstanceListSupplier.builder().withBlockingDiscoveryClient().build(context);
}
}
- 因为
discoveryClient
的实现就是nacosDiscoveryClient
其中的getInstances(serviceId)
方法是走ServiceInfoHolder
的缓存的. - 在项目启动时不会初始化这两个配置. 在第一次调用的时候才会初始化这个配置类. 对应上面的
LoadBalancerClientFactory
更多推荐
已为社区贡献1条内容
所有评论(0)