一、zookeeper詳解概念與原理(總結的乾貨)
ZK總結:
zookeeper(以下就用ZK代替)是一個分散式協調系統,主要有兩大功能,檔案系統和通知系統。
1、zk(分散式高性協調系統):
功能:
配置服務
叢集管理
名字服務
分散式同步
釋出訂閱(註冊中心)
資料庫動態切換
分散式日誌收集
分散式鎖
佇列管理
組服務等
2、zk結構和Linux有點類似
樹狀結構
3、zk的角色
leader
follower
observer(比如:操作zk的java程式碼)
4、zk的主要特點:
1.最終一致性
2.可靠性
3.實時性
4.等待無關性
5.原子性
6.順序性
一、概念:
1.zk結構:常規ZNode和臨時ZNode
2. zk伺服器端和zk客戶端
zk客戶端請求zk server叢集的時候,zk server可以透明的移動(zk server 通過zk leader可以把資源共享)
zk客戶端請求zk server的時候會生成一個session,session是可以設定超時間(t),每t/3ms 就會向伺服器
傳送一個心跳來維持長連線,如果2t/3ms 沒有接收到zk server的心跳回復,就會切換到另一個zk server,
3.ZK Watcher
Zk支援Watch操作,zk Client可以在zk server上的ZNode節點上設定Watcher,
如果ZNode有變化就會通知Zk client端,但是Watcher 是一次性的,如果需要必須重新設定Watcher。
二、ZK的特性
1.讀寫模式
1.1.讀:zk client端讀取資料的時候,可以從任意一個ZK server中讀取
1.2.寫:zk client端操作寫資料的時候,一般請求會作用在follower上,然後再到leader上,然後leader通過
(原子廣播協議)將寫資料的請求廣播給所有的Follower,Leader只要收到一半以上的Follower寫資料成功的(ACK)響應後,
就將持久化資料。並且把操作成功結果響應給zk client。
2.WAL(Write-Ahead-Log:在操作資料之前寫日誌)和Snapshot
2.1.WAL:對於zk 的每個操作都會先WAL,然後再對資料做操作。
2.2 .Snapshot:每隔一段時間zk會對記憶體中的目錄樹形ZNode進行Snapshot,
寫入磁碟。(這與HDFS中的FSImage的功能類似)。目的:確保資料完整備份和持久化,讓zk的啟動恢復速度加快。
3.FIFO:所有的zk client操作zk server都遵循FIFO順序,因為通訊協議是基於TCP的,
tcp傳輸包是FIFO的順序,zk server也是按照FIFO順序執行的。
4.Linearizability:zk都是FIFO的,更新的操作都是序列的。
三、ZK client API介面
create(path, data, flags): 建立一個ZNode path是其路徑,data是要儲存在該ZNode上的資料,
flags常用的有: PERSISTEN, PERSISTENT_SEQUENTAIL, EPHEMERAL, EPHEMERAL_SEQUENTAIL
delete(path, version): 刪除一個ZNode,可以通過version刪除指定的版本, 如果version是-1的話,
exists(path, watch): 判斷指定ZNode是否存在,並設定是否Watch這個ZNode。這裡如果要設定Watcher的話,
以下幾個帶watch引數的API也都類似
setData(path, watch): 更新指定ZNode的資料,並設定是否Watch這個ZNode
sync(path): 把所有在sync之前的更新操作都進行同步,達到每個請求都在半數以上的ZooKeeper Server上生效。
path引數目前沒有用
getAcl(path): 獲取指定ZNode的Acl資訊
四、常用的zk使用場景
1.名字服務:在分散式系統中,一般需要一套命令機制,既要能產生唯一標識,又能便於記憶和識別。因為每個ZNode都可以標識路徑的唯一性,路徑本身比較簡單直觀,ZNode可以儲存少量資料(一般預設1M)
1.1.通過簡單的名字來訪問指定的HDFS叢集
1.2.定義命名規則:這裡要做到簡潔易記憶。下面是一種可選的方案: [serviceScheme://][zkCluster]-[clusterName],比如hdfs://lgprc-example/表示基於lgprc ZooKeeper叢集的用來做example的HDFS叢集
1.3.配置DNS對映: 將zkCluster的標識lgprc通過DNS解析到對應的ZooKeeper叢集的地址
1.4.建立ZNode:在對應的ZooKeeper上建立/NameService/hdfs/lgprc-example結點,將HDFS的配置檔案儲存於該結點下
1.5.使用者程式要訪問hdfs://lgprc-example/的HDFS叢集,首先通過DNS找到lgprc的ZooKeeper機群的地址,然後在ZooKeeper的/NameService/hdfs/lgprc-example結點中讀取到HDFS的配置,進而根據得到的配置,得到HDFS的實際訪問入口
2.配置管理:在分散式系統中,有很多例項中的大多數配置項是相同的,需要改變配置項,如果有zk的話,不需要在每個例項去修改。
2.1.將公共的配置內容放在zk中的某個ZNode上,如:/xpservice/common-conf
2.2.所有的例項在啟動時會把zk的叢集的入口地址,執行中Watch 到/xpservice/common-conf這個ZNode
2.3.zk叢集修改了/xpservice/common-conf,所有的例項都會被通知到,跟新自己的配置,並且重新設定Watch /xpservice/common-conf節點
3.組員管理:在Master-Slave結構的分散式系統中,Master管理所有的Slave,當有Slave加入,或者有Slave宕機,master都需要知道,然後做出調整,以便不影響整個叢集對外提供服務。如:HBase。HMaster管理了所有的RegionServer,當有新的RegionServer加入的時候,HMaster需要分配一些Region到該RegionServer上其提供服務;當有RegionServer宕機時,HMaster需要將該RegionServer之前服務的Region都重新分配到當前正在提供服務的其它RegionServer上,以便不影響客戶端的正常訪問。
3.1.Master在ZooKeeper上建立/service/slaves結點,並設定對該結點的Watcher
3.2.每個Slave在啟動成功後,建立唯一標識自己的臨時性(Ephemeral)結點/service/slaves/${slave_id},並將自己地址(ip/port)等相關資訊寫入該結點
3.3.Master收到有新子結點加入的通知後,做相應的處理
3.4.如果有Slave宕機,由於它所對應的結點是臨時性結點,在它的Session超時後,ZooKeeper會自動刪除該結點
3.5.Master收到有子結點消失的通知,做相應的處理
4.簡單的分散式鎖(簡單互斥鎖):傳統執行緒、程序的同步,作業系統一般可以提供相應的機制完成。在分散式系統,多個程序之間的同步,作業系統層就不能為力。在這個時候就需要zk這樣的分散式協調(Coordination)服務來協助完成同步。
4.1.多個程序去在指定的目錄下建立一個臨時節點(臨時ZNode),如:/lock/my_lock
4.2.zk是可以保證一個程序只會一個程序建立了該節點,建立成功程序相當於搶到鎖
4.3.其他程序對/lock/my_lock進行watch
4.4.當獲取鎖的程序不需要鎖的時候,顯示的刪除/lock/my_lock節點(ZNode),然後Watcher就能監測到變更,然後通知讓其他程序去建立/lock/my_lock臨時節點(ZNode)搶鎖過程。依次迴圈。
5.分散式鎖(互斥鎖):上面簡單分散式鎖,每次都會有大量程序競爭,會造成羊群效應(Herd Effect),為了解決這個問題。
5.1.每個程序ZK上建立臨時的順序節點(Ephemeral Sequential)/lock/lock_{req}最小的為當前的鎖持有者(${req}是ZK生成的Sequential number)
5.3.其他程序只對比自己小的程序節點Watch,如:程序2 Watch 程序1,程序3 Watch 程序2,以此類推
5.4.當前持鎖釋放鎖後,比當前程序大的程序就會收到ZK的通知,它就成為持鎖者,如此迴圈。
補充:分散式系統中,zk來做leader Election(選主)就是通過上面的機制來實現的,這裡的持鎖者就是當前的“主”
6.讀寫鎖:讀寫鎖和互斥鎖不同的地方是,讀寫鎖分成讀和寫兩種模式,多個讀是可以併發執行,但寫和讀、都是互斥的。不能同事執行。利用zk,在上面的基礎上,稍作修改也可以實現傳統的讀寫鎖的語義。
6.1.每個程序都在zk上建立一個臨時的順序點(Ephemeral Sequential)/lock/lock_{req}最小的一個或多個節點為當前的持鎖者,多個是因為多個讀可以併發
6.3.需要寫鎖的程序,watch比它次小的程序對應的節點
6.4.需要讀鎖的程序,watch比它小的最後一個寫程序對應的節點
6.5.當前節點釋放鎖後,所有的watch該節點的程序都會被通知到,他們成為新的持鎖者,如此迴圈反覆。
7. 屏障(Barrier)
在分散式系統中,屏障是這樣一種語義: 客戶端需要等待多個程序完成各自的任務,然後才能繼續往前進行下一步。下用是用ZooKeeper來實現屏障的基本步驟:
7.1.Client在ZooKeeper上建立屏障結點/barrier/my_barrier,並啟動執行各個任務的程序
7.2.Client通過exist()來Watch /barrier/my_barrier結點 7.3.每個任務程序在完成任務後,去檢查是否達到指定的條件,如果沒達到就啥也不做,如果達到了就把/barrier/my_barrier結點刪除
7.4.Client收到/barrier/my_barrier被刪除的通知,屏障消失,繼續下一步任務
8. 雙屏障(Double Barrier)
雙屏障是這樣一種語義: 它可以用來同步一個任務的開始和結束,當有足夠多的程序進入屏障後,才開始執行任務;當所有的程序都執行完各自的任務後,屏障才撤銷。下面是用ZooKeeper來實現雙屏障的基本步驟:
進入屏障:
Client Watch /barrier/ready結點, 通過判斷該結點是否存在來決定是否啟動任務每個任務程序進入屏障時建立一個臨時結點/barrier/process/${process_id},然後檢查進入屏障的結點數是否達到指定的值,如果達到了指定的值,就建立一個/barrier/ready結點,否則繼續等待Client收到/barrier/ready建立的通知,就啟動任務執行過程
離開屏障:
Client Watch /barrier/process,如果其沒有子結點,就可以認為任務執行結束,可以離開屏障
每個任務程序執行任務結束後,都需要刪除自己對應的結點/barrier/process/${process_id}