一、背景
在分布式系統中,zookeeper可以作為服務注冊中心,所有提供服務的節點都可以在zookeeper上面注冊,并作為一個node被組織起來,如下圖:
在RPC架構中,這些服務提供者就是RPC服務的提供者。zookeeper注冊中心為每個服務都維持了會話session。為了監測這些服務是否線上,還使用了心跳機制。
對于zookeeper來說,這些RPC服務的提供者就是zookeeper用戶端。
網上很多人說zookeeper的配置檔案裡的第一個參數
ticktime
就是指的心跳間隔,如下圖,
ticktime = 2000
,即2000毫秒。但實際上,通過tcpdump抓包分析和源碼閱讀,可以看到其實并不是這樣的。
二、抓包
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伺服器的端口号)
抓包結果如下:
可以看到,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端還存活的連接配接。
本文參考以下部落格:
zookeeper心跳機制源碼分析
zookeeper簡介