Eureka源码(五)— 心跳、服务下线、实例摘除、故障感知
2022-05-10 10:18:20 1 举报
Eureka源码的第五部分主要涉及心跳、服务下线、实例摘除和故障感知。心跳是服务端定期接收客户端的心跳以确认其是否在线;服务下线则是客户端主动通知服务端其已停止提供服务;实例摘除是在服务端发现某个实例长时间没有发送心跳时,将其从注册表中移除;故障感知是通过健康检查机制,当某个服务出现故障时,Eureka能够自动将其从服务列表中剔除。这四个功能共同保证了Eureka服务的高可用性和稳定性。
作者其他创作
大纲/内容
结束
自动检查服务实例是否故障宕机
internalCancel()
每隔30s的定时任务调用增量获取注册表接口
一、numberOfRenewsPerMinThreshold(期望一分钟要有多少次心跳) 是如何初始化和计算的?
将线程池都给shutdown掉,释放资源,停止运行的线程
EurekaBootStrap初始化 --> contextInitialized() --> initEurekaServerContext();--> 上下文初始化serverContext.initialize() --> registry.init(peerEurekaNodes);--> scheduleRenewalThresholdUpdateTask() 启动定时调度的任务
renewLease()
如果上一分钟实际的心跳次数,比期望的一分钟的心跳次数要小,触发自我保护机制,不允许摘除任何服务实例,此时认为eureka server出现网络故障,大量的服务实例无法发送心跳过来
服务实例变更过了,必须将之前的缓存都清理掉,从readWriteCacheMap中清理掉
自我保护机制的逻辑与自动故障感知的逻辑代码在一起evict()方法内部,先会判断上一分钟的心跳次数,是否小于期望的一分钟的心跳次数,如果小于,那么就不让清理任何服务实例
五、自我保护机制的触发
通过注册表的renew()方法,进去完成服务续约实际进入AbstractInstanceRegistry的renew()方法
三、定时更新
expectedNumberOfClientsSendingRenews:预期每分钟收到续约的客户端数量,取决于注册到eureka server上的服务数量
通过注册表的cancel()方法实际进入AbstractInstanceRegistry的cancel()方法
evict()
在摘除的时候,是从故障实例中随机挑选本次可以摘除的数量的服务实例,来摘除,随机摘取机制摘除服务实例的时候,其实就是调用下线的方法,internelCancel()方法(具体参考服务下线中的internelCancel()逻辑)
关闭网络通信组件eurekaTransport.shutdown();
注册的时候,预期每分钟收到续约的客户端数量 + 1
将服务实例信息扔掉最近改变的队列中
初始化调度任务
详细逻辑
DiscoveryClient初始化
自动故障感知
每隔30秒去发送一次心跳,每隔30秒执行一次HeartbeatTHread线程的逻辑,发送心跳
四、getNumOfRenewsInLastMin()(实际的上一分钟的心跳次数) 是如何计算的?
MeasuredRate 是如何计算每一分钟内的一个内存中的计数的呢?计算每一分钟内的心跳的次数?代码如下
expectedNumberOfClientsSendingRenews = 服务实例数量
client端
registry.renew()
cancelScheduledTasks()
applicationInfoManager.setInstanceStatus(InstanceStatus.DOWN);
从内存的map数据结构的注册表中将这个服务实例移除
心跳机制(服务续约)
随机摘取机制
发送心跳
若eureka server自己的机器所在的网络故障了,导致那些client服务的心跳发送不过来。就导致eureka server本地一直没有更新心跳。那么eureka server就进入一个自我保护的机制,从此之后就不会再摘除任何服务实例了
unregister();
总结:(1)在注册中心,将服务实例从注册表中移除,下线的服务放入recentChangedQueue中去(2)每个服务都会定时拉取增量注册表,此时可以从recentChangedQueue中感知到下线的服务实例,然后就可以在自己本地缓存中删除那个下线的服务实例服务的注册、下线、故障摘除,都会代表这个服务实例变化,都会将自己放入最近改变的队列中最近改变的队列,只会保留最近3分钟的服务实例所以eureka client拉取增量注册表的时候,其实就是拉取最近3分钟有变化的服务实例的注册表
二、注册、下线、故障对每分钟期望的心跳的次数的影响
server端
每隔30秒执行一次定时的任务将readWriteCacheMap和readOnlyCacheMap进行一个同步
isLeaseExpirationEnabled()
取消注册,调用EurekaHttpClient的cancel()方法http://localhost:8080/v2/apps/ServiceA/i-00000-1,delete请求
每次心跳的时候,就会加一记录
getExpectedClientRenewalIntervalSeconds():多久续订一次,通过expected-client-renewal-interval-seconds配置,默认30秒。
每分钟期望的心跳的次数,跟服务实例的数量相关的,服务实例随着上线、下线和故障,都在不断的变动着
eureka源码(四)— 注册表抓取、多级缓存
调用PeerAwareInstanceRegistryImpl的父类AbstractInstanceRegistry的postInit方法
leaseToCancel.cancel()
若eureka client要停机,要在代码里自己调用DiscoveryClient的shutdown()方法,就会发送请求到eureka server去下线一个服务实例但是有些时候,服务自己宕机了,就不会调用shutdown()方法,也不会去发送请求下线服务实例eureka有一个自动故障感知机制,以及服务实例摘除机制eureka靠心跳来感知,可能某个服务已经挂掉了,就不会再发送心跳了,如果在一段时间内没有接收到某个服务的心跳,那么就将这个服务实例摘除,认为这个服务实例已经宕机了
判断上一分钟getNumOfRenewsInLastMin心跳次数是否小于等于服务实例数量(期望一分钟的心跳次数)
每隔60s会运行一次定时调度的后台线程任务,EvictionTask
有时候在eureka控制台看到上面日志信息其实是eureka-resources项目下的headser.jsp展示的,调用了registry类的isBelowRenewThresold方法
将服务实例的状态设置为DOWN
Eureka不会一次性将所有故障的服务实例都摘除,下次EvictionTask再次执行的时候,会再次摘除,分批摘取机制
new EvictionTask()
eureka server网络故障时的的自我保护机制
服务下线的时候,预期每分钟收到续约的客户端数量 - 1
开始
cancelLease()
注册
internelCancel()
下次所有的eureka client来拉取增量注册表的时候,都会发现readOnlyCacheMap里没有,会找readWriteCacheMap也会发现没有,然后就会从注册表里抓取增量注册表,此时就会将上面的recentChangedQueue中的记录返回
在了解eureka server网络故障时的的自我保护机制最开始有提到这个方法参数
从注册表的map中,根据服务名和实例id,获取一个Lease<InstanceInfo>
核心取消代码,调用Lease的cancel方法里面保存了一个evictionTimestamp,就是服务实例被清理掉,服务实例下线的时间戳
ApplicationsResource --> ApplicationResource --> InstanceResource通过DELETE请求,可以找到cancelLease方法
让所有的eureka client下一次拉取增量注册表的时候,可以拉取到这个服务实例下线的这么一个变化
将监听器关掉heartbeatStalenessMonitor.shutdown();registryStalenessMonitor.shutdown();
initScheduledTasks()
故障
最近改变的队列ConcurrentLinkedQueue<RecentlyChangedItem> recentlyChangedQueue
new HeartbeatThread()
看源码可知:若服务实例上次心跳时间到现在为止超过了90*2=180s,才会认为这个服务实例过期了但是官方文档写的是超过90s就会认为这个服务实例过期,这是一个bug,但是根据注释,官方目前并不会修复这个问题
DiscoveryClient中的shutdown()方法
super.postInit();
服务剔除
getRenewalPercentThreshold():自我保护阀值,续订数低于期望比例时,开启自我保护机制。自我保护续约百分比阈值因子,默认0.85。 也就是说每分钟的续约数量要大于85%
分批摘取机制
EurekaBootStrap初始化
在Lease对象中,更新lastUpdateTimestamp时间戳
EurekaBootStrap初始化 时会初始化 PeerAwareInstanceRegistryImpl初始化PeerAwareInstanceRegistryImpl时会初始化其父类AbstractInstanceRegistryAbstractInstanceRegistry初始化时,会初始化MeasuredRate renewsLastMin
故障的时候,摘除一个服务实例代码流程看上面的自动故障感知,最后在internalCancel中的最后有相关逻辑 实际的心跳次数比期望的心跳次数要小,就不会再摘除任何服务实例了
所以 自我保护阀值 = 服务总数 * 每分钟续约数(60S/客户端续约间隔) * 自我保护续约百分比阀值因子如:2个客户端实例,续订默认30秒一次,阀值默认0.85。numberOfRenewsPerMinThreshold = 2*(60/30)*0.85 =2*2*0.85=3.36=3
走的是EurekaHttpClient的sendHeartbeat()方法http://localhost:8080/v2/apps/ServiceA/i-000000-1put请求
负责承接服务实例的心跳相关的这些操作的,是ApplicationsResourceApplicationsResource --> ApplicationResource --> InstanceResource通过PUT请求,可以找到renewLease方法
服务下线
获取补偿时间
对每个服务实例的租约进行判断
默认15分钟执行一次定时任务算一下服务实例的数量,如果从其它eureka server拉取到的服务实例的数量,大于当前的服务实例的数量,会重新计算一下,主要是跟其他的eureka server做一下同步
registry.cancel()
MeasuredRate初始化的时候,会生成一个定时任务
停止服务实例时的服务下线以及实例摘除
0 条评论
回复 删除
下一页