-
叢集任務
-
主從架構
在分散式系統設計中一個得到廣泛應用的架構:一個主-從(master-worker)架構,該系統中遵循這個架構的一個重要例子是HBase——一個Google的資料儲存系統(BigTable)模型的實現,在最高層,主節點伺服器(HMaster)負責跟蹤區域伺服器(HRegionServer)是否可用,並分派區域到伺服器。
-
master-worker模式面臨的問題
- 主節點崩潰
如果主節點傳送錯誤並失效,系統將無法分配新的任務或重新分配已失敗的任務。這就需要重選備份主節點接管主要主節點的角色,進行故障轉移,資料恢復等等,更糟的是,如果一些從節點無法與主要主節點通訊,如由於網路分割槽(network partition)錯誤導致,這些從節點可能會停止與主要主節點的通訊,而與第二個主要主節點建立主-從關係。針對這個場景中導致的問題,我們一般稱之為腦裂(split-brain):系統中兩個或者多個部分開始獨立工作,導致整體行為不一致性。我們需要找出一種方法來處理主節點失效的情況,關鍵是我們需要避免發生腦裂的情況。
- 從節點崩潰
如果從節點崩潰,已分配的任務將無法完成。如果從節點崩潰了,所有已派發給這個從節點且尚未完成的任務需要重新派發。其中首要需求是讓主節點具有檢測從節點的崩潰的能力。主節點必須能夠檢測到從節點的崩潰,並確定哪些從節點是否有效以便派發崩潰節點的任務。一個從節點崩潰時,從節點也許執行了部分任務,也許全部執行完,但沒有報告結果。如果整個運算過程產生了其他作用,我們還有必要執行某些恢復過程來清除之前的狀態。
- 通訊故障
如果主節點和從節點之間無法進行資訊交換,從節點將無法得知新任務分配給它。如果一個從節點與主節點的網路連線斷開,比如網路分割槽(network partition)導致,重新分配一個任務可能會導致兩個從節點執行相同的任務。如果一個任務允許多次執行,我們在進行任務再分配時可以不用驗證第一個從節點是否完成了該任務。如果一個任務不允許,那麼我們的應用需要適應多個從節點執行相同任務的可能性。
- 主節點崩潰
-
主從模式總結
- 主節點選舉
這是關鍵的一步,使得主節點可以給從節點分配任務。
- 崩潰檢測
主節點必須具有檢測從節點崩潰或失去連線的能力。
- 組成員關係管理
主節點必須具有知道哪一個從節點可以執行任務的能力。
- 後設資料管理
主節點和從節點必須具有通過某種可靠的方式來儲存分配狀態和執行狀態的能力。
- 主節點選舉
-
期望
理想的方式是,以上每一個任務都需要通過原語(核心或微核提供核外呼叫的過程或函式稱為原語(primitive))的方式暴露給應用,對開發者完全隱藏實現細節。ZooKeeper提供了實現這些原語的關鍵機制,因此,開發者可以通過這些實現一個最適合他們需求、更加關注應用邏輯的分散式應用。
-
-
什麼是zookeeper
-
來源
Zookeeper 最早起源於雅虎研究院的一個研究小組。在當時,研究人員發現,在雅虎內部很多大型系統基本都需要依賴一個類似的系統來進行分散式協調,但是這些系統往往都存在分散式單點問題。所以,雅虎的開發人員就試圖開發一個通用的無單點問題的分散式協調框架,以便讓開發人員將精力集中在處理業務邏輯上。
-
zookeeper是什麼
ZooKeeper是一種用於分散式應用程式的高效能協調服務.
ZooKeeper is a high-performance coordination service for distributed applications. It exposes common services - such as naming, configuration management, synchronization, and group services - in a simple interface so you don't have to write them from scratch. You can use it off-the-shelf to implement consensus, group management, leader election, and presence protocols. And you can build on it for your own, specific needs.
ZooKeeper是一個典型的分散式資料一致性解決方案,其設計目標是將那些複雜且容易出錯的分散式一致性服務封裝起來,構成一個高效可靠的原語集,並以一系列簡單易用的介面提供給使用者使用。分散式應用程式可以基於 ZooKeeper 實現諸如資料釋出/訂閱、負載均衡、命名服務、分散式協調/通知、叢集管理、Master 選舉、分散式鎖和分散式佇列等功能。
-
初識
-
zk架構
-
角色
-
Leader
Leader作為整個ZooKeeper叢集的主節點,負責響應所有對ZooKeeper狀態變更的請求。它會將每個狀態更新請求進行排序和編號,以便保證整個叢集內部訊息處理的FIFO。
-
Follower
Follower主要是響應本伺服器上的讀請求外,另外follower還要處理leader的提議,並在leader提交該提議時在本地也進行提交。另外需要注意的是,leader和follower構成ZooKeeper叢集的法定人數,也就是說,只有他們才參與新leader的選舉、響應leader的提議。
-
Observe
為客戶端提供讀伺服器,如果是寫服務則轉發給Leader。不參與選舉過程中的投票,也不參與“過半寫成功”策略。在不影響寫效能的情況下提升叢集的讀效能。
-
client
連線zookeeper伺服器的使用著,請求的發起者。獨立於zookeeper伺服器叢集之外的角色。
-
-
資料模型znode
-
ZAB協議
- 崩潰恢復
- 原子廣播
-
-
特點
- 簡單化:ZooKeeper允許各分散式程式通過一個共享的名稱空間相互聯絡,該名稱空間類似於一個標準的層次型的檔案系統。
- 順序一致性:按照客戶端傳送請求的順序更新資料。
- 原子性:更新要麼成功,要麼失敗,不會出現部分更新。
- 單一性 :無論客戶端連線哪個 server,都會看到同一個檢視。
- 可靠性:一旦資料更新成功,將一直保持,直到新的更新。
- 及時性:客戶端會在一個確定的時間內得到最新的資料。
- 速度優勢:ZooKeeper特別適合於以讀為主要負荷的場合。ZooKeeper可以執行在數千臺機器上,如果大部分操作為讀,例如讀寫比例為10:1,ZooKeeper的效率會很高。
-
運用場景
- 資料釋出與訂閱(配置中心)
- 負載均衡
- 命名服務(Naming Service)
- 分散式通知/協調
- 叢集管理與Master選舉
- 分散式鎖
- 分散式佇列
-
-
Standalone模式演示開始,本地啟動
-
配置
- tickTime
ZooKeeper 中使用的基本時間單元, 以毫秒為單位, 預設值是 2000。它用來調節心跳和超時。
- initLimit
預設值是 10, 即 tickTime 屬性值的 10 倍。它用於配置允許 followers 連線並同步到 leader 的最大時間。如果 ZooKeeper 管理的資料量很大的話可以增加這個值。
- syncLimit
預設值是 5, 即 tickTime 屬性值的 5 倍。它用於配置leader 和 followers 間進行心跳檢測的最大延遲時間。如果在設定的時間內 followers 無法與 leader 進行通訊, 那麼 followers 將會被丟棄。
- dataDir
ZooKeeper 用來儲存記憶體資料庫快照的目錄, 並且除非指定其它目錄, 否則資料庫更新的事務日誌也將會儲存在該目錄下。
- clientPort
伺服器監聽客戶端連線的埠, 也即客戶端嘗試連線的埠, 預設值是 2181。
- tickTime
-
/bin/命令
- zkCleanup:清理Zookeeper歷史資料,包括事務日誌檔案和快照資料檔案
- zkCli:Zookeeper的一個簡易客戶端
- zkEnv:設定Zookeeper的環境變數
- zkServer:Zookeeper伺服器的啟動、停止、和重啟指令碼
-
監控命令
在客戶端可以通過 telnet 或 nc 向 ZooKeeper 提交相應的服務資訊查詢命令。使用方式
echo mntr | nc localhost 2181
.- conf: 輸出相關服務配置的詳細資訊。比如埠、zk資料及日誌配置路徑、最大連線數,session超時時間、serverId等
- cons: 列出所有連線到這臺伺服器的客戶端連線/會話的詳細資訊。包括“接受/傳送”的包數量、session id 、操作延遲、最後的操作執行等資訊.
- stat: 輸出伺服器的詳細資訊:接收/傳送包數量、連線數、模式(leader/follower)、節點總數、延遲。 所有客戶端的列表。
- envi: 輸出關於伺服器的環境詳細資訊(不同於conf命令),比如host.name、java.version、java.home、user.dir=/data/zookeeper-3.4.6/bin之類資訊
- ...
-
-
複製模式配置
- 配置server id
zookeeper叢集模式下還要配置一個myid檔案,這個檔案需要放在dataDir目錄下,檔案中寫入一個id即可。
- zoo.cfg配置叢集server列表
- 叢集模式多了 server.id=host:port1:port2 的配置。
server.1= 192.168.1.9:2888:3888 server.2= 192.168.1.124:2888:3888 server.3= 192.168.1.231:2888:3888 複製程式碼
其中,id 被稱為 Server ID,用來標識該機器在叢集中的機器序號(在每臺機器的 dataDir 目錄下建立 myid 檔案,檔案內容即為該機器對應的 Server ID 數字)。host 為機器 IP,port1 用於指定 Follower 伺服器與 Leader 伺服器進行通訊和資料同步的埠,port2 用於進行 Leader 選舉過程中的投票通訊。
- 叢集模式多了 server.id=host:port1:port2 的配置。
- 配置server id
-
核心概念
-
資料模型znode
-
儲存
- 記憶體資料
Zookeeper的資料模型是樹結構,在記憶體資料庫中,儲存了整棵樹的內容,包括所有的節點路徑、節點資料、ACL資訊,Zookeeper會定時將這個資料儲存到磁碟上。
- DataTree
DataTree是記憶體資料儲存的核心,是一個樹結構,代表了記憶體中一份完整的資料。DataTree不包含任何與網路、客戶端連線及請求處理相關的業務邏輯,是一個獨立的元件。
- DataNode
DataNode是資料儲存的最小單元,其內部除了儲存了結點的資料內容、ACL列表、節點狀態之外,還記錄了父節點的引用和子節點列表兩個屬性,其也提供了對子節點列表進行操作的介面。
- ZKDatabase
Zookeeper的記憶體資料庫,管理Zookeeper的所有會話、DataTree儲存和事務日誌。ZKDatabase會定時向磁碟dump快照資料,同時在Zookeeper啟動時,會通過磁碟的事務日誌和快照檔案恢復成一個完整的記憶體資料庫。
- DataTree
- 事務日誌
事務日誌指zookeeper系統在正常執行過程中,針對所有的更新操作,在返回客戶端“更新成功”的響應前,zookeeper會保證已經將本次更新操作的事務日誌已經寫到磁碟上,只有這樣,整個更新操作才會生效。
- 記憶體資料
-
臨時(Ephemeral)znode
- as long as the session
- 只能是在葉子節點上建立
-
持久(PERSISTENT)znode
-
順序(SEQUENTIAL)znode
- 在父節點下有序自增
- int
-
zxid
- 有序
- 全域性唯一
-
zookeeper znode stat 結構
- czxid Created ZXID表示該資料節點被建立時的事務ID
- mzxid Modified ZXID 表示該節點最後一次被更新時的事務ID
- pzxid 表示該節點的子節點列表最後一次被修改時的事務ID。只有子節點列表變更了才會變更pZxid,子節點內容變更不會影響pZxid
- ctime Created Time表示節點被建立的時間
- mtime Modified Time表示節點最後一次被更新的時間
- dataVersion 資料節點版本號
- cversion 子節點的版本號
- aclVersion 節點的ACL版本號
- ephemeralOwner 建立該臨時節點的會話的SessionID。如果節點是持久節點,這個屬性為0
- dataLength 資料內容的長度
- numChildren 當前節點的子節點個數
-
-
ZooKeeper Sessions
ZooKeeper的每個客戶端都維護一組服務端資訊,在建立連線時由應用指定,客戶端隨機選擇一個服務端進行連線,連線成功後,服務端為每個連線分配一個唯一標識。客戶端在建立連線時可以指定溢位時間,客戶端會週期性的向服務端傳送PING請求來保持連線,當客戶端檢測到與服務端斷開連線後,客戶端將自動選擇服務端列表中的另一個服務端進行重連。
-
建立會話
ZooKeeper zk = new ZooKeeper(serverList, sessionTimeout, watcher); zk.create("/test", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); 複製程式碼
建立客戶端session時,應用必須傳入一組以逗號分隔的host:port列表,每個都對應一個ZooKeeper服務端,ZooKeeper客戶端將選擇任意一個服務端並嘗試與其連線(這組serverlist會在初始化的時候打亂),如果連線失敗,或者由於某些原因導致客戶端與服務端連線斷開,客戶端將自動的選擇列表中的另一個服務端進行連線,直到成功。當session建立成功後,ZooKeeper服務端為session分配一個唯一標識。
- 建立過程
-
client進行tcp建立連線
-
當tcp連線成功之後,client傳送一個ConnectRequest包,將ZooKeeper建構函式傳入的sessionTimeout數值發給Server。zookeeper server會驗證客戶端發來的sessionTimeout值;zookeeper server中有連個配置項.
- minSessionTimeout 單位毫秒。預設2倍tickTime
- maxSessionTimeout 單位毫秒。預設20倍tickTime
(tickTime也是一個配置項。是Server內部控制時間邏輯的最小時間單位)
如果客戶端發來的sessionTimeout超過min-max這個範圍,server會自動擷取為min或max.
-
server等表決通過後,會為這個session生成一個password,連同sessionId,sessionTimeOut一起返回給客戶端(ConnectResponse)。客戶端如果需要重連Server,可以新建一個ZooKeeper物件,將上一個成功連線的ZooKeeper 物件的sessionId和password傳給Server ZooKeeper zk = new ZooKeeper(serverList, sessionTimeout, watcher, sessionId,passwd);ZKServer會根據sessionId和password為同一個client恢復session,如果還沒有過期的話。
-
- 建立過程
-
會話狀態
Zookeeper會話在整個執行期間的生命週期中,會在不同的會話狀態中之間進行切換,這些狀態可以分為CONNECTING, ASSOCIATING, CONNECTED, CLOSED, AUTH_FAILED。
一旦客戶端開始建立Zookeeper物件,那麼客戶端狀態就會變成CONNECTING狀態,同時客戶端開始嘗試連線服務端,連線成功後,客戶端狀態變為CONNECTED,通常情況下,由於斷網或其他原因,客戶端與服務端之間會出現斷開情況,一旦碰到這種情況,Zookeeper客戶端會自動進行重連服務,同時客戶端狀態再次變成CONNCTING,直到重新連上服務端後,狀態又變為CONNECTED,在通常情況下,客戶端的狀態總是介於CONNECTING和CONNECTED之間。但是,如果出現諸如會話超時、許可權檢查或是客戶端主動退出程式等情況,客戶端的狀態就會直接變更為CLOSE狀態。
-
session啟用
在ZooKeeper中,伺服器和客戶端之間維持的是一個長連線,在 SESSION_TIMEOUT 時間內,伺服器會確定客戶端是否正常連線(客戶端會定時向伺服器傳送heart_beat),伺服器重置下次SESSION_TIMEOUT時間。;同時在Zookeeper的實際設計中,只要客戶端有請求傳送到服務端,那麼就會觸發一次會話啟用,總結下來兩種情況都會觸發會話啟用。
- 客戶端向服務端傳送請求,包括讀寫請求,就會觸發會話啟用。
- 客戶端會定時向伺服器傳送heart_beat。
-
會話清理
leader server的SessionTracker管理執行緒會管理者session,執行session的過期檢查,如果會話過期就執行清理操作.
-
會話重連
- CONNECTIONLOSS
- SESSIONEXPIRED
-
客戶端連線指定根路徑
在ZooKeeper 3.2.0增加了可選的“chroot”字尾,可以改變當前客戶端的根路徑。例如,如果使用”localhost:2181/app/a”,客戶端將使用”/app/a”作為其根路徑,所有的路徑都會相對於該路徑。比如操作路徑”/foo/bar”將真正對應到”/app/a/foo/bar”。這個特徵在多租戶環境下是非常有用的,可以簡化客戶端的應用邏輯。
-
-
ZooKeeper Watches
在ZooKeeper中,所有的讀操作(getData,getChildren和exists)都可以設定監聽,一個Watch事件是一個一次性的觸發器,當被設定了Watch的資料發生了改變的時候,則伺服器將這個改變傳送給設定了Watch的客戶端,以便通知它們。
-
zookeeper機制的特點
- 一次性的觸發器(one-time trigger)
當資料改變的時候,那麼一個Watch事件會產生並且被髮送到客戶端中。但是客戶端只會收到一次這樣的通知,如果以後這個資料再次發生改變的時候,之前設定Watch的客戶端將不會再次收到改變的通知,因為Watch機制規定了它是一個一次性的觸發器。
- 傳送到客戶端(Sent to the client)
這個表明了Watch的通知事件是從伺服器傳送給客戶端的,是非同步的,這就表明不同的客戶端收到的Watch的時間可能不同,但是ZooKeeper有保證:當一個客戶端在看到Watch事件之前是不會看到結點資料的變化的。例如:A=3,此時在上面設定了一次Watch,如果A突然變成4了,那麼客戶端會先收到Watch事件的通知,然後才會看到A=4。
- 監聽方式(The data for which the watch was set)
znode 節點本身具有不同的改變方式,setData() 會觸發設定在某一節點上所設定的資料監視(假定資料設定成功),而一次成功的 create() 操作則會出發當前節點上所設定的資料監視以及父節點的子節點監視。一次成功的 delete() 操作將會觸發當前節點的資料監視和子節點監視事件,同時也會觸發該節點父節點的child watch。WatchEvent是最小的通訊單元,結構上只包含通知狀態、事件型別和節點路徑。ZooKeeper服務端只會通知客戶端發生了什麼,並不會告訴具體內容。
- 一次性的觸發器(one-time trigger)
-
監聽事件型別
- Created event:呼叫exists方法設定監聽;
- Deleted event:呼叫exists、getData、getChildren設定監聽;
- Changed event:呼叫getData設定監聽;
- Child event:呼叫getChildren設定監聽。
-
-
ACL 許可權控制
zk做為分散式架構中的重要中介軟體,通常會在上面以節點的方式儲存一些關鍵資訊,預設情況下,所有應用都可以讀寫任何節點,在複雜的應用中,這不太安全,ZK通過ACL機制來解決訪問許可權問題.
- 身份認證方式
- world:預設方式,相當於全世界都能訪問
- auth:代表已經認證通過的使用者(cli中可以通過addauth digest user:pwd 來新增當前上下文中的授權使用者)
- digest:即使用者名稱:密碼這種方式認證,這也是業務系統中最常用的
- ip:使用Ip地址認證
- 身份認證方式
-
-
回顧zookeeper架構
-
ZAB協議
ZAB協議(Zookeeper Atomic Broadcast Protocol)是Zookeeper系統專門設計的一種支援崩潰恢復的原子廣播協議。Zookeeper使用該協議來實現分佈資料一致性並實現了一種主備模式的系統架構來保持各叢集中各個副本之間的資料一致性。採用zab協議的最大目標就是建立一個高可用可擴充套件的分散式資料主備系統。即在任何時刻只要leader發生當機,都能保證分散式系統資料的可靠性和最終一致性。
-
特點
- 一致性保證
- 可靠提交(Reliable delivery) -如果一個事務 A 被一個server提交(committed)了,那麼它最終一定會被所有的server提交
- 全域性有序(Total order) - 假設有A、B兩個事務,有一臺server先執行A再執行B,那麼可以保證所有server上A始終都被在B之前執行
- 因果有序(Causal order) - 如果傳送者在事務A提交之後再傳送B,那麼B必將在A之前執行
- 只要大多數(法定數量)節點啟動,系統就行正常執行
- 當節點下線後重啟,它必須保證能恢復到當前正在執行的事務
- 一致性保證
-
ZAB協議工作原理
ZAB協議要求每個leader都要經歷三個階段,即發現,同步,廣播。
* 發現:即要求zookeeper叢集必須選擇出一個leader程式,同時leader會維護一個follower可用列表。將來客戶端可以與這個follower中的節點進行通訊。 * 同步:leader要負責將本身的資料與follower完成同步,做到多副本儲存。這樣也是體現了CAP中高可用和分割槽容錯。follower將佇列中未處理完的請求消費完成後,寫入本地事物日誌中。 * 廣播:leader可以接受客戶端新的proposal請求,將新的proposal請求廣播給所有的follower。 複製程式碼
-
ZAB兩種模式
- 崩潰恢復
當服務初次啟動,或者 leader 節點掛了,系統就會進入恢復模式,直到選出了有合法數量 follower 的新 leader,然後新 leader 負責將整個系統同步到最新狀態。
- 訊息廣播模式
Zab 協議中,所有的寫請求都由 leader 來處理。正常工作狀態下,leader 接收請求並通過廣播協議來處理。
- 崩潰恢復
-
-
選舉
-
問題: 如何選舉leader
某個服務可以配置為多個例項共同構成一個叢集對外提供服務。其每一個例項本地都存有冗餘資料,每一個例項都可以直接對外提供讀寫服務。在這個叢集中為了保證資料的一致性,需要有一個Leader來協調一些事務。那麼問題來了:如何確定哪一個例項是Leader呢?
- 選舉的難點
- 沒有一個仲裁者來選定Leader
- 每一個例項本地可能已經存在資料,不確定哪個例項上的資料是最新的
- 選舉的難點
-
分散式選舉演算法
- Paxos
- Raft
- ZooKeeper ZAB
-
-
zookeeper選主
-
搞清楚幾個問題
- 一個Server是如何知道其它的Server?
在ZooKeeper叢集中,Server的資訊都在zoo.conf配置檔案中,根據配置檔案的資訊就可以知道其它Server的資訊。
- 成為Leader的必要條件?
Leader要具有最高的zxid;叢集中大多數的機器(至少n/2+1)得到響應並follow選出的Leader。
- 如果所有zxid都相同(例如: 剛初始化時),此時有可能不能形成n/2+1個Server,怎麼辦?
ZooKeeper中每一個Server都有一個ID,這個ID是不重複的,如果遇到這樣的情況時,ZooKeeper就推薦ID最大的哪個Server作為Leader。
- ZooKeeper中Leader怎麼知道Fllower還存活,Fllower怎麼知道Leader還存活?
Leader定時向Fllower發ping訊息,Fllower定時向Leader發ping訊息,當發現Leader無法ping通時,就改變自己的狀態(LOOKING),發起新的一輪選舉。
- 一個Server是如何知道其它的Server?
-
leader選主時機
- Server初始化
- server執行期間無法和leader保持連線
-
核心概念
-
ZooKeeper伺服器狀態
- LOOKING:尋找leader狀態
- LEADING:領導狀態(節點為leader)
- FOLLOWING:跟隨者狀態
- OBSERVING:觀察者狀態(此狀態不參與選舉)
-
myid
每個Zookeeper伺服器,都需要在資料資料夾下建立一個名為myid的檔案,該檔案包含整個Zookeeper叢集唯一的ID(整數)。例如某Zookeeper叢集包含三臺伺服器,hostname分別為zoo1、zoo2和zoo3,其myid分別為1、2和3,則在配置檔案中其ID與hostname必須一一對應,如下所示。在該配置檔案中,server.後面的資料即為myid.
server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 server.3=zoo3:2888:3888 複製程式碼
-
zxid
每次對Zookeeper的狀態的改變都會產生一個zxid(ZooKeeper Transaction Id),zxid是全域性有序的,如果zxid1小於zxid2,則zxid1在zxid2之前發生。為了保證順序性,該zkid必須單調遞增。因此Zookeeper使用一個64位的數來表示,高32位是Leader的epoch,從1開始,每次選出新的Leader,epoch加一。低32位為該epoch內的序號,每次epoch變化,都將低32位的序號重置。這樣保證了zkid的全域性遞增性。
-
logicalclock
每個伺服器會維護一個自增的整數,名為logicalclock,它表示這是該伺服器發起的第多少輪投票。
-
-
選主步驟
- 狀態變更
伺服器啟動的時候每個server的狀態時Looking,如果是leader掛掉後進入選舉,那麼餘下的非Observer的Server就會將自己的伺服器狀態變更為Looking,然後開始進入Leader的選舉狀態;
- 自增選舉輪次
Zookeeper規定所有有效的投票都必須在同一輪次中。每個伺服器在開始新一輪投票時,會先對自己維護的logicalclock進行自增操作。
- 初始化選票
每個伺服器在廣播自己的選票前,會將自己的投票箱清空。該投票箱記錄了所收到的選票。例:伺服器2投票給伺服器3,伺服器3投票給伺服器1,則伺服器1的投票箱為(2, 3), (3, 1), (1, 1)。票箱中只會記錄每一投票者的最後一票,如投票者更新自己的選票,則其它伺服器收到該新選票後會在自己票箱中更新該伺服器的選票。
- 發起投票
每個server會產生一個(sid,zxid)的投票,系統初始化的時候zxid都是0,如果是執行期間,每個server的zxid可能都不同,這取決於最後一次更新的資料。將投票傳送給叢集中的所有機器;
- 接收外部投票
伺服器會嘗試從其它伺服器獲取投票,並記入自己的投票箱內。如果無法獲取任何外部投票,則會確認自己是否與叢集中其它伺服器保持著有效連線。如果是,則再次傳送自己的投票;如果否,則馬上與之建立連線。
- 判斷選舉輪次
收到外部投票後,首先會根據投票資訊中所包含的logicalclock來進行不同處理. * 外部投票的logicalclock大於自己的logicalclock。說明該伺服器的選舉輪次落後於其它伺服器的選舉輪次,立即清空自己的投票箱並將自己的logicalclock更新為收到的logicalclock,然後再對比自己之前的投票與收到的投票以確定是否需要變更自己的投票,最終再次將自己的投票廣播出去。 * 外部投票的logicalclock小於自己的logicalclock。當前伺服器直接忽略該投票,繼續處理下一個投票。 * 外部投票的logickClock與自己的相等。當時進行選票PK。
- 處理投票
對自己的投票和接收到的投票進行PK: 1. 先檢查zxid,較大的優先為leader; 2. 如果zxid一樣,sid較大的為leader; 3. 根據PK結果更新自己的投票,在次傳送自己的投票;
- 統計投票
每次投票後,伺服器統計投票資訊,如果有過半機器接收到相同的投票,那麼leader產生,如果否,那麼進行下一輪投票;
- 改變server狀態
一旦確定了Leader,server會更新自己的狀態為Following或者是Leading。選舉結束。
- 狀態變更
-
幾種leader選舉場景
- 叢集啟動選舉
- Follower重啟選舉
- Leader重啟選舉
-
舉例
-
叢集啟動選舉
-
Follower重啟選舉
-
Leader重啟選舉
-
-
-
資料同步
在完成leader選舉階段後,準Leader可以獲取叢集中最新的提議歷史。準Leader在該階段會把最新的提議歷史同步到叢集中的所有節點。當同步完成時(過半),準Leader才會真正成為Leader,執行Leader的工作。
- 恢復模式需要解決的兩個重要問題
- 已經被處理的訊息不能丟
- 被丟棄的訊息不能再次出現
- 恢復模式需要解決的兩個重要問題
-
原子廣播
-
分散式一致問題
分散式中有這麼一個疑難問題,客戶端向一個分散式叢集的服務端發出一系列更新資料的訊息,由於分散式叢集中的各個服務端節點是互為同步資料的,所以執行完客戶端這系列訊息指令後各服務端節點的資料應該是一致的,但由於網路或其他原因,各個服務端節點接收到訊息的序列可能不一致,最後導致各節點的資料不一致。
-
分散式一致性
-
CAP
分散式系統的最大難點,就是各個節點的狀態如何同步。CAP 定理是這方面的基本定理,也是理解分散式系統的起點。
- Consistency (一致性)
寫操作之後的讀操作,必須返回該值。
- Availability (可用性)
意思是隻要收到使用者的請求,伺服器就必須給出回應。每次請求都能獲取到非錯的響應——但是不保證獲取的資料為最新資料。
- Partition tolerance (分割槽容錯)
區間通訊可能失敗。
這三個基本需求,最多隻能同時滿足其中的兩項,一致性和可用性不可能同時成立,因為可能通訊失敗(即出現分割槽容錯)。
- Consistency (一致性)
-
拜占庭問題
11位拜占庭將軍去打仗, 他們各自有權力觀測敵情並作出判斷, 進攻或撤退, 那麼怎麼讓他們只用傳令兵達成一致呢?一種很符合直覺的方法就是投票,每位將軍作出決定後都將結果"廣播"給其餘所有將軍, 這樣所有將軍都能獲得同樣的11份(包括自己)結果, 取多數, 即可得到全軍都同意的行為.但如果這11位將軍中有間諜呢? 假設有9位忠誠的將軍, 5位判斷進攻, 4位判斷撤退, 還有2個間諜惡意判斷撤退, 雖然結果是錯誤的撤退, 但這種情況完全是允許的. 因為這11位將軍依然保持著狀態一致性。
-
一致性解決方案
-
2PC和3PC
-
2PC
第一階段:準備階段(投票階段)和第二階段:提交階段(執行階段)。
-
3PC
在第一階段和第二階段中插入一個準備階段。保證了在最後提交階段之前各參與節點的狀態是一致的。引入超時機制,同時在協調者和參與者中都引入超時機制。
-
區別
相對於2PC,3PC主要解決的單點故障問題,並減少阻塞,因為一旦參與者無法及時收到來自協調者的資訊之後,他會預設執行commit。而不會一直持有事務資源並處於阻塞狀態。但是這種機制也會導致資料一致性問題,因為,由於網路原因,協調者傳送的abort響應沒有及時被參與者接收到,那麼參與者在等待超時之後執行了commit操作。這樣就和其他接到abort命令並執行回滾的參與者之間存在資料不一致的情況。
-
總結
無論是二階段提交還是三階段提交都無法徹底解決分散式的一致性問題。那麼世上只有一種一致性演算法,那就是Paxos,所有其他一致性演算法都是Paxos演算法的不完整版。
-
-
Paxos
-
-
-
ZAB原子廣播(資料一致原理)
paxos理論到實際是個艱難的過程。比如怎樣在分散式環境下維持一個全域性唯一遞增的序列,如果是靠資料庫的自增主鍵,那麼整個系統的穩定和效能的瓶頸全都集中於這個單點。paxos演算法也沒有限制Proposer的個數,Proposer個數越多,那麼達成一致所造成的碰撞將越多,甚至產生活鎖,如果限制Proposer的個數為一個,那麼就要考慮唯一的Proposer崩潰要怎麼處理。
-
工作步驟
- leader從客戶端收到一個寫請求
- leader生成一個新的事務併為這個事務生成一個唯一的ZXID,
- leader將這個事務傳送給所有的follows節點
- follower節點將收到的事務請求加入到歷史佇列(history queue)中,併傳送ack給ack給leader
- 當leader收到大多數follower(超過法定數量)的ack訊息,leader會傳送commit請求
- 當follower收到commit請求時,會判斷該事務的ZXID是不是比歷史佇列中的任何事務的ZXID都小,如果是則提交,如果不是則等待比它更小的事務的commit.
-
-
擴充套件
- Client-java
- Curator
Curator是Netflix公司開源的一套Zookeeper客戶端框架。瞭解過Zookeeper原生API都會清楚其複雜度。Curator幫助我們在其基礎上進行封裝、實現一些開發細節,包括接連重連、反覆註冊Watcher和NodeExistsException等。
-
整體回顧
-
思考問題
- 一個客戶端修改了某個節點的資料,其它客戶端能夠馬上獲取到這個最新資料嗎(跨客戶端檢視的併發一致性)
- 叢集中clientPort不一致,可以等了解了讀寫機制理解
- observer是怎麼設定的
- zxid溢位變成負數了怎麼辦
- 水平擴容
- zookeeper 有哪些缺點
- 資料量大,同步慢,超時
reference
- ZooKeeper基本原理
- 原始碼Zookeeper 叢集版建立連線過程
- ZooKeeper解惑
- ZooKeeper FAQ
- Zookeeper會話
- zookeeper curator處理會話過期session expired
- zookeeper之資料模型
- ZooKeeper session管理
- ZooKeeper的Znode剖析
- ZooKeeper資料一致性
- 一直對zookeeper的應用和原理比較迷糊,今天看一篇文章,講得很通透
- Zookeeper - CLI
- 分散式一致性原理、Paxos演算法與Zookeeper的ZAB協議、Zookeeper使用場景與在電商系統中的應用
- 關於若干選舉演算法的解釋與實現
- Zookeeper的FastLeaderElection演算法分析
- 深入淺出Zookeeper(一) Zookeeper架構及FastLeaderElection機制
- 聊聊zookeeper的ZAB演算法
- ZAB協議的那些事?
- ZooKeeper典型應用場景一覽
- Zookeeper的sync操作是什麼?
- ZAB協議詳解
- Zookeeper請求處理
- zookeeper leader和learner的資料同步
- 品味ZooKeeper之Watcher機制
- 關於分散式事務、兩階段提交協議、三階提交協議
- 分散式系統的一致性協議之 2PC 和 3PC
- 2PC/3PC、paxos與ZAB協議
- Zookeeper資料與儲存