文章目錄
1 zookeeper基礎
1.1 基本瞭解
zookeeper
是一個類似hdfs
的樹形文件結構,zookeeper
可以用來保證數據在(zk
)集羣之間的數據的事務性一致- 分佈、開源的應用程序協調服務,它是集羣的管理者,監視着集羣中各個節點的狀態,根據節點的反饋進行下一步合理操作。最終,將簡單易用的接口和性能高效、功能穩定的系統提供給用戶。
- 主要解決分佈式應用經常遇到的
數據管理問題
,如:統一命名服務、狀態同步服務、集羣管理、分佈式應用配置項的管理等。 Zookeeper
作爲Hadoop
項目中的一個子項目,是Hadoop
集羣管理的一個必不可少的模塊,它主要用來控制集羣中的數據,如它管理Hadoop
集羣中的NameNode
,還有Hbase
中Master Election、Server
之間狀態同步等
1.2 角色與功能
1.2.1 角色
1.2.1.1 三種角色
- 領導者(
leader
),負責進行投票的發起和決議,更新系統狀態 - 學習者(
learner
),包括跟隨者(follower
)和觀察者(observer
)
follower
用於接受客戶端請求
並想客戶端返回結果,在選主過程中參與投票
Observer
可以接受客戶端連接,將寫請求轉發給leader
,但observer
不參加投票過程,只同步leader
的狀態
observer
的目的是爲了擴展系統
,提高讀取速度
- 客戶端(
client
)請求發起方:
1.2.1.2 爲什麼引入Observer
Zookeeper
需保證高可用和強一致性,爲了支持更多的客戶端,需要增加更多Server
;
Server
增多,投票階段延遲增大,影響性能;權衡伸縮性
和高吞吐率
,引入Observer
Observer
不參與投票;Observers
接受客戶端的連接,並將寫請求轉發給leader
節點;- 加入更多
Observer
節點,提高伸縮性,同時不影響吞吐率
1.2.2 角色的功能
Leader
主要功能:恢復數據、維持與Follower
的心跳;接收Follower
請求並判斷Follower
的請求消息類型
Leader
的消息類型主要有PING
消息、REQUEST
消息、ACK
消息、REVALIDATE
消息,根據不同的消息類型,進行不同的處理。Follower
主要功能:向Leader
發送請求(PING
消息、REQUEST
消息、ACK
消息、REVALIDATE
消息);接收Leader
消息並進行處理;接收Client
的請求,如果爲寫請求,發送給Leader
進行投票;返回Client
結果
不同的消息類型:
PING
消息是指Leader
的心跳信息;PROPOSAL
消息:Leader
發起的提案,要求Follower
投票;COMMIT
消息:服務器端最新一次提案的信息;REQUEST
消息是Follower
發送的提議信息,包括寫請求
及同步請求
ACK
消息是Follower
的對提議的回覆,超過半數的Follower
通過,則commit
該提議REVALIDATE
消息是用來延長SESSION
有效時間。UPTODATE
消息:表明同步完成;SYNC
消息:返回SYNC
結果到客戶端,這個消息最初由客戶端發起,用來強制得到最新的更新。
1.3 zookeeper提供了什麼
1.3.1 文件系統
Zookeeper
提供一個多層級的節點命名空間(節點稱爲znode
)。
與文件系統不同的是,這些節點都可以設置關聯的數據
,而文件系統中只有文件節點
可以存放數據而目錄節點不行。
Zookeeper
爲了保證高吞吐
和低延遲
,在內存中維護了這個樹狀的目錄結構,這種特性使得Zookeeper
不能用於存放大量的數據,每個節點的存放數據上限爲1M
Znode
分爲四種類型:
PERSISTENT
持久化目錄節點。(客戶端與zookeeper
斷開連接後,該節點依舊存在)。PERSISTENT_SEQUENTIAL
-持久化順序編號目錄節點。(客戶端與zookeeper
斷開連接後,該節點依舊存在,只是Zookeeper
給該節點名稱進行順序編號)EPHEMERAL
-臨時目錄節點(客戶端與zookeeper
斷開連接後,該節點被刪除)EPHEMERAL_SEQUENTIAL
-臨時順序編號目錄節點。(客戶端與zookeeper
斷開連接後,該節點被刪除,只是Zookeeper給該節點名稱進行順序編號)
1.4 Zookeeper的核心及原理
1.4.1 zookeeper特性
一致性
:client
不論連接到哪個Server
,展示給它都是同一個視圖,這是zookeeper
最重要的性能。可靠性
:具有簡單、健壯、良好的性能,如果消息m被到一臺服務器接受,那麼它將被所有的服務器接受。實時性
:Zookeeper
保證客戶端將在一個時間間隔範圍內獲得服務器的更新信息,或者服務器失效的信息。但由於網絡延時等原因,Zookeeper
不能保證兩個客戶端能同時得到剛更新的數據,如果需要最新數據,應該在讀數據之前調用sync()
接口。等待無關
(wait-free
):慢的或者失效的client
不得干預快速的client
的請求,使得每個clien
t都能有效的等待。原子性
:更新只能成功或者失敗,沒有中間狀態。順序性
:包括全局有序
和偏序
兩種:全局有序是指如果在一臺服務器上消息a在消息b
前發佈,則在所有Server
上消息a
都將在消息b前被髮布;偏序是指如果一個消息b
在消息a
後被同一個發送者發佈,a
必將排在b
前面。
1.4.2 zookeeper原理
Zookeeper
的核心是原子廣播,這個機制保證了各個Server
之間的同步。實現這個機制的協議叫做Zab
協議。
Zab
協議有兩種模式,它們分別是恢復模式(選主)
和廣播模式(同步)
:
- 當服務啓動或者在領導者崩潰後,
Zab
就進入了恢復模式,當領導者被選舉出來,且大多數Server
完成了和leader
的狀態同步以後,恢復模式就結束了。狀態同步保證了leader
和Server
具有相同的系統狀態。 消息廣播模式
:在ZooKeeper
中所有的事務請求都由一個主服務器也就是Leader
來處理,其他服務器爲Follower
,Leader
將客戶端的事務請求轉換爲事務Proposal
,並且將Proposal
分發給集羣中其他所有的Follower
,然後Leader
等待Follwer
反饋,當有過半數(>=N/2+1
)的Follower
反饋信息後,Leader
將再次向集羣內Follower
廣播Commit
信息,Commit
爲將之前的Proposal
提交。
廣播模式需要保證proposal
被按順序處理,爲了保證事務的順序一致性,zookeeper
採用了遞增的事務id
號(zxid
)來標識事務。所有的提議(proposal
)都在被提出的時候加上了zxid
。zxid
是一個64
位的數字,它高32
位是epoch
用來標識leader
關係是否改變,每次一個leader
被選出來,它都會有一個新的epoch
,標識當前屬於那個leader
的統治時期。低32
位用於遞增計數
。
一旦leader
已經和多數的follower
進行了狀態同步
後,他就可以開始廣播消息
了,即進入廣播狀態。這時候當一個server
加入zookeeper
服務中,它會在恢復模式
下啓動,發現leader
,並和leader
進行狀態同步。待到同步結束,它也參與消息廣播。Zookeeper
服務一直維持在Broadcast
狀態,直到leader
崩潰了或者leader
失去了大部分的followers
支持。
每個Server
在工作過程中有三種狀態:
LOOKING
:當前Server
不知道leader
是誰,正在搜尋。LEADING
:當前Server
即爲選舉出來的leader
FOLLOWING
:leader
已經選舉出來,當前Server
與之同步
1.5 zookeeper流程
1.5.1 數據流程
- 在
Client
向Follwer
發出一個寫的請求 Follwer
把請求發送給Leader
Leader
接收到以後開始發起投票並通知Follwer
進行投票Follwer
把投票結果發送給Leader
Leader
將結果彙總後如果需要寫入,則開始寫入同時把寫入操作通知給Follwer
,然後commit
;Follwer
把請求結果返回給Client
1.5.2 選主流程以及算法
1.5.2.1 選舉leader
當leader
崩潰或者leader
失去大多數的follower
,這時候zk
進入恢復模式,恢復模式需要重新選舉出一個新的leader
,讓所有的server
都恢復到一個正確的狀態。
每個Server
啓動以後都詢問其它的Server
它要投票給誰。
對於其他server
的詢問,server
每次根據自己的狀態都回復自己推薦的leader
的id
和上一次處理事務的zxid
(系統啓動時每個server
都會推薦自己)
收到所有Server
回覆以後,就計算出zxid
最大的哪個Server
,並將這個Server
相關信息設置成下一次要投票的Server
計算這過程中獲得票數最多的的sever
爲獲勝者,如果獲勝者的票數超過半數,則改server
被選爲leader
。否則,繼續這個過程,直到leader
被選舉出來,leader
就會開始等待server
連接
Follower
連接leader
,將最大的zxid
發送給leader
,Leader
根據follower
的zxid
確定同步點
完成同步後通知follower
已經成爲uptodate
狀態
Follower
收到uptodate
消息後,又可以重新接受client
的請求進行服務了
1.5.2.2 選舉算法
Zk
的選舉算法有兩種:一種是基於basic paxos
實現的,另外一種是基於fast paxos
算法實現的。系統默認的選舉算法爲fast paxos
。
1.5.2.2.1 Basic paxos
Basic paxos
:當前Server
發起選舉的線程,向所有Server
發起詢問,選舉線程收到所有回覆,計算zxid
最大Server
,並推薦此爲leader
,若此提議獲得n/2+1
票通過,此爲leader
,否則重複上述流程,直到leader
選出。
1.5.2.2.2 Fast paxos
Fast paxos
:某Server
首先向所有Server
提議自己要成爲leader
,當其它Server
收到提議以後,解決epoch
和 zxid
的衝突,並接受對方的提議,然後向對方發送接受提議完成的消息,重複這個流程,最後一定能選舉出Leader
。(即提議方解決其他所有epoch
和zxid
的衝突,即爲leader
)
1.6 ZooKeeper的Watcher機制
client
端會對某個znode
建立一個watcher
事件,當該znode
發生變化時,這些client
會收到zk
的通知,然後client
可以根據znode
變化來做出業務上的改變等
ZooKeeper
的 Watcher
機制主要包括客戶端線程
、客戶端 WatchManager
和 ZooKeeper 服務器
三部分。
ZooKeeper
:部署在遠程主機上的ZooKeeper
集羣,當然,也可能是單機的。Client
:分佈在各處的 ZooKeeper 的 jar 包程序,被引用在各個獨立應用程序中。WatchManager
:一個接口,用於管理各個監聽器,只有一個方法materialize()
,返回一個Watcher
的set
。
客戶端在向 ZooKeeper
服務器註冊 Watcher
的同時,會將Watcher
對象存儲在客戶端的 WatchManager
中。當ZooKeeper
服務器觸發 Watcher
事件後,會向客戶端發送通知,客戶端線程從WatchManager
的實現類中取出對應的 Watcher
對象來執行回調邏輯。
Watcher
特性總結
- 一次性
無論是服務端還是客戶端,一旦一個Watcher
被觸發,ZooKeeper
都會將其從相應的存儲中移除。因此,在Watcher
的使用上,需要反覆註冊。這樣的設計有效地減輕了服務端的壓力。 - 客戶端串行執行
客戶端Watcher
回調的過程是一個串行同步的過程,這爲我們保證了順序,同時,需要注意的一點是,一定不能因爲一個Watcher
的處理邏輯影響了整個客戶端的Watcher
回調,所以,覺得客戶端Watcher
的實現類要另開一個線程進行處理業務邏輯,以便給其他的Watcher
調用讓出時間。 - 輕量
WatcherEvent
是ZooKeeper
整個Watcher
通知機制的最小通知單元,這個數據結構中只包含三部分內容:通知狀態、事件類型和節點路徑。也就是說,Watcher
通知非常簡單,只會告訴客戶端發生了事件,而不會說明事件的具體內容。例如針對NodeDataChanged
事件,ZooKeeper
的Watcher
只會通知客戶端指定數據節點的數據內容發生了變更,而對於原始數據以及變更後的新數據都無法從這個事件中直接獲取到,而是需要客戶端主動重新去獲取數據——這也是ZooKeeper
的Watcher
機制的一個非常重要的特性
2 zookeeper的作用
2.1 命名服務
在zookeeper
的文件系統裏創建一個目錄,即有唯一的path
。在我們使用tborg
無法確定上游程序的部署機器時即可與下游程序約定好path
,通過path
即能互相探索發現。
2.2 配置管理
把應用配置放置zookeeper
上去,保存在 Zookeeper
的某個目錄節點中,然後所有相關應用程序對這個目錄節點進行監聽,一旦配置信息發生變化,每個應用程序就會收到 Zookeeper
的通知,然後從Zookeeper
獲取新的配置信息應用到系統中就好。
2.3 集羣管理
節點(機器)增刪及Master
選取。
2.3.1 節點增刪
所有機器約定在父目錄GroupMembers
下創建臨時目錄節點,然後監聽父目錄節點的子節點變化消息。一旦有機器掛掉,該機器與zookeeper
的連接斷開,其所創建的臨時目錄節點被刪除,所有其他機器都收到通知:某個兄弟目錄被刪除,於是,所有人都知道:它掛了。新機器加入 也是類似,所有機器收到通知:新兄弟目錄加入,highcount
又有了。
2.3.1 Master節點選取
所有機器創建臨時順序編號目錄節點,每次選取編號最小的機器作爲master
就好。
如果有多個master
,每次只能有一個master
負責主要的工作,其他的master
作爲備份,同時對負責工作的master
進行監聽,一旦負責工作的master
掛掉了,其他的master
就會收到監聽的事件,從而去搶奪負責工作的權利,其他沒有爭奪到負責主要工作的master
轉而去監聽負責工作的新master
,簡而言之:一人幹,多人看
2.4 分佈式鎖
基於zookeeper
一致性文件系統,實現鎖服務。鎖服務分爲保存獨佔
及時序控制
兩類。
2.4.1 保存獨佔
將zookeeper
上的一個znode
看作是一把鎖,通過createznode
的方式來實現。
所有客戶端都去創建 /distribute_lock
節點,最終成功創建的那個客戶端也即擁有了這把鎖。
用完刪除自己創建的distribute_lock
節點就釋放鎖。
2.4.2 時序控制
基於/distribute_lock
鎖,所有客戶端在它下面創建臨時順序編號目錄節點,和選master
一樣,編號最小的獲得鎖,用完刪除,依次方便。
2.5 隊列管理
分同步隊列
,FIFO隊列
(入隊與出隊)
2.5.1 同步隊列
當一個隊列的成員都聚齊時,這個隊列纔可用,否則一直等待所有成員到達。在約定目錄下創建臨時目錄節點,監聽節點數目是否是我們要求的數目
2.5.2 FIFO隊列
FIFO
隊列(入隊與出隊)和分佈式鎖服務中的控制時序場景基本原理一致,入列有編號,出列按編號。
2.6 分佈式與數據複製
Zookeeper
作爲一個集羣提供一致的數據服務,必然在所有機器間做數據複製。
數據複製好處:
容錯
:一個節點出錯,不致於讓整個系統停止工作,別的節點可以接管它的工作。提高系統的擴展能力
:把負載分佈到多個節點上,或者增加節點來提高系統的負載能力;性能提升
:讓客戶端本地訪問就近節點,提高用戶訪問速度。
3 數據一致性與paxos 算法
3.1 數據集羣
數據集羣系統分:
- 寫主(
writeMaster
),對數據的修改提交給指定的節點。讀無此限制,可以讀取任何一個節點。這種情況下客戶端需要對讀與寫進行區別,俗稱讀寫分離; - 寫任意(對數據的修改可提交給任意的節點,跟讀一樣。這種情況下,客戶端對集羣節點的角色與變化透明)對
zookeeper
來說,它採用的方式是寫任意。通過增加機器,它的讀吞吐能力和響應能力擴展性非常好,而寫,隨着機器的增多吞吐能力肯定下降(這也是它建立observer
的原因),而響應能力則取決於具體實現方式,是延遲複製保持最終一致性,還是立即複製快速響應。
3.2 原則
在一個分佈式數據庫系統中,如果各節點的初始狀態一致,每個節點都執行相同的操作序列,那麼他們最後能得到一個一致的狀態。Paxos算法解決:保證每個節點執行相同的操作序列。
Paxos
算法通過投票來對寫操作
進行全局編號,同一時刻,只有一個寫操作被批准,同時併發的寫操作要去爭取選票,只有獲得過半數
選票的寫操作纔會被 批准(所以永遠只會有一個寫操作得到批准),其他的寫操作競爭失敗只好再發起一輪投票,就這樣,在日復一日年復一年的投票中,所有寫操作都被嚴格編號排序。編號嚴格遞增,當一個節點接受了一個編號爲100
的寫操作,之後又接受到編號爲99
的寫操作(因爲網絡延遲等很多不可預見原因),它馬上能意識到自己數據不一致了,自動停止對外服務並重啓同步過程。任何一個節點掛掉都不會影響整個集羣的數據一致性(總2n+1
臺,除非掛掉大於n
臺)。