近期一直在忙WebPageTest(下面簡稱wpt)開源庫的改動工做,當中一項工做需要將zookeeper(下面簡稱zk)集成到wpt裏。apache
zk做爲分佈式系統的同步工具。實現了寫的原子性(要麼失敗。要麼成功,並不存在寫一半的狀況),並經過「選舉組長「和」重選組長「,在負載均衡的同一時候保證數據一致性。關於zk服務端的設計,可以參考官網http://zookeeper.apache.org/。網絡
本文闡述zkclient的實現,一來可以梳理下思路,二來也可做爲閱讀筆記。負載均衡
zkclient代碼比較少。全然採用C語言來實現。包含:異步
一、hashtable的實現socket
hashtable的實現。包含hashtable.h。hashtable.c,hashtable_itr.h和hashtable_itr.c。從代碼中可以看到,hashtable的方式基本是依照JAVA中的hash表實現的。進一步講,hash表的內部實現事實上很是easy,如圖所看到的:分佈式
hashtable內部保存了多個鏈表(數量可變。噹噹前節點數超過指定負載時添加)。元素插入。改動,刪除時都以hash key爲惟一主鍵,換言之最重要的就是保證hash key的惟一性。元素插入時,hashtable依據key計算出index。並依據index選擇將元素插入第幾個鏈表。比方:假設key計算出index爲1,那麼元素就被插入到list2中;假設當前負載超過最大額度。hashtable本身主動擴展鏈表數並對各個鏈表中的節點又一次hash。函數
hashtable_itr.h和hashtable_itr.c是hashtable的迭代器,其實是直接對hashtable中的某個鏈表進行迭代。工具
二、序列化和反序列化post
zk本身實現了序列化,總體而言,zk傳輸的網絡數據都是:包長度(網絡大端形式)+包內容。oarchive結構體和iarchive分別包括序列化和反序列化的函數指針,這些函數指針包括最主要的操做,如(反)序列化int,long。字符串(vector,buffer,String)。google
詳細協議包頭數據(zookeeper.jute.h和zookeeper.jute.c)。則依據詳細數據類型。調用各個基本函數指針完畢。
三、winconfig.h
這裏需要單獨講一下winconfig.h。在講zk繼承到wpt時,我發現編譯報錯HMONITOR__ type redefinition。進一步排查發現與原來是這個文件定義的類型和wpt中相沖突,在各個宏定義以前加上#ifndef推斷以後,編譯成功。
四、核心實現
核心實現中_zhandle封裝zkclient的所有數據,包含zk_adaptor.h,mt_adaptor.c
1)IO線程。
IO線程負責socket的接收或發送。發送時數據被寫入到to_send鏈表。zk隨後經過select或poll完畢。
假設是異步任務(需要回調),則同一時候建立回調並將回調數據增長到sent_requests鏈表。因爲zk服務端保證了任務的有序性(順序請求必定也是順序返回)。因此當zk服務端任務結果到來,IO線程將任務結果寫入to_process鏈表中。那麼to_process中的結果和sent_requests中的回調就是相應的。
同步調用和異步調用流程一致,不一樣的是同步調用沒有回調函數(實際上回調函數被指定爲SYNCHRONOUS_MARKER),該標識會致使Complete線程作特殊處理。因爲異步流程是沒有等待的,因此同步時函數進入等待狀態(等待任務標記完畢)。
接下來就很是easy了:zk將兩者統一發送給Complete線程去處理。我想zk經過順序來肯定回調,應該是爲了不在發送數據中記錄回調的信息。
2)Complete線程。Complete線程很是easy,就是IO線程的消費者:調用回調函數。
假設回調函數爲SYNCHRONOUS_MARKER。則Complete通知等待線程任務完畢。