Eureka核心源码解析(三)- 服务发现、集群信息同步篇

举报
码农参上 发表于 2022/04/27 09:08:07 2022/04/27
【摘要】 在前面的两篇文章中,我们介绍了Eureka的服务的注册与续约 和 服务剔除与下线,本文我们再来看一看最后两个模块,服务发现和集群信息同步。 服务发现 Eureka-client在学习服务发现的源码前,先写一个测试用例:@Autowiredprivate DiscoveryClient discoveryClient;@GetMapping("/find")public void test(S...

在前面的两篇文章中,我们介绍了Eureka的服务的注册与续约 和 服务剔除与下线,本文我们再来看一看最后两个模块,服务发现和集群信息同步。

服务发现

Eureka-client

在学习服务发现的源码前,先写一个测试用例:

@Autowired
private DiscoveryClient discoveryClient;

@GetMapping("/find")
public void test(String id){
    List<ServiceInstance> instances = discoveryClient.getInstances(id);
    System.out.println(instances);
}

调用DiscoveryClientgetInstances方法,可以根据服务id获取服务实例列表:

那么这里就有一个问题了,我们还没有去调用微服务,那么服务列表是什么时候被拉取或缓存到本地的服务列表的呢?答案是在这里调用了CompositeDiscoveryClientgetInstances()方法:

中间调用过程省略:

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,选择分支,最终调用PeerEurekaNoderegister方法:

最终发送http请求,但是与普通注册操作不同的时,这时将集群同步的标识置为true,说明注册信息是来自集群同步。

在注册过程中运行到addInstance方法时,单独注册时isReplication的值为false,集群同步时为true。通过该值,能够避免集群间出现死循环,进行循环同步的问题。

最后

觉得对您有所帮助,小伙伴们可以点个赞啊,非常感谢~
公众号『码农参上』,一个热爱分享的公众号,有趣、深入、直接,与你聊聊技术。欢迎来加我好友 DrHydra9,围观朋友圈,做个点赞之交。

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。