Eureka核心源码解析(三)- 服务发现、集群信息同步篇
在前面的两篇文章中,我们介绍了Eureka的服务的注册与续约 和 服务剔除与下线,本文我们再来看一看最后两个模块,服务发现和集群信息同步。
服务发现
Eureka-client
在学习服务发现的源码前,先写一个测试用例:
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/find")
public void test(String id){
List<ServiceInstance> instances = discoveryClient.getInstances(id);
System.out.println(instances);
}
调用DiscoveryClient
的getInstances
方法,可以根据服务id获取服务实例列表:
那么这里就有一个问题了,我们还没有去调用微服务,那么服务列表是什么时候被拉取或缓存到本地的服务列表的呢?答案是在这里调用了CompositeDiscoveryClient
的 getInstances()
方法:
中间调用过程省略:
EurekaDiscoveryClient # getInstances() ->
DiscoveryClient # getInstancesByVipAddress() ->
# getInstancesByVipAddress() -> //和上面不是一个方法
Applications # getInstancesByVirtualHostName()
查看Applications
中的getInstancesByVirtualHostName
方法:
发现一个名为virtualHostNameAppMap
的Map集合中已经保存了当前所有注册到eureka的服务列表。
private final Map<String, VipIndexSupport> virtualHostNameAppMap;
也就是说,在我们没有手动去调用服务的时候,该集合里面已经有值了,说明在Eureka-server项目启动后,会自动去拉取服务,并将拉取的服务缓存起来。
那么追根溯源,来查找一下服务的发现究竟是什么时候完成的。回到DiscoveryClient
这个类,在它的构造方法中定义了任务调度线程池cacheRefreshExecutor
,定义完成后,调用initScheduledTask
方法:
在这个thread中,调用了refreshRegistry()
方法:
在fetchRegistry
方法中,执行真正的服务列表拉取:
在fetchRegistry
方法中,先判断是进行增量拉取还是全量拉取:
1、全量拉取
当缓存为null
,或里面的数据为空,或强制时,进行全量拉取,执行getAndStoreFullRegistry
方法:
2、增量拉取
只拉取修改的,执行getAndUpdateDelta
方法:
①②:先发送http请求,获取在eureka-server中修改或新增的集合
③:判断,若拉取的集合为null,则进行全量拉取
④:更新操作,在updateDelta
方法中,根据类型进行更改
⑤:获取一致性的hashcode值,用来校验eureka-server集合和本地是否一样
在这进行判断,若远程集合的hash值等于缓存中的hash值,不需要拉取,否则再进行拉取一次。
最后提一下,Applications
中定义的以下这些变量,都是在eureka-server中准备好的,直接拉取就可以了。
private final AbstractQueue<Application> applications;
private final Map<String, Application> appNameApplicationMap;
private final Map<String, VipIndexSupport> virtualHostNameAppMap;
private final Map<String, VipIndexSupport> secureVirtualHostNameAppMap;
对服务发现过程进行一下重点总结:
- 服务列表的拉取并不是在服务调用的时候才拉取,而是在项目启动的时候就有定时任务去拉取了,这点在
DiscoveryClient
的构造方法中能够体现; - 服务的实例并不是实时的Eureka-server中的数据,而是一个本地缓存的数据;
- 缓存更新根据实际需求分为全量拉取与增量拉取。
集群信息同步
Eureka-server
集群信息同步发生在Eureka-server之间,之前提到在PeerAwareInstanceRegistryImpl
类中,在执行register
方法注册微服务实例完成后,执行了集群信息同步方法replicateToPeers
,具体分析一下该方法:
首先,遍历集群节点,用以给各个集群信息节点进行信息同步。
然后,调用replicateInstanceActionsToPeers
方法,在该方法中根据具体的操作类型Action,选择分支,最终调用PeerEurekaNode
的register
方法:
最终发送http请求,但是与普通注册操作不同的时,这时将集群同步的标识置为true,说明注册信息是来自集群同步。
在注册过程中运行到addInstance
方法时,单独注册时isReplication
的值为false,集群同步时为true。通过该值,能够避免集群间出现死循环,进行循环同步的问题。
最后
觉得对您有所帮助,小伙伴们可以点个赞啊,非常感谢~
公众号『码农参上』,一个热爱分享的公众号,有趣、深入、直接,与你聊聊技术。欢迎来加我好友 DrHydra9,围观朋友圈,做个点赞之交。
- 点赞
- 收藏
- 关注作者
评论(0)