1. @LoadBalanced注解详解
1.1 简介
Ribbon依赖地址:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
**@LoadBalanced
将一个RestTemplate标志为底层采用LoadBalancerClient来执行实际的http操作,支持负载均衡,找这个注解对应工程下的包**
工程地址:https://github.com/spring-cloud/spring-cloud-commons
1.2 LoadBalancerAutoConfiguration
可以找到LoadBalancerAutoConfiguration
这个配置类,一般spring cloud或者是spring boot相关的项目,一定会有一个XXAutoConfiguraiton的一个东西,来初始化一些配置或者记载什么的。
1.2.1 restTemplates
Ribbon将所有标记@LoadBalanced
注解的RestTemplate
保存到一个List集合当中
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
RestTemplate继承InterceptingHttpAccessor,提供了获取和设置拦截器的方法
1.2.2 loadBalancedRestTemplateInitializer
loadBalancedRestTemplateInitializer()
初始化一些东西,里面有个内部类,拿到当前的RestTemplate
进行遍历,遍历customizers
专门用来定制RestTemplate
组件,用每个customizers来定制每个RestTemplate
在这个方法中会为所有被@LoadBalanced注解标识的 RestTemplate添加ribbon的自定义拦截器LoadBalancerInterceptor
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializer(
final List<RestTemplateCustomizer> customizers) {
return new SmartInitializingSingleton() {
@Override
public void afterSingletonsInstantiated() {
for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
for (RestTemplateCustomizer customizer : customizers) {
customizer.customize(restTemplate);
}
}
}
};
}
在restTemplateCustomizer
方法里面会为每个放进来的RestTemplate
定制一个ClientHttpRequestInterceptor
拦截器,实现拦截器的是他的子类LoadBalancerInterceptor
- 创建Ribbon自定义拦截器LoadBalancerInterceptor
- 添加拦截器具体方法。首先获取当前拦截器集合(List),然后将loadBalancerInterceptor添加到当前集合中,最后将新的集合放回到restTemplate中。
@Configuration
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
static class LoadBalancerInterceptorConfig {
@Bean
public LoadBalancerInterceptor ribbonInterceptor(
LoadBalancerClient loadBalancerClient,
LoadBalancerRequestFactory requestFactory) {
return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
final LoadBalancerInterceptor loadBalancerInterceptor) {
return new RestTemplateCustomizer() {
@Override
public void customize(RestTemplate restTemplate) {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
}
};
}
}
1.2.3 ClientHttpRequestInterceptor
完成拦截请求后的逻辑内容,由子类LoadBalancerInterceptor
来实现拦截请求,看下拦截器里面的逻辑,当对RestTemplate
执行某种操作的时候,比如请求一个服务的接口,此时不会由RestTemplate
来实现,而是由这个拦截器来实现这个请求的http
请求
- request.getURI():获取请求路径 http://ServiceA/sayHello/leo
- originalUri.getHost():获取服务名:ServiceA
- 发送请求
2.RibbonLoadBlancerClient 剖析
当发起请求时ribbon会用LoadBalancerInterceptor
这个拦截器进行拦截。在该拦截器中会调用LoadBalancerClient.execute()
方法
具体执行execute()
由子类RibbonLoadBlancerClient 执行
2.1 RibbonLoadBalancerClient 初始化
RibbonLoadBlancerClient
实际位置在spring-cloud-netflix-core
工程org.springframework.cloud.netflix.ribbon
包中RibbonAutoConfiguration
类中,实例化注入bean
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tA6yvNMc-1657457021110)(C:\Users\崔小畅\AppData\Roaming\Typora\typora-user-images\image-20220709155938771.png)]
2.2 execute()具体执行请求的方法
2.2.1 getLoadBalancer
通过参数serviceId
也就是服务名,到这个里面 this.clientFactory.getLoadBalancer(serviceId)
这个clientFactory就是SpringClientFactory
意思就是说你要调用的每个服务名称对应都得有一个spring的ApplicationContext容器,比如 ServiceA服务对应的自己ApplicationContext 容器、ServiceB服务对应自己的ApplicationContext容器
ApplicationContext容器获取自己的ILoadBalancer,里面包含了自己这个服务的独立的一堆组件,比如说LoadBalancer,如果要获取一个服务对应的LoadBalancer,其实就是在自己的那个ApplicationContext里面去获取那个LoadBalancer即可。根据ILoadBalancer接口类型,获取一个ILoadBalancer接口类型的实例化的bean即可
protected ILoadBalancer getLoadBalancer(String serviceId) {
return this.clientFactory.getLoadBalancer(serviceId);
}
@Override
public <C> C getInstance(String name, Class<C> type) {
C instance = super.getInstance(name, type);
if (instance != null) {
return instance;
}
IClientConfig config = getInstance(name, IClientConfig.class);
return instantiateWithConfig(getContext(name), type, config);
}
private Map<String, AnnotationConfigApplicationContext> contexts = new ConcurrentHashMap<>();
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);
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cFR6uN1w-1657457021112)(C:\Users\崔小畅\AppData\Roaming\Typora\typora-user-images\image-20220709165131195.png)]
2.2.1.1 ZoneAwareLoadBalancer
ILoadBalancer执行是的ZoneAwareLoadBalancer 父类来执行
-
看看ZoneAwareLoadBalancer
什么都没有,直接调用父类DynamicServerListLoadBalancer
-
看看DynamicServerListLoadBalancer
-
super执行一个initWithConfig()
启动一个任务调度,每隔10秒 ping一次服务实例,检查状态,可以查看
2.2.1.1.3
IPing
public BaseLoadBalancer(IClientConfig config, IRule rule, IPing ping) {
initWithConfig(config, rule, ping);
}
void setupPingTask() {
if (canSkipPing()) {
return;
}
if (lbTimer != null) {
lbTimer.cancel();
}
lbTimer = new ShutdownEnabledTimer("NFLoadBalancer-PingTimer-" + name,
true);
lbTimer.schedule(new PingTask(), 0, pingIntervalSeconds * 1000);
forceQuickPing();
}
-
restOfInit
-
enableAndInitLearnNewServersFeature():定时更新
ServerListUpdater就是PollingServerListUpdater,可以看2.2.1.1.1ServerList 有详解
在PollingServerListUpdater中,创建了一个Runnable线程,里面就是执行UpdateAction的行为,在延迟一定的时间过后,每隔一定的时间就执行一下那个Runnable线程,就会执行UpdateAction中的操作来刷新注册表,从eureka client中获取注册表,然后刷新到LoadBalancer中去
public void enableAndInitLearnNewServersFeature() { LOGGER.info("Using serverListUpdater {}", serverListUpdater.getClass().getSimpleName()); serverListUpdater.start(updateAction); }
public synchronized void start(final UpdateAction updateAction) { if (isActive.compareAndSet(false, true)) { final Runnable wrapperRunnable = new Runnable() { @Override public void run() { if (!isActive.get()) { if (scheduledFuture != null) { scheduledFuture.cancel(true); } return; } try { updateAction.doUpdate(); lastUpdated = System.currentTimeMillis(); } catch (Exception e) { logger.warn("Failed one update cycle", e); } } }; // private static long LISTOFSERVERS_CACHE_UPDATE_DELAY = 1000; // msecs; // private static int LISTOFSERVERS_CACHE_REPEAT_INTERVAL = 30 * 1000; // msecs; // 默认的是1秒钟过后,会第一次执行那个Runnable线程, //以后是每隔30秒执行一下那个Runnable线程,就去从eureka client刷新注册表到自己的ribbon的LoadBalancer中来。 scheduledFuture = getRefreshExecutor().scheduleWithFixedDelay( wrapperRunnable, initialDelayMs, refreshIntervalMs, TimeUnit.MILLISECONDS ); } else { logger.info("Already active, no-op"); } }
public void doUpdate() { DynamicServerListLoadBalancer.this.updateListOfServers(); }
public void updateListOfServers() { List<T> servers = new ArrayList(); if (this.serverListImpl != null) { servers = this.serverListImpl.getUpdatedListOfServers(); LOGGER.debug("List of Servers for {} obtained from Discovery client: {}", this.getIdentifier(), servers); if (this.filter != null) { servers = this.filter.getFilteredListOfServers((List)servers); LOGGER.debug("Filtered List of Servers for {} obtained from Discovery client: {}", this.getIdentifier(), servers); } } this.updateAllServerList((List)servers); }
-
updateListOfServers()更新server list
public void updateListOfServers() { List<T> servers = new ArrayList<T>(); if (serverListImpl != null) { servers = serverListImpl.getUpdatedListOfServers(); LOGGER.debug("List of Servers for {} obtained from Discovery client: {}", getIdentifier(), servers); if (filter != null) { servers = filter.getFilteredListOfServers(servers); LOGGER.debug("Filtered List of Servers for {} obtained from Discovery client: {}", getIdentifier(), servers); } } updateAllServerList(servers); }
-
protected void updateAllServerList(List<T> ls) {
// other threads might be doing this - in which case, we pass
if (serverListUpdateInProgress.compareAndSet(false, true)) {
try {
for (T s : ls) {
s.setAlive(true); // set so that clients can start using these
// servers right away instead
// of having to wait out the ping cycle.
}
setServersList(ls);
super.forceQuickPing();
} finally {
serverListUpdateInProgress.set(false);
}
}
}
public void setServersList(List lsrv) {
super.setServersList(lsrv);
List<T> serverList = (List<T>) lsrv;
Map<String, List<Server>> serversInZones = new HashMap<String, List<Server>>();
for (Server server : serverList) {
// make sure ServerStats is created to avoid creating them on hot
// path
getLoadBalancerStats().getSingleServerStat(server);
String zone = server.getZone();
if (zone != null) {
zone = zone.toLowerCase();
List<Server> servers = serversInZones.get(zone);
if (servers == null) {
servers = new ArrayList<Server>();
serversInZones.put(zone, servers);
}
servers.add(server);
}
}
setServerListForZones(serversInZones);
}
2.2.1.1.1 ServerList
代表了服务的server list。肯定是从eureka里去读的,但是这里的这个ServerList是从配置里面读的,不是我们要找的这个
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oCmWVDU7-1657457021115)(C:\Users\崔小畅\AppData\Roaming\Typora\typora-user-images\image-20220709172536439.png)]
具体用的serverList在spring-cloud-netflix-eureka-client
工程下的org.springframework.cloud.netflix.ribbon.eureka
包下的EurekaRibbonClientConfiguration
中,实例化通过@Bean 注入
提供啦getUpdatedListOfServers
来获取serverList
eurekaClientProvider.get()`获取eureka client
VipAddress
:服务名
eurekaClient.getInstancesByVipAddress
通过服务名称从eurekaClient本地注册表获取服务实例
2.2.1.1.2 IRule
在spring-cloud-netflix-core
工程下的org.springframework.cloud.netflix.ribbon
包下的RibbonClientConfiguration
类中
ZoneAvoidanceRule的父类PredicateBasedRule提供啦choose() round robin轮询算法
2.2.1.1.3 IPing
ping一下服务器,看看服务器是否存活
改组件在spring-cloud-netflix-eureka-client
工程下ribbon和eureka整合包中
,NIWSDiscoveryPing
类中提供一个isAlive()
判断服务实例是否存活
其实就是判断服务实例的状态
2.2.1.1.4 ServerListUpdater
PollingServerListUpdater这个组件提供啦更新ServerList的方法
2.2.2 getServer: 通过负载均衡算法(round robin轮询算法),选择一个server出来
loadBalancer.chooseServer():调用的是父类ZoneAwareLoadBalancer.chooseServer()
ZoneAwareLoadBalancer有调用父类chooseServer()–>BaseLoadBalancer.chooseServer()
getLoadBalancerStats().getAvailableZones().size():多机房的概念
直接就是用的IRule来选择了一台服务器
IRule是哪来的勒?看2.2.1.2
轮询算法
modulo:当前有几天机器
nextIndex:AtomicInteger nextIndex = new AtomicInteger() 刚开始默认是0
比如说有三台机器
192.168.1.107:8080
192.168.1.108:8080
192.168.1.109:8080
第一次发请求过来:current = nextIndex=0 ,next = current =0+1=1%3 =1 ,cas把current 设置成1 ,return 0
第二次发请求过来:current = nextIndex=1 ,next = current =1+1=2%3 =2,cas把current 设置成2,return 1
第三次发请求过来:current = nextIndex=2,next = current =2+1=3%3 =0 ,cas把current 设置成0,return 2
第三次发请求过来:current = nextIndex=0,next = current =0+1=1%3 =1 ,cas把current 设置成1,return 0
private int incrementAndGetModulo(int modulo) {
for (;;) {
int current = nextIndex.get();
int next = (current + 1) % modulo;
if (nextIndex.compareAndSet(current, next) && current < modulo)
return current;
}
}
2.3 最后执行请求的方法
根据serviceId=服务名称从SpringClientFactory中拿到对应的RibbonLoadBalancerContext
LoadBalancerRequest是一个匿名内部类,request.apply()传入负载均衡选入出来的服务实例,调用的内部类的apply()发送请求
-
RibbonLoadBlancerClient
剖析
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jUlADWoM-1657457021124)(CEE153E456F843F8816375A148E55C8F)]-
execute
具体执行请求的方法 -
getLoadBalancer()
方法获取ILoadBalancer 负载均衡器接口- 通过参数
serviceId
也就是服务名,到这个里面this.clientFactory.getLoadBalancer(serviceId)
这个clientFactory就是SpringClientFactory
意思就是说你要调用的每个服务对应得服务名称都有一个对应spring的applicationContext容器,比如 ServiceA服务对应的自己ApplicationContext容器获取自己的ILoadBalancer,里面包含了自己这个服务的独立的一堆组件,比如说LoadBalancer,如果要获取一个服务对应的LoadBalancer,其实就是在自己的那个ApplicationContext里面去获取那个LoadBalancer即可。根据ILoadBalancer接口类型,获取一个ILoadBalancer接口类型的实例化的bean即可
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tOpm9HSI-1657457021125)(AB3A22730DE94A429C5E8E06B775A582)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eCi6RDyH-1657457021125)(8B6D484413754A968B9F8382DDCF42BB)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nToIWA1R-1657457021126)(FCA19A554FED42B584A6511BB14DBD5C)]
- 调用父类的
getInstance()
方法拿取ILoadBalancer
直接返回
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yGuV8mR3-1657457021126)(60F786012D4A4C05B0C3315969DD1428)] contexts
是一个map
,如果这个服务名存在,就直接中map
中去,如果不存在,就创建,然后存到map
中
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n1JKnl9C-1657457021127)(ABF7DC1D4CBE4EF59AA652CB7E84151F)]- 这一块就很明确了,一个服务对应一个独立的
applicationContext
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wnCyzSHu-1657457021128)(4B32A773570545EB938727320E6C6541)] - 流程图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z1A0sUtR-1657457021128)(B481C5CE903A45F4B3FE922CF373CBE8)]
- 通过参数
-
getServer(loadBalancer)
通过负载均衡算法(round robin轮询算法),选择一个server出来
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2sECyWQY-1657457021129)(9B5669EF037746B2820A5B80F8668C59)]- 调用父类chooseServer()方法,父类BaseLoadBalander
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jdQBWhHZ-1657457021129)(5F500459AB084E7EA4AA2682016A1CB4)] - BaseLoadBalancer的chooseServer()方法中,直接就是用的IRule来选择了一台服务器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7eKqGqYS-1657457021130)(B57016114BCF4C1F929B5F2E70416DC6)] - IRule 实例化在这,调用ZoneAvoidanceRule 父类的choose()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6TOh8E02-1657457021130)(BE1CFFB0CF5C4E22A19D59FF47442CDA)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dy7TZsPt-1657457021131)(1C53DEB70F654FDB9AABEA5BAC63D1CC)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EBLGc1CI-1657457021131)(D8DCDDB65F9849698A9CA427B4261929)] - 负载均衡实际就是用的轮询算法,nextIndex是一个AtomicInteger,默认是0开始,当前的(current+1)%modulo(当前服务机器的数量)=next,然后把next更新到current里面,返回选中的机器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cYXQluGI-1657457021132)(52292173E183450D8757CAE8F9A146FF)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w6Sbv2f5-1657457021132)(86D2935C466B422FA11B580E88A8EA98)]
- 调用父类chooseServer()方法,父类BaseLoadBalander
-
execute(serviceId, ribbonServer, request)
最后执行请求,这个reuqest 就是在拦截器哪里调用execute()
通过requestFactory.createRequest
创建
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gXIKS8BP-1657457021133)(B572FB9C034B469AA5C1ECBEE1BC3E58)]- 主要就是封装一些请求参数,比如http://ServiceA/sayHello/leo ==> 替换成http://localhost:8080/sayHello/leo,就用这个请求,基于底层的ClientHttpRequestExecution发起一次http请求
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wYLydVEh-1657457021134)(02AAAA8EE2884A1CA4119633ADC658C7)]
- 主要就是封装一些请求参数,比如http://ServiceA/sayHello/leo ==> 替换成http://localhost:8080/sayHello/leo,就用这个请求,基于底层的ClientHttpRequestExecution发起一次http请求
-
-
ILoadBlancer
是什么东西,干吗用的?ILoadBlancer
实例化,在spring-cloud-netflix-core
工程下的org.springframework.cloud.netflix.ribbon
包中的RibbonClientConfiguration
类中
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ohkAn6j2-1657457021134)(C332F112BEC540C7A1D22FC2E81C5A14)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kmm1R9xT-1657457021135)(3515B9AD0E104290AD8FE1934486B27E)]- 创建的
ZoneAwareLoadBalancer
,ZoneAwareLoadBalancer
的父类是:DynamicServerListLoadBalancer
,他的父类又是:BaseLoadBalancer
- 看核心方法
restOfInit
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d0dbCxWY-1657457021135)(30BEE7925B8A4CE19AED5C0F1FDE817B)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qBbD9xsd-1657457021136)(E1C8970CE29848CF89AA7491118FB521)] enableAndInitLearnNewServersFeature
定时刷新从eureka client中获取注册表(定时任务),然后刷新到LoadBalancer中去,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uk3FjxLr-1657457021136)(7709709B76E742E7BA55254EC118E980)]- 通过start()创建一个Runnable线程,然后用任务调度每隔30s执行Runnable线程,从eureka client 刷新注册表到自己的Ribbon的ILoadBalancer
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LAvK3Cbv-1657457021137)(3C3999E1DA2A4BCE9820943897BD1A06)]
- 通过start()创建一个Runnable线程,然后用任务调度每隔30s执行Runnable线程,从eureka client 刷新注册表到自己的Ribbon的ILoadBalancer
updateListOfServers()
:通过这个方法,从eureka client那里获取到Service的server list 服务下的所有服务实例
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vC7eEaoE-1657457021138)(F56012D0B9C8431683D990C7BBC108A9)]serverListImpl
是通过构造函数传过来的,就是个serverList
,具体在spring-cloud-netflix-eureka-client
工程下的org.springframework.cloud.netflix.ribbon.eureka
包下的EurekaRibbonClientConfiguration
中,实例化通过@Bean 注入
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QD1yMXeo-1657457021138)(B1A1C7C7499A40B49B433971B02C64FA)]- 通过
serverListImpl.getUpdatedListOfServers
拿到服务下的所有服务实例,getUpdatedServerList()方法,是调用的DiscoveryEnabledNIWSServerList
的getUpdatedServerList()
方法:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pgktXxfl-1657457021139)(FA1C87D12D404168A9AD5109B438F7B6)]
ILoadBlancer
主要就干两件事- 定时任务定时更新
eureka clent
根据服务名获取服务实例到ILoadBlancer
- 从
eureka clent
根据服务名获取服务实例到ILoadBlancer
- 定时任务定时更新
- 流程图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-50L657sl-1657457021139)(F002ED06B8484B21B7F6F710871C7638)]
-
Ping
机制 -
ribbon Ping机制 检查服务器是否存活
-
Ping机制的源码,原生的ribbon Ping机制是通过
DummyPing
类实现的,但是DummyPing
里面什么逻辑的都没,默认下是不生效的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fem8yldJ-1657457021140)(2E60B41739634C0397EE99E03B9DFF27)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vjxzdo89-1657457021140)(A63F27629CD1425B851FE23F0EE38B5D)] -
判断服务是否存活应该是eureka的事情erueka自己会有故障发现和服务实例摘除的机制,如果某个服务实例挂了,eureka server会发现,然后摘除这个服务实例,然后所有的eureka client都会得到一个通知,eureka client本地的ribbon,不是有一个PollingServerListUpdater组件,每隔30秒去从自己本地的eureka client去拉取注册表
-
ribbon通过与eureka的整合,自动就有一套服务实例故障自动摘除的机制,源码在
EurekaRibbonClientConfiguration
类中
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CCn3FNEB-1657457021141)(7DF3C651E930405583E1FD0677B0EE17)] -
通过
NIWSDiscoveryPing
类实现Ping机制,isAlive()
方法判断服务是否存活,主要判断服务实例是不是UP状态
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Nyu1LTSm-1657457021141)(3BCC309F9034423DBE574F41C88B254E)] -
在构建
ILoadBalancer
中,ZoneAwareLoadBalancer
的父类BaseLoadBalancer initWithConfig()
有个定时任务,每隔一段时间(默认30s)就会执行用IPing组件对每个server都执行一下isAlive()方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rKXGBTkZ-1657457021142)(1C763E0A09614B658BB4B43B9219C5D6)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hKepkXd7-1657457021143)(D5EBF9177F09452A8CB6F7F0AAD96BAF)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tMq1L9Ea-1657457021143)(E195CB5661A044768D260F5AFAD6FF9C)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yO7o0Hr5-1657457021144)(A468F27B7934464C8D8ABC224771189C)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yejdsq4C-1657457021144)(0E9FADEC45A7445491CC0875F865592A)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mozrZ3rx-1657457021145)(C06A2035FF104A7787A1E8E4A8DB559A)]