背景
一切的恐懼,且來源于火力不足
假如有人問題如下問題,你能回答上來嗎?如果你能回答上來,那么你可以跳過本文。如何回答不了,本文將給你答案。
-
- 按順序啟動Zookeeper集群,Leader會是哪個結(jié)點?
-
- ZooKeeper的應(yīng)用場景有哪些?
-
- ZooKeeper如何保證數(shù)據(jù)的一致性?
-
- ZooKeeper的節(jié)點有哪些類型?
-
- ZooKeeper的數(shù)據(jù)模型是什么?
架構(gòu)圖
集群模式詳解
Zookeeper概述
客戶端連接到單個ZooKeeper服務(wù)器。客戶端維護一個TCP連接,通過該連接發(fā)送請求、獲取響應(yīng)、獲取監(jiān)視事件和發(fā)送檢測信號。如果與服務(wù)器的TCP連接中斷,客戶端將連接到其他服務(wù)器。
訂購了ZooKeeper。ZooKeeper在每次更新時都會使用一個數(shù)字來標(biāo)記,該數(shù)字反映了所有ZooKeeper事務(wù)的順序。后續(xù)操作可以使用該順序來實現(xiàn)更高級別的抽象,例如同步基元。
ZooKeeper速度很快。在“讀取主導(dǎo)”工作負(fù)載中,它的速度尤其快。ZooKeeper應(yīng)用程序在數(shù)千臺機器上運行,在讀取比寫入更常見的情況下,它的性能最佳,比率約為10:1。
數(shù)據(jù)模型和分層命名空間
ZooKeeper 提供的命名空間與標(biāo)準(zhǔn)文件系統(tǒng)的命名空間非常相似。名稱是一系列由斜杠 (/) 分隔的路徑元素。ZooKeeper 命名空間中的每個節(jié)點都由路徑標(biāo)識。
永久節(jié)點和臨時節(jié)點
Znodes 維護一個統(tǒng)計信息結(jié)構(gòu),其中包括數(shù)據(jù)更改、ACL 更改和時間戳的版本號,以允許緩存驗證和協(xié)調(diào)更新。每當(dāng) znode 的數(shù)據(jù)發(fā)生變化時,版本號就會增加。例如,每當(dāng)客戶端檢索數(shù)據(jù)時,它也會接收數(shù)據(jù)的版本。
存儲在命名空間中每個 znode 的數(shù)據(jù)都是以原子方式讀取和寫入的。讀取獲取與 znode 關(guān)聯(lián)的所有數(shù)據(jù)字節(jié),寫入替換所有數(shù)據(jù)。每個節(jié)點都有一個訪問控制列表 (ACL),用于限制誰可以執(zhí)行哪些操作。
ZooKeeper 也有臨時節(jié)點的概念。只要創(chuàng)建 znode 的會話處于活動狀態(tài),這些 znode 就存在。會話結(jié)束時,znode 將被刪除。
條件更新和監(jiān)視
ZooKeeper 支持watches的概念。客戶端可以在 znode 上設(shè)置監(jiān)視。當(dāng) znode 發(fā)生變化時,將觸發(fā)并刪除監(jiān)視。當(dāng)監(jiān)視被觸發(fā)時,客戶端會收到一個數(shù)據(jù)包,指出 znode 已更改。如果客戶端與其中一個 ZooKeeper 服務(wù)器之間的連接斷開,客戶端將收到本地通知。
保證
ZooKeeper非常快速且非常簡單。但是,由于它的目標(biāo)是成為構(gòu)建更復(fù)雜服務(wù)(例如同步)的基礎(chǔ),因此它提供了一組保證。這些是:
- 順序一致性-來自客戶端的更新將按發(fā)送順序應(yīng)用。
- 原子性-更新成功或失敗。沒有部分結(jié)果。
- 單個系統(tǒng)映像-無論客戶端連接到哪個服務(wù)器,它都將看到相同的服務(wù)視圖。也就是說,即使客戶* 端故障轉(zhuǎn)移到具有相同會話的其他服務(wù)器,客戶端也永遠不會看到系統(tǒng)的舊視圖。
- 可靠性-應(yīng)用更新后,它將從那時起一直存在,直到客戶端覆蓋更新。
- 及時性-保證在一定時間范圍內(nèi),客戶端對系統(tǒng)的看法是最新的。
簡單的API
ZooKeeper的設(shè)計目標(biāo)之一是提供一個非常簡單的編程接口。因此,它僅支持以下操作:
創(chuàng)建:在樹中的某個位置創(chuàng)建一個節(jié)點
delete:刪除節(jié)點
exists:測試某個位置是否存在節(jié)點
獲取數(shù)據(jù):從節(jié)點讀取數(shù)據(jù)
setdata:將數(shù)據(jù)寫入節(jié)點
GetChildren:檢索節(jié)點的子節(jié)點列表
sync:等待數(shù)據(jù)傳播
Zookeeper集群
跨計算機要求
要使 ZooKeeper 服務(wù)處于活動狀態(tài),必須有大多數(shù)可以相互通信的非故障計算機。對于具有 N 臺服務(wù)器的 ZooKeeper 集成,如果 N 為奇數(shù),則集成能夠容忍多達 N/2 個服務(wù)器故障,而不會丟失任何 znode 數(shù)據(jù);如果 N 為偶數(shù),則集成最多能夠容忍 N/2-1 個服務(wù)器故障。
領(lǐng)導(dǎo)人選舉
ZooKeeper 進行 leader 選舉使用一種簡單方法是使用 SEQUENCE|創(chuàng)建代表客戶“建議”的 znode 時的臨時標(biāo)志。這個想法是有一個 znode,比如 “/election”,這樣每個 znode 創(chuàng)建一個子 znode “/election/guid-n_”,兩個標(biāo)志都是 SEQUENCE|短暫的。使用序列標(biāo)志,ZooKeeper 會自動附加一個序列號,該序列號大于之前附加到“/election”子項的序列號。創(chuàng)建具有最小附加序列號的 znode 的進程是領(lǐng)導(dǎo)者。
群集選項
本節(jié)中的選項設(shè)計用于服務(wù)器集合,即在部署服務(wù)器群集時。
-
electionAlg :(無 Java 系統(tǒng)屬性)要使用的選舉實現(xiàn)。值“1”對應(yīng)于未經(jīng)身份驗證的基于 UDP 的快速領(lǐng)導(dǎo)者選舉版本,“2”對應(yīng)于經(jīng)過身份驗證的基于 UDP 的快速領(lǐng)導(dǎo)者選舉版本,“3”對應(yīng)于基于 TCP 的快速領(lǐng)導(dǎo)者選舉版本。算法 3 在 3.2.0 中是默認(rèn)的,以前的版本(3.0.0 和 3.1.0)也使用算法 1 和 2。
注意
領(lǐng)導(dǎo)者選舉 1 和 2 的實現(xiàn)在 3.4.0 中已棄用。由于 3.6.0 只有 FastLeaderElection 可用,因此在升級時,您必須關(guān)閉所有服務(wù)器并使用 electionAlg=3 重新啟動它們(或從配置文件中刪除該行)。> -
maxTimeToWaitForEpoch : (Java 系統(tǒng)屬性: zookeeper.leader.maxTimeToWaitForEpoch) 3.6.0 中的新功能:激活領(lǐng)導(dǎo)者時等待投票者 epoch 的最長時間。如果領(lǐng)導(dǎo)者收到來自其投票者之一的 LOOKING 通知,并且它沒有收到來自 maxTimeToWaitForEpoch 內(nèi)多數(shù)人的紀(jì)元數(shù)據(jù)包,則它將轉(zhuǎn)到 LOOKING 并再次選舉領(lǐng)導(dǎo)者。這可以進行調(diào)整以減少仲裁或服務(wù)器不可用時間,它可以設(shè)置為比 initLimit * tickTime 小得多。在跨數(shù)據(jù)中心環(huán)境中,可以將其設(shè)置為類似 2 秒的值。
initLimit :(無 Java 系統(tǒng)屬性)允許追隨者連接并同步到領(lǐng)導(dǎo)者的時間量,以刻度為單位(參見 tickTime)。如果 ZooKeeper 管理的數(shù)據(jù)量很大,則根據(jù)需要增加此值。 -
connectToLearnerMasterLimit :(Java 系統(tǒng)屬性:zookeeper。connectToLearnerMasterLimit) 允許關(guān)注者在領(lǐng)導(dǎo)者選舉后連接到領(lǐng)導(dǎo)者的時間量(以刻度為單位)(參見 tickTime)。默認(rèn)值為 initLimit。當(dāng) initLimit 較高時使用,因此連接到學(xué)習(xí)器主節(jié)點不會導(dǎo)致更高的超時。
-
leaderServe :(Java 系統(tǒng)屬性:zookeeper。leaderServes) Leader 接受客戶端連接。默認(rèn)值為“yes”。主計算機協(xié)調(diào)更新。為了以略有讀取吞吐量為代價獲得更高的更新吞吐量,可以將領(lǐng)導(dǎo)者配置為不接受客戶端并專注于協(xié)調(diào)。此選項的默認(rèn)值為 yes,這意味著領(lǐng)導(dǎo)者將接受客戶端連接。
注意
當(dāng)一個集合中有三個以上的 ZooKeeper 服務(wù)器時,強烈建議打開領(lǐng)導(dǎo)者選擇。 -
server.x=[hostname]:nnnnn[:nnnnn] etc : (無 Java 系統(tǒng)屬性)構(gòu)成 ZooKeeper 集合的服務(wù)器。當(dāng)服務(wù)器啟動時,它通過在數(shù)據(jù)目錄中查找文件 myid 來確定它是哪個服務(wù)器。該文件包含 ASCII 格式的服務(wù)器編號,并且應(yīng)與此設(shè)置左側(cè)的 server.x 中的 x 匹配??蛻舳耸褂玫臉?gòu)成 ZooKeeper 服務(wù)器的服務(wù)器列表必須與每個 ZooKeeper 服務(wù)器擁有的 ZooKeeper 服務(wù)器列表匹配。有兩個端口號 nnnnn。第一個追隨者用于與領(lǐng)導(dǎo)者建立聯(lián)系,第二個追隨者用于領(lǐng)導(dǎo)者選舉。如果要在一臺計算機上測試多個服務(wù)器,則可以對每個服務(wù)器使用不同的端口。
從 ZooKeeper 3.6.0 開始,可以為每個 ZooKeeper 服務(wù)器指定多個地址(參見 ZOOKEEPER-3188)。要啟用此功能,必須將 multiAddress.enabled 配置屬性設(shè)置為 true。這有助于提高可用性,并為 ZooKeeper 增加網(wǎng)絡(luò)級別的彈性。當(dāng)服務(wù)器使用多個物理網(wǎng)絡(luò)接口時,ZooKeeper 能夠在所有接口上綁定,并在發(fā)生網(wǎng)絡(luò)錯誤時運行時切換到工作接口??梢栽谂渲弥惺褂秘Q線 (‘|’) 字符指定不同的地址。使用多個地址的有效配置如下所示:
server.1=zoo1-net1:2888:3888|zoo1-net2:2889:3889
server.2=zoo2-net1:2888:3888|zoo2-net2:2889:3889
server.3=zoo3-net1:2888:3888|zoo3-net2:2889:3889
注意
啟用此功能后,仲裁協(xié)議(ZooKeeper Server-Server 協(xié)議)將發(fā)生變化。用戶不會注意到這一點,當(dāng)任何人使用新配置啟動 ZooKeeper 集群時,一切都會正常工作。但是,如果舊的 ZooKeeper 群集不支持 multiAddress 功能(和新的仲裁協(xié)議),則無法在滾動升級期間啟用此功能并指定多個地址。如果您需要此功能,但還需要從低于 3.6.0 的 ZooKeeper 集群執(zhí)行滾動升級,則首先需要在不啟用 MultiAddress 功能的情況下進行滾動升級,然后使用新配置進行單獨的滾動重啟,其中 multiAddress.enabled 設(shè)置為 true 并提供多個地址。
-
syncLimit :(無 Java 系統(tǒng)屬性)允許關(guān)注者與 ZooKeeper 同步的時間量,以刻度為單位(參見 tickTime)。如果追隨者落后于領(lǐng)導(dǎo)者太遠,他們就會被放棄。
group.x=nnnnn[:nnnnn] : (無 Java 系統(tǒng)屬性)啟用分層仲裁構(gòu)造。x“是組標(biāo)識符,”=“符號后面的數(shù)字對應(yīng)于服務(wù)器標(biāo)識符。分配的左側(cè)是以冒號分隔的服務(wù)器標(biāo)識符列表。請注意,組必須是不相交的,并且所有組的并集必須是 ZooKeeper 集合。你可以在這里找到一個例子 -
weight.x=nnnnn :(無 Java 系統(tǒng)屬性)與“group”一起使用,在形成仲裁時為服務(wù)器分配權(quán)重。這樣的值對應(yīng)于投票時服務(wù)器的權(quán)重。ZooKeeper 有幾個部分需要投票,例如領(lǐng)導(dǎo)者選舉和原子廣播協(xié)議。默認(rèn)情況下,服務(wù)器的權(quán)重為 1。如果配置定義了組,但未定義權(quán)重,則值 1 將分配給所有服務(wù)器。你可以在這里找到一個例子
-
cnxTimeout :(Java 系統(tǒng)屬性:zookeeper。cnxTimeout) 設(shè)置為領(lǐng)導(dǎo)者選舉通知打開連接的超時值。僅當(dāng)您使用 electionAlg 3 時才適用。默認(rèn)值為 5 秒。
-
quorumCnxnTimeoutMs :(Java 系統(tǒng)屬性:zookeeper。quorumCnxnTimeoutMs) 設(shè)置領(lǐng)導(dǎo)者選舉通知的連接的讀取超時值。僅當(dāng)您使用 electionAlg 3 時才適用。默認(rèn)值為 -1,然后使用 syncLimit * tickTime 作為超時。
-
standaloneEnabled :(無 Java 系統(tǒng)屬性) 3.5.0 中的新增功能:設(shè)置為 false 時,可以在復(fù)制模式下啟動單個服務(wù)器,單獨的參與者可以使用觀察者運行,并且集群可以重新配置到一個節(jié)點,然后從一個節(jié)點向上配置。默認(rèn)值為 true,以實現(xiàn)向后兼容性??梢允褂?QuorumPeerConfig 的 setStandaloneEnabled 方法或通過將“standaloneEnabled=false”或“standaloneEnabled=true”添加到服務(wù)器的配置文件來設(shè)置它。
-
reconfigEnabled :(無 Java 系統(tǒng)屬性)3.5.3 中的新增功能:這控制動態(tài)重新配置功能的啟用或禁用。啟用該功能后,用戶可以通過 ZooKeeper 客戶端 API 或通過 ZooKeeper 命令行工具執(zhí)行重新配置操作,前提是用戶有權(quán)執(zhí)行此類操作。禁用該功能后,任何用戶(包括超級用戶)都無法執(zhí)行重新配置。任何重新配置的嘗試都將返回錯誤?!皉econfigEnabled”選項可以設(shè)置為服務(wù)器配置文件的“reconfigEnabled=false”或“reconfigEnabled=true”,或使用QuorumPeerConfig的setReconfigEnabled方法。默認(rèn)值為 false。如果存在,則該值應(yīng)在整個整體中的每個服務(wù)器上保持一致。在某些服務(wù)器上將該值設(shè)置為 true,在其他服務(wù)器上將該值設(shè)置為 false 將導(dǎo)致不一致的行為,具體取決于被選為領(lǐng)導(dǎo)者的服務(wù)器。如果領(lǐng)導(dǎo)者的設(shè)置為“reconfigEnabled=true”,則集合將啟用重新配置功能。如果領(lǐng)導(dǎo)者的設(shè)置為“reconfigEnabled=false”,則集合將禁用重新配置功能。因此,建議在整體中的服務(wù)器之間使用一致的“reconfigEnabled”值。
-
4lw.commands.whitelist :(Java 系統(tǒng)屬性:zookeeper.4lw.commands.whitelist) 3.5.3 中的新功能:用戶想要使用的逗號分隔的四個字母單詞命令列表。必須在此列表中放置有效的四個字母單詞命令,否則 ZooKeeper 服務(wù)器將不會啟用該命令。默認(rèn)情況下,白名單僅包含 zkServer.sh 使用的“srvr”命令。默認(rèn)情況下,其余的四個字母的單詞命令處于禁用狀態(tài):嘗試使用它們將獲得響應(yīng)“…未執(zhí)行,因為它不在白名單中。下面是一個配置示例,該配置啟用 stat、ruok、conf 和 isro 命令,同時禁用 Four Letter Words 命令的其余部分:
4lw.commands.whitelist=stat, ruok, conf, isro
zxid 由兩部分組成:紀(jì)元和計數(shù)器。在我們的實現(xiàn)中,zxid 是一個 64 位數(shù)字。我們使用高階 32 位作為紀(jì)元,使用低階 32 位作為計數(shù)器。由于 zxid 由兩部分組成,因此 zxid 既可以表示為數(shù)字,也可以表示為一對整數(shù)(epoch、count)。紀(jì)元數(shù)字代表領(lǐng)導(dǎo)層的變化。每當(dāng)新領(lǐng)導(dǎo)人上臺時,它都會有自己的紀(jì)元。我們有一個簡單的算法來為提案分配一個唯一的 zxid:領(lǐng)導(dǎo)者只需遞增 zxid 即可為每個提案獲得一個唯一的 zxid。領(lǐng)導(dǎo)力激活將確保只有一個領(lǐng)導(dǎo)者使用給定的紀(jì)元,因此我們的簡單算法可以保證每個提案都有一個唯一的 ID。
ZooKeeper 消息傳遞包括兩個階段:
-
領(lǐng)導(dǎo)者激活 :在此階段,領(lǐng)導(dǎo)者建立系統(tǒng)的正確狀態(tài)并準(zhǔn)備開始提出建議。
-
主動消息傳遞 :在此階段,領(lǐng)導(dǎo)者接受要建議的消息并協(xié)調(diào)消息傳遞。
如何查看 ZK 集群中的角色
./bin/zkServer.sh status conf/zoo.cfg
可以看到,其中節(jié)點 2 為 leader,其他的為 follower。但是如果你按照 zoo1.cfg,zoo2.cfg,zoo3.cfg 的順序啟動,無論你啟動多少遍,節(jié)點 2 總是 leader,而這時如果把節(jié)點 2 關(guān)掉,進行查看角色,發(fā)現(xiàn)節(jié)點 3 成了 leader。
zk集群選舉過程
zk 會進行多輪的投票,直到某一個節(jié)點的票數(shù)大于或等于半數(shù)以上,在 3 個節(jié)點中,總共會進行 2 輪的投票:
- 第一輪,每個節(jié)點啟動時投票給自己,那這樣 zk1,zk2,zk3 各有一票。
- 第二輪,每個節(jié)點投票給大于自己 myid,那這樣 zk2 啟動時又獲得一票。加上自己給自己投的那一票??偣灿?2 票。2 票大于了當(dāng)前節(jié)點總數(shù)的半數(shù),所以投票終止。zk2 當(dāng)選 leader。
正常客戶端數(shù)據(jù)提交流程
客戶端寫入數(shù)據(jù)提交流程大致為:leader 接受到客戶端的寫請求,然后同步給各個子節(jié)點:
客戶端會和所有的節(jié)點建立鏈接,并且發(fā)起寫入請求是挨個遍歷節(jié)點進行的,比如第一次是節(jié)點 1,第二次是節(jié)點 2。
以此類推。
如果客戶端正好鏈接的節(jié)點的角色是 leader,那就按照上面的流程走。
那如果鏈接的節(jié)點不是 leader,是 follower 呢,則有以下流程:
如果 Client 選擇鏈接的節(jié)點是 Follower 的話,這個 Follower 會把請求轉(zhuǎn)給當(dāng)前 Leader,然后 Leader 會走藍色的線把請求廣播給所有的 Follower,每個節(jié)點同步完數(shù)據(jù)后會走綠色的線告訴 Leader 數(shù)據(jù)已經(jīng)同步完成(但是還未提交)。
當(dāng) Leader 收到半數(shù)以上的節(jié)點 ACK 確認(rèn)消息后,那么 Leader 就認(rèn)為這個數(shù)據(jù)可以提交了,會廣播給所有的 Follower 節(jié)點,所有的節(jié)點就可以提交數(shù)據(jù)。
整個同步工作就結(jié)束了。
ZK 中的過期數(shù)據(jù)選舉
假設(shè)還是有一個 3 個節(jié)點的集群,zk2 為 Leader,這時候如果 zk2 掛了。zk3 當(dāng)選 Leader,zk1 為 Follower。這時候如果更新集群中的一個數(shù)據(jù)。
然后把 zk1 和 zk3 都關(guān)閉。然后挨個再重啟 zk1,zk2,zk3。這時候啟動后,zk2 還能當(dāng)選為 Leader 嗎?
其實這個問題,換句話說就是:在挨個啟動 zk 節(jié)點的時候,zk1 和 zk3 的數(shù)據(jù)為最新,而 zk2 的數(shù)據(jù)不是最新的,按照之前的選舉規(guī)則的話,zk2 是否能順利當(dāng)選 Leader?
答案為否,最后當(dāng)選的為 zk1。
這是為什么呢。文章來源:http://www.zghlxwxcb.cn/news/detail-823548.html
因為 zk2 的最新 ZXID 已經(jīng)不是最新了,zk 的選舉過程會優(yōu)先考慮 ZXID 大的節(jié)點。這時 ZXID 最大的有 zk1 和 zk3,選舉只會在這 2 個節(jié)點中產(chǎn)生,根據(jù)之前說的選舉規(guī)則。在第一輪投票的時候,zk1 只要獲得 1 票,就能達到半數(shù)了,就能順利當(dāng)選為 Leader 了。文章來源地址http://www.zghlxwxcb.cn/news/detail-823548.html
參考文章
- zookeeper官網(wǎng)
到了這里,關(guān)于Zookeeper架構(gòu)系列——集群模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!