一、背景

在分布式系统中,zookeeper可以作为服务注册中心,所有提供服务的节点都可以在zookeeper上面注册,并作为一个node被组织起来,如下图:

android 心跳包发送 心跳包抓包_zookeeper


在RPC框架中,这些服务提供者就是RPC服务的提供者。zookeeper注册中心为每个服务都维持了会话session。为了监测这些服务是否在线,还使用了心跳机制。

对于zookeeper来说,这些RPC服务的提供者就是zookeeper客户端。

网上很多人说zookeeper的配置文件里的第一个参数ticktime就是指的心跳间隔,如下图,ticktime = 2000,即2000毫秒。但实际上,通过tcpdump抓包分析和源码阅读,可以看到其实并不是这样的。

android 心跳包发送 心跳包抓包_RPC_02

二、抓包

zk的服务端和客户端之间是用ping消息来作为心跳消息的。ping是应用层协议,下层直接就是网络层协议ICMP,(ICMP利用的是IP协议传输消息,很有趣,网络层依赖网络层),没有使用TCP或UDP,也就是说,ZK客户端和服务器即使在TCP三次握手或挥手过程出现了问题,也不影响心跳消息的收发

在RPC项目中,RPC服务提供者就是zk的客户端,所以我们首先运行RPC服务提供者程序。
然后ifconfig查看网络配置,因为都在本地运行,所以ip地址为回环地址127.0.0.1,网卡名为lo。
然后使用linux提供的抓包工具tcpdump,运行sudo tcpdump -i lo port 2181
(-i后接参数,lo是本地网卡名;port后的2181是zk服务器的端口号)

抓包结果如下:

android 心跳包发送 心跳包抓包_RPC_03


可以看到,ping消息的时间是14:31:19、14:31:29、14:31:39、14:31:49、14:31:59、

也就是间隔10秒发送一次ping消息。

而我们在zookeeper客户端程序初始化zookeeper句柄时,调用函数zookeeper_init()传入的会话超时时间参数是30000,即30秒(这个也是zk默认的会话超时时间),也就是说,zk发送心跳消息的默认时间间隔是默认会话超时时间的1/3,即10000ms

其实查看zk的客户端发送ping请求的源码class SendThread也能找到发送ping的时间间隔,部分代码如下:

class SendThread extends ZooKeeperThread{
......
public void run(){
	......
	final int MAX_SEND_PING_INTERVAL = 10000;
	......
	}
}

对于前面说的配置文件里的ticktime,是这样解释的:
Client端的ping心跳检测间隔时间是轮询隔一段时间后向Server端发送ping请求,而Server端的tickTime间隔时间作用是每隔一段时间就判断在Server端的Client连接对象是否已经死亡,如果已经过期死亡则将连接对象进行清除关闭。所以ping心跳检测的意义是Client端告诉服务器我还活着,tickTime意义是定期清除没有告诉Server端还存活的连接。