【Zookeeper讀書筆記-3】客戶端原理

1 基礎概念

ClientCnxn是網絡連接器,管理客戶端與服務端的網絡交互。

ClientWatchManager保存客戶端的watcher

HostProvider服務器地址列表管理器

outgoingQueue客戶端的請求發送隊列

pendingQueue客戶端的服務端響應等待隊列

SendThread管理客戶端與服務端的所有網絡IO

客戶端的SendThread通過一定頻率向服務端發送PING包實現心跳檢測,維護客戶端與服務端的會話生命週期;

會話週期內客戶端與服務端之間出現TCP連接斷開,會自動重連,這個過程是透明的;

 

SendThread管理客戶端所有的請求發送與響應接收;

SendThread將服務端事件傳遞給EventThread去處理;

EventThread處理客戶端的事件,觸發客戶端註冊的Watcher監聽。

2 客戶端初始化與啓動過程

  1. 設置默認watcher
  2. 設置Zookeeper服務器地址列表
  3. 創建ClientCnxn

創建Zookeeper構造方法中傳入watcher對象,則此watcher對象會被保存入defaultWatcher中,作爲客戶端會話期間默認的watcher。

2.1 會話創建的初始化階段

1 初始化Zookeeper對象,創建的客戶端Watcher管理器ClientWatcherManager

2 設置會話默認Watcher,創建Zookeeper對象是傳入的Watcher對象會被保存入ClientWatcherManager

3 構造Zookeeper服務器地址列表管理器HostProvider

4 創建並初始化客戶端網絡連接起ClientCnxn,管理客戶端與服務端的網絡交互;

    同時客戶端會初始化隊列outgoingQueue用於客戶端的請求發送隊列和pendingQueue用於服務端響應的等待隊列;

    同時客戶端還要創建ClientCnxnSocket,作爲底層IO處理器

5 初始化網絡線程SendThread管理客戶端與服務端的網絡連接,使用ClientCnxnSocket作爲底層IO處理器

   初始化網絡線程EventThread處理客戶端的事件,初始化待處理事件隊列waitingEvents,存放所有等待被客戶端處理的事件。

2.2 會話創建階段 

6 啓動SendThread,EventThread

   SendThread首先判斷客戶端的狀態,進行一些清理工作,爲客戶端發送”會話創建“請求做準備。

7 獲取一個服務器地址列表

   SendThread首先從HostProvider隨機獲取一個Zookeeper地址,交給ClientCnxnSocket去創建與Zookeeper服務器之間的TCP連接。

8 創建TCP連接

獲取到一個服務器地址,ClientCnxnSocket負責與服務器創建一個TCP長連接

9 構造connectRequest請求

SendThread負責構造ConnectRequest,該請求代表客戶端要與服務端連接創建會話。ZK客戶端還會將該請求包裝成網絡層的Packet對象,放入請求發送隊列outgoingQueue中。

10 發送請求

ClientCnxnSocket從outgoingQueue取出一個代發送的Packet對象,序列化成ByteBuffer對象向服務端發送

2.3 響應處理階段

11 接收服務端響應

ClientCnxnSocket接到服務端響應,首先判斷當前客戶端狀態是否是“已初始化”,如果未初始化就認爲此響應是會話創建請求的響應,直接由readConnectResult方法處理該響應。

12 處理Response

ClientCnxnSocket對服務端響應反序列化,得到ConnectResponse對象,並獲取ZK服務端分配的會話SessionId。

13 連接成功

連接成功後,同志SendThread線程進一步設置readTimeout,connectTimeout等參數,並更新客戶端狀態;

通知地址管理器HostProvider當前成功連接的服務器地址。

14 生成事件SyncConnected-None

SendThread會生成事件,目的是上層應用感知會話創建成功。代表客戶端與服務端的會話創建成功,並將該事件傳遞給EventThread線程。

15 獲取Watcher

EventThread收到事件後從ClientWatcherManager中獲取對應的watcher,針對SyncConnected-None直接找出步驟2中存儲的默認watcher,放入EventThread中的waitingEvents隊列中。

16 處理事件

EventThread從waitingEvents隊列中獲取待處理的watcher對象,調用該對象的process方法。

2.4 服務器地址列表

創建ZK客戶端時傳入的服務器地址列表時如何生效的?按照順序連接各個服務器還是隨機連接?

服務器地址列表解析器ConenctStringParser將傳入的地址列表解析成chrootPath,並且保存下服務器地址列表

- chroot指的是每個客戶端爲自己設置命名空間,之後該客戶端的操作都會限定在自己的命名空間內。例如“192.168.1.1:2181, 192.168.1.2:2181/apps/a”

- ConenctStringParser將IP以及port封裝到InetSocketAddress對象,以ArrayList形式保存入ConenctStringParser.serverAddresses屬性中,經過處理的地址列表會被進一步封裝到StaticHostProvider(提供服務器地址個數,地址列表,回調方法用於客戶端與服務端創建連接成功)。

StaticHostProvider實現了接口HostProvider

- 解析地址與端口,封裝成集合

- 調用Collections.shuffle將地址列表打散,組裝成環形循環隊列,使用過程中從這個隊列獲取地址信息

2.5 網絡IO

1 請求發送

outgoingQueue隊列中提取出一個可以發送的Packet對象,同時生成客戶端請求序號XID,並將其設置到Packet請求頭中,然後序列化併發送。

請求發送完畢,立即將Packet保存到pendingQueue中,等待服務端響應後進行相應處理。

2 響應接收

客戶端接到服務端響應後,根據客戶端請求類型不同,進行不同的處理。

客戶端還未初始化,說明客戶端與服務端正在創建會話,直接將接到的ByteBuffer(incomingBuffer)序列化成ConnectResponse對象。

客戶端處於正常的會話週期,並且接到的服務端響應是一個事件,客戶端將接到的ByteBuffer(incomingBuffer)序列化成WatcherEvent對象,並將該對象放入待處理隊列。

如果是一個常規請求(Create,GetData,Exists等操作),從pendingQueue隊列中取出一個Packet對象進行處理。客戶端檢查服務端響應中包含的XID確保請求處理順序,然後將接到的ByteBuffer(incomingBuffer)序列化成Response對象。

finishPacket方法中處理Watcher註冊等邏輯。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章