心跳机制
目录
TIP
临时实例:实例发起心跳请求,服务端处理请求,并需要进行心跳检测
永久实例:服务端主动发起健康检测
临时实例
客户端
临时实例在注册的时候会开启心跳包,这个在前面有说(默认5s心跳)
1.开启入口
NacosNamingService.registerInstance():
buildBeatInfo就是心跳信息的封装,我们主要看addBeatInfo方法
2.心跳开启
BeatReactor.addBeatInfo():
把心跳任务BeatTask丢到了延迟线程池里面执行,所以主要执行逻辑在BeatTask中
3.心跳执行逻辑
BeatTask.run()
1.发送HTTP心跳请求 URL地址为:/nacos/v1/ns/instance/beat
2.如果当前实例在注册中心未找到就重新注册
3.不管结果如何添加心跳任务,继续定时发起心跳(继续将任务丢到线程池里面执行)
心跳请求如下,URL地址为:/nacos/v1/ns/instance/beat
服务端
1.心跳请求的处理
从上面请求URL:/nacos/v1/ns/instance/beat ,我们很容易能找到处理请求逻辑:
InstanceControllerregister.beat()
我这里省略了前面的校验逻辑,直接看主体逻辑:
1.从注册表中获取实例信息,若无则重新注册
2.从注册表中获取服务,若无则直接异常(实例都注册完了,服务还找不到是不合理的)
3.开启异步任务将临时实例状态 置为健康状态,然后返回
2.心跳检测处理
实例如果宕机或者其他什么请求无法发送心跳,那么服务端自然也要对这个实例进行处理,就在服务初始化的时候,会开启会实例的心跳检测任务,上面也有提到过
ServiceManager.putServiceAndInit()
Service.init()
这个内部呢,就会有个ClientBeatCheckTask任务被放入了线程池,5s执行一次
ClientBeatCheckTask.run()
而ClientBeatCheckTask任务主要做了两件事:
- 找到心跳超时的实例,改变其健康状态,并发布serviceChange事件(后面说),还有实例心跳超时事件
- 找到满足删除条件的实例,从注册表中删除该实例信息(HTTP请求调用API,异步删除)
- 默认15s超时,30s剔除
永久实例
1.入口
入口和上面临时实例入口差不多,但永久实例是在集群初始化的时候,而临时实例是在服务初始化的时候
Cluster.init如下: 1.检测任务就是HealthCheckTask,这是个异步任务 2.延迟任务第一次(2000ms+5000ms以内随机数)执行,后续在1000ms-5000ms内浮动
HealthCheckTask任务如下:
- process方法有多种实现意味着有多种检测方案(这里以TCP为例)
- 不管结果如何继续延迟执行,约等于是个定时器(因为每次延迟时间不同)
- HealthCheckTask实例化的时候同时初始化了TcpSuperSenseProcessor,该方法是一个Runnable,会执行TcpSuperSenseProcessor.run方法(以TCP为例)
2.获取所有永久实例加入阻塞队列
TcpSuperSenseProcessor .process()
这里会遍历所有永久实例并将实例封装成Beat加入到阻塞队列中
3.从队列中获取实例并封装
上面把永久实例信息放到了阻塞队列中,那么就肯定有方法去取,那是哪里呢?还记得前面说过TcpSuperSenseProcessor本身也是个异步任务吗?
TcpSuperSenseProcessor.run方法如下:
- 会先从阻塞队列中取出实例信息并封装,然后尝试与实例建立socket连接
- 最后判断连接状态,连接上了就进去实例健康处理并断开连接
- 同时会有一个异步的延迟任务,去检测这段时间内是否连接上过,这段时间内没连接上过说明连接超时了
- 可以看到这个run方法是个死循环
TcpSuperSenseProcessor.processTask方法如下:
- 从阻塞队列中取实例信息,并封装成TaskProcessor异步任务
- 批量提交任务,就是执行TaskProcessor异步任务
4.与实例尝试建立连接
TaskProcessor.run()
- 主要就是尝试建立socket连接
- 开启一个超时检测的延迟任务TimeOutTask(500ms)
5.超时判断
TimeOutTask.run()
因为已经延迟执行了,就判断这段时间内是否连接上过,没有就代表超时,超时会进入finishCheck方法
6.正常处理
前面都执行完了,就到TcpSuperSenseProcessor.run里面最后的PostProcessor异步任务了,连接成功会进入finishCheck方法
PostProcessor.run()
7.最终判断
Beat.finishCheck
连接成功或超时连接都会进到这里处理,不管如何都会发布服务变更事件,只会改变实例状态不会剔除实例
总结
- 临时实例:
- 采用客户端心跳检测模式,心跳检测周期5秒
- 心跳间隔超过15秒(默认)则标记为不健康
- 心跳间隔超过30秒(默认)则从服务列表删除
- 永久实例:
- 采用服务端主动健康检测方式
- 周期为2000 + 5000毫秒内的随机数
- 检测异常只会标记为不健康,不会删除