1、背景
在一些只能进行间接交互的场景下,可以使用此方法实现连接的存活性检测。使用间接交互的方式而不是依赖配置下发通道的存活校验机制,可以减少对配置下发通道功能的依赖,只要通道支持基本的kv存储功能(例如redis、etcd、nacos)即可实现基于间接交互的心跳检测。
2、问题
在客户端与服务端间接交互的情况下,可以由客户端定时向公共服务写入心跳时间戳,让服务端感知到客户端仍然存活(无法通过接收客户端心跳请求的方式来实现,因为客户端无法直接向服务端发起请求,客户端发起心跳请求的时候服务端是无法感知的)。但是假如客户端和服务端之间的时间差过大,则会出现客户端注册上来的时间戳本来就是过期的,这时要进行时间校准。但是时间校准需要服务端提供时间校准API,服务端与客户端的网络又不能联通,这样无法进行时间校准。如果在这个场景下按照普通的NTP时间校准方式来进行时间校准,又会出现一个与心跳间隔相关的误差。当这个误差存在的时候,稍微出现的网络延时都可能引起节点存活性检测失败。
3、方案
本方案提出一种通过事先约定心跳间隔,然后使用改进的NTP时间校准公式,通过心跳间隔一致这个特性来实现时间的校准,完成心跳检测的方法。
- 普通心跳检测
普通的心跳检测由客户端定时向服务端写入请求,服务端只要检测2次请求的间隔小于超时时间,即可认为客户端存活。图1为普通心跳检测。
1.1、客户端创建定时任务,定时调用服务端的心跳检测API
1.2、服务端接受到心跳检测请求后,为该连接创建一个上下文,记录当前收到心跳检测请求的时间
1.3、服务端再次收到心跳检测请求时,将当前时间与上下文中上一次收到的心跳请求时间对比,差值超过预定的心跳时间间隔的2倍即可认为客户端失去连系,销毁连接
- 基于间接交互的心跳检测
在间接交互的情况下,无法通过接收客户端心跳请求的方式来实现,因为客户端无法直接向服务端发起请求,客户端发起心跳请求的时候服务端是无法感知的,所以也无法获得客户端提交心跳请求的时间。因此可以由客户端定时向公共服务写入心跳时间戳,服务端定时轮询并校验时间戳即可感知到客户端仍然存活。图2为基于间接交互的心跳检测。
2.1、客户端发起请求,添加客户端节点并写入时间戳如node.node-1,并等待服务端响应到指定的位置如status.node-1
2.2、服务端定时轮询客户端存储数据列表node.*,将心跳超时的节点移除,并为新加入的节点分配响应空间如status.node-1
2.3、节点收到响应后,注册成功,定时向node.node-1写入新的时间戳。
2.4、服务端重复步骤2.2。
- 基于间接交互的心跳检测的时间偏差问题
但是假如客户端和服务端之间的时间差过大,则会出现客户端注册上来的时间戳本来就是过期的。图3为基于间接交互的心跳检测的时间偏差问题。
但是时间校准需要服务端提供时间校准API,服务端与客户端的网络又不能联通,这样无法按NTP的方式进行时间校准。
- 基于间接交互的时间校准后的心跳检测
基于上述方案进行改进,可以通过事先约定心跳间隔,然后使用改进的NTP时间校准公式,通过心跳间隔一致这个特性来实现时间的校准,完成心跳检测的过程,解决时间校准的问题。图4为基于间接交互的时间校准后的心跳检测。