本文已参与「新人创作礼」活动,一起开启掘金创作之路。
Netflix Eureka 目录汇总
-
eureka server启动以及初始化
-
eureka client启动以及初始化
-
服务注册
3.1 可重入读写锁-读锁
-
服务发现
4.1. 全量抓取注册表
4.2. 注册表多级缓存机制
4.3. 注册表多级缓存过期机制(主动、定时、被动)
4.4. 增量抓取注册表
4.4.1. 一致性Hash对比机制 4.4.2. 可重入读写锁-写锁 -
服务续约
-
服务下线
-
服务故障自动感知及服务实例自动摘除
-
自我保护机制
Netflix Eureka 时间间隔简要
服务注册-
服务发现-
读写缓存-定时过期(180秒)
只读缓存-被动过期(30秒(整30秒))
定时抓取增量注册表(30秒)
定时删除超过3分钟的服务实例变更记录(30秒)
服务续约(30秒)
服务下线
服务故障自动感知及服务实例自动摘除(感知:90秒(BUG:90 * 2秒);摘除:60秒)
自我保护机制
每分钟期望的续约次数 & 每分钟期望的续约次数阈值(15分钟)
MeasuredRate renewsLastMin(60秒)
自我保护机制
假如说,20个服务实例,结果在1分钟之内,只有8个服务实例保持了心跳 --> eureka server是应该将剩余的12个没有心跳的服务实例都摘除吗?
这个时候很可能说的是,eureka server自己网络故障了,那些服务没问题的。只不过eureka server自己的机器所在的网络故障了,导致那些服务的心跳发送不过来。就导致eureka server本地一直没有更新心跳。
针对这种情况eureka server自己进入一个自我保护的机制,从此之后就不会再摘除任何服务实例了
注册表的evict()方法,EvictionTask,定时调度的任务,60s来一次,会判断一下服务实例是否故障了,如果故障了,一直没有心跳,就会将服务实例给摘除。
-
evict()方法内部,先会判断上一分钟的心跳次数,是否小于期望的一分钟的心跳次数,如果小于,那么压根儿就不让清理任何服务实例
-
期望的一分钟的心跳次数是怎么算出来的?
(1)eureka server启动的时候初始化
registry.openForTraffic(applicationInfoManager, registryCount);
完成了numberOfRenewsPerMinThreshold这个值,期望一分钟得有多少次心跳的值,初始化。刚开始会调用syncUp()的方法,从相邻的eureka server节点,拷贝过来注册表,如果是自己本地还没注册的服务实例,就在自己本地注册一下。
会记录一下从别的eureka server拉取过来的服务实例的数量,将这个服务实例的数量,就作为自己eureka server本地初始化的这么一个服务实例的数量。将服务实例数量 * 2。
期望心跳次数的计算硬编码BUG,后续版本通过updateRenewsPerMinThreshold()方法已修复。
用这个服务实例 * 2 * 0.85 = 20 * 2 * 0.85 = 34,期望的是最少一分钟20个服务实例,得有34个心跳。根据当前的服务实例的数量,计算出来的一分钟最少需要的心跳次数。服务实例个数 * (60 / 心跳时间间隔) * 0.85 = 每分钟最少的心跳次数。
(2)注册、下线、故障
每分钟期望的心跳的次数,是跟服务实例的数量相关的,服务实例随着上线和下线(故障情况在之后版本修复的),都在不断的变动着。注册的时候,每分钟期望心跳次数 + 2。服务下线的时候,直接每分钟期望心跳次数 - 2。
故障的时候,摘除一个服务实例,没有直接更新期望心跳次数。使用15分钟一次的定时任务updateRenewalThreshold()更新expectedNumberOfRenewsPerMin和numberOfRenewsPerMinThreshold。
实际的心跳次数比期望的心跳次数要小,会假定是eureka server网络问题,而不是eureka client服务实例的问题,不会再摘除任何服务实例。
(3)定时更新
Registry注册表,默认是15分钟,会跑一次定时任务,算一下服务实例的数量,如果本地缓存的applications服务实例的数量,大于当前的服务实例的期望的数量时,会重新计算一下。(只有当阈值大于当前预期阈值 或者 自我保护未开启,才更新阈值。)
- 实际的上一分钟的心跳次数是怎么算出来的
每次一个心跳过来,调用MeasuredRate.increment()方法增加心跳记录次数。
内部的三个属性:
lastBucket:用来保存上一个完整周期统计的心跳记录次数;
currentBucket:用来记录当前未完成周期的心痛记录统计次数;
timer定时器:用来每隔60秒将currentBucket属性统计的心跳记录统计次数复制给lastBucket,并将currentBucket赋值为0,开始新的每分钟心跳记录次数统计周期。
- 自我保护机制的触发
如果上一分钟实际的心跳次数,比我们期望的一分钟的心跳次数要小,触发自我保护机制,不允许摘除任何服务实例,此时认为自己的eureka server出现网络故障,大量的服务实例无法发送心跳过来
- 关于15分钟内心跳次数小于85%阈值才开启自我保护机制的争议。
服务注册、服务下线会直接触发【续约阈值】的更新,故障感知剔除不会直接出发【续约阈值】的更新,需要配合15分钟一次的【续约阈值更新】任务的调度才会更新【续约阈值】