8 张图 | 剖析 Eureka 的首次同步注册表
初次见面,能否把你的「注册表」都给我?
大家好,我是悟空。
Eureka 注册中心系列文章汇总:
一、前言
注册表对于注册中心尤为重要,所有的功能都是围绕这个注册表展开。比如服务 A 要想访问服务 B,就得知道服务 B 的 IP 地址和端口号吧。如下图所示,传统的方式就是服务 A 知道了服务 B 的地址后,发送 HTTP 请求到对应的 API 地址上。
那服务 A 和 服务 B 的信息其实就是放在注册中心的注册表里面的,由注册中心统一管理所有服务的注册、下线。服务 A 和 服务 B 想要获取注册信息,统一访问注册中心,拿到注册表,就知道其他服务的 IP 地址 和端口号了。
上一讲,我们讲到一个 Eureka Client 成功注册到 Eureka Server 后,Eureka Server 就会把注册表信息存到一个 ConcurrentHashMap 中。
那 Client 怎么获取其他客户注册信息呢?
二、首次获取注册信息
首先我们想一下,服务 B 发送注册请求到注册中心了,那服务 A 就得获取注册表了吧,服务 A 本地一开始肯定是没有注册表信息的,那肯定就得到注册中心把注册表全部拉取一遍了。(这里服务 A 也称作 Eureka 客户端)
服务 A 对于注册中心来说,就是
初次见面
,服务 A 想把所有
注册信息都在自己本地存一份,方便后续的 API 调用。
接下来我们从源码角度分析下客户端怎么获取全量注册表的吧。
客户端发送获取的请求
Client 初始化的时候,就会从 Eureka 注册中心获取全量的注册表:
首次获取注册信息就是用在 DiscoveryClient 初始化的时候获取的。我们可以从源码中找到如下判断:
if (clientConfig.shouldFetchRegistry() && !fetchRegistry(false)) { fetchRegistryFromBackup(); }
这段代码的意思如图所示:
就是先根据是否配置了 shouldFetchRegistry,如果配置了,则会调用 fetchRegistry 方法获取注册表。
因为是新的 client,所以肯定是没有注册信息的,所以本地的变量 applications = null。然后根据几个条件来判断是否需要全量获取注册表,满足其中一个条件就会全量获取:
- 条件一:是否强制全量获取。传的 false,不需要全量。
- 条件二:注册表信息是否为空。application == null,为空,需要全量获取。
- 条件三:获取已注册的 client 的个数是否等于 0。是的,需要全量获取。
因为满足 applications=null,所以需要全量获取。
获取全量注册信息的方法:
getAndStoreFullRegistry()
在这个里面就会发送下面这个 HTTP 请求调用 jersey 的 restful 接口:
getApplications()
然后 Eureka Server 处理这个 http 的请求的类是在这里:ApplicationsResource 类的 getContainers 方法。这个方法里面就会去拿 Server 那边注册表了。
三、Server 端的注册表缓存
Server 端会把注册表放到缓存里面,读取注册表其实是从缓存里面读取出来的。
分为两级缓存,只读缓存 readOnlyCacheMap
和读写缓存 readOnlyCacheMap
。
如下图所示:
缓存的读取逻辑如下:
-
Jersey Servlet 处理 HTTP 请求。
-
首先默认会先从只读缓存里面找。
-
没有的话,再从读写缓存里面找。
-
找到了的话就更新只读缓存,并返回找到的缓存。
-
还找不到的话,就返回空。
留几个问题,放到缓存架构那篇再讲:
(1)两级缓存数据怎么来的?
(2)缓存数据如何更新的?
(3)缓存如何过期?
然后,Eureka Client 获取注册表信息后,就会存到本地 localRegionApps 变量中。这样 Client 就会有一份 Server 的注册表信息了。
localRegionApps.set(this.filterAndShuffle(apps));
四、总结
注册表无论是对于 Client 还是 Server 来说,都非常重要:
- 对于 Server 端来说,为了更好的提供查询注册表的服务,使用了多级缓存来缓存注册表信息。
- 对于 Client 端来说,首次获取注册表时就会全量抓取注册表,存在自己本地。
后续:第二次见面,怎么获取注册表呢?
作者简介:悟空,8年一线互联网开发和架构经验,用故事讲解分布式、架构设计、Java 核心技术。《JVM性能优化实战》专栏作者,开源了《Spring Cloud 实战 PassJava》项目,公众号:悟空聊架构
。本文已收录至 www.passjava.cn
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
微服务架构 | 如何利用好日志链路追踪做性能分析?
导读:做性能分析听到最多的歪理就是,服务做水平、垂直扩容、分表分库、读写分离、XX中间件、资源静态化等等但是归根到底这些方案都是为了尽可能减少对数据库的访问以及堆栈的释放,提高数据库IO的读写速度和程序的运行效率。 系统都是逐渐演进的,一个系统在运行中必须是根据场景逐渐地提高优化性能。高并发就是对资源的节约的考验,这种考验除了更换优秀和先进的技术,优化架构,还在于从小处出发,对尽可能节约的资源进行节约。 而在一个系统的数据访问中,系统的瓶颈往往是来自于数据库,因此我们要尽可能减少对数据库的访问! 一、背景 最近一段时间粉丝可能留意到,技术号一直没有更新多少技术文章。因为近期都在做一直在做性能优化。 在业务模块在并发量起来以后,接口的性能瓶颈就愈发变得明显。 本篇主要针对配置布局资源文件过大,导致接口耗时过长问题分析解决。 二、日志链路追踪 排查性能如果从代码层面出发少不了堆栈分析,但是目前大部分服务都为了便于服务扩容、升级都做了微服务处理,日志分析排查免不了通过链路ID追踪日志《微服务分布式架构中,如何实现日志链路跟踪?》 ▐ 链路追踪日志改造 - RPC接口 在《链路日志追踪》中提到...
- 下一篇
dart系列之:浏览器中的舞者,用dart发送HTTP请求
简介 dart:html包为dart提供了构建浏览器客户端的一些必须的组件,之前我们提到了HTML和DOM的操作,除了这些之外,我们在浏览器端另一个常用的操作就是使用XMLHttpRequest去做异步HTTP资源的请求,也就是AJAX请求。 dart同样提供了类似JS中XMLHttpRequest的封装,其对应的类叫做HttpRequest,一起来看看在dart中怎么使用HttpRequest吧。 发送GET请求 虽然现代的web APP被各种框架所封装,但是归根结底他还是一个AJAX的富客户端应用。我们通过各种异步的HTTP请求向服务器端请求数据,然后展示在页面上。一般来说数据的交互格式是JSON,当然也可以有其他的数据交互格式。 AJAX中最常用的方式就是向服务器端发送get请求,对应的HttpRequest有一个getString方法: static Future<String> getString(String url, {bool? withCredentials, void onProgress(ProgressEvent e)?}) { return r...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker安装Oracle12C,快速搭建Oracle学习环境
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- CentOS8安装Docker,最新的服务器搭配容器使用
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- CentOS关闭SELinux安全模块
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS7设置SWAP分区,小内存服务器的救世主