《面試八股文》之Zookeeper12卷
微信公眾號(hào):moon聊技術(shù)
關(guān)注選擇“ 星標(biāo) ”, 重磅干貨,第一 時(shí)間送達(dá)!
[如果你覺(jué)得文章對(duì)你有幫助,歡迎關(guān)注,在看,點(diǎn)贊,轉(zhuǎn)發(fā)]

其他《面試八股文》系列文章請(qǐng)關(guān)注公號(hào)moon聊技術(shù)獲取~
每天一個(gè)知識(shí)點(diǎn)
多想,多思考,多溝通,多交流
目錄
1.Zookeeper 是什么?能做什么?
2.說(shuō)說(shuō) Zookeeper 的數(shù)據(jù)結(jié)構(gòu)吧
3.Znode里面都存儲(chǔ)了什么?
4.Zookeeper 的系統(tǒng)架構(gòu)又是怎么樣的?
5.那你繼續(xù)給我講講 ZAB 協(xié)議吧
6.Zookeeper初始化是如何進(jìn)行Leader選舉的?
7.如果Leader掛了,進(jìn)入崩潰恢復(fù),怎么選舉Leader?
8.說(shuō)說(shuō)Wather監(jiān)聽(tīng)機(jī)制和它的原理?
9.Zookeeper有哪些特性呢?
10.Zookeeper 如何識(shí)別請(qǐng)求的先后順序?
11.選舉 leader 后是怎么進(jìn)行數(shù)據(jù)同步的
12.Zookeeper 會(huì)有數(shù)據(jù)不一致的情況發(fā)生嗎?
1.Zookeeper 是什么?能做什么?
Zookeeper 是一個(gè)開(kāi)源的,是用于維護(hù)配置信息,命名,提供分布式同步和提供組服務(wù)的集中式服務(wù)。

可以基于 Zookeeper 實(shí)現(xiàn)諸如數(shù)據(jù)發(fā)布/訂閱、負(fù)載均衡、命名服務(wù)、分布式協(xié)調(diào)/通知、集群管理、Master 選舉、分布式鎖和分布式隊(duì)列等功能。

Zookeeper 最常用的一個(gè)使用場(chǎng)景就是作為注冊(cè)中心,生產(chǎn)者將自己提供的服務(wù)注冊(cè)到 Zookeeper,然后消費(fèi)者從 Zookeeper 中拿到生產(chǎn)者的服務(wù)列表信息,然后再去調(diào)用生產(chǎn)者的內(nèi)容數(shù)據(jù),比如 Dubbo,Kafka 都是使用 Zookeeper 作為注冊(cè)中心的。
2.說(shuō)說(shuō) Zookeeper 的數(shù)據(jù)結(jié)構(gòu)吧

ZooKeeper 提供的名稱(chēng)空間與標(biāo)準(zhǔn)文件系統(tǒng)的名稱(chēng)空間非常相似。名稱(chēng)是由斜杠(“ /”)分隔的一系列路徑元素。ZooKeeper 命名空間中的每個(gè) znode 均由路徑標(biāo)識(shí)。每個(gè) znode 都有一個(gè)父對(duì)象,其路徑是 znode 的前綴,元素少一個(gè);此規(guī)則的例外是 root(“ /”),它沒(méi)有父項(xiàng)。此外,與標(biāo)準(zhǔn)文件系統(tǒng)完全一樣,如果 znode 有子節(jié)點(diǎn),則無(wú)法刪除它。
ZooKeeper 與標(biāo)準(zhǔn)文件系統(tǒng)之間的主要區(qū)別在于,每個(gè) znode 都可以具有與之關(guān)聯(lián)的數(shù)據(jù)(每個(gè)文件也可以是目錄,反之亦然),并且 znode 限于它們可以擁有的數(shù)據(jù)量。ZooKeeper 旨在存儲(chǔ)協(xié)調(diào)數(shù)據(jù):狀態(tài)信息,配置,位置信息等。這種元信息通常以千字節(jié)(如果不是字節(jié))來(lái)度量。ZooKeeper 具有1M的內(nèi)置完整性檢查,以防止將其用作大型數(shù)據(jù)存儲(chǔ),但是通常,它用于存儲(chǔ)小得多的數(shù)據(jù)。

Znode的三種類(lèi)型:
持久節(jié)點(diǎn)(persistent node)節(jié)點(diǎn)會(huì)被持久 臨時(shí)節(jié)點(diǎn)(ephemeral node),客戶(hù)端斷開(kāi)連接后,ZooKeeper 會(huì)自動(dòng)刪除臨時(shí)節(jié)點(diǎn) 順序節(jié)點(diǎn)(sequential node),每次創(chuàng)建順序節(jié)點(diǎn)時(shí),ZooKeeper 都會(huì)在路徑后面自動(dòng)添加上10位的數(shù)字,從1開(kāi)始,最大是2147483647 (2^32-1)

Znode的四種形式:
持久節(jié)點(diǎn):如 create /test/a "hello",通過(guò) create 參數(shù)指定為持久節(jié)點(diǎn) 持久順序節(jié)點(diǎn):通過(guò) create -s 參數(shù)指定為順序節(jié)點(diǎn) 臨時(shí)節(jié)點(diǎn):通過(guò) create -e 參數(shù)指定為順序節(jié)點(diǎn) 臨時(shí)順序節(jié)點(diǎn):通過(guò) create -s -e 參數(shù)指定為臨時(shí)及順序節(jié)點(diǎn)
3.Znode里面都存儲(chǔ)了什么?
Znode包含了存儲(chǔ)數(shù)據(jù)(data)、訪問(wèn)權(quán)限(acl)、子節(jié)點(diǎn)引用(child)、節(jié)點(diǎn)狀態(tài)信息(stat)

data: znode存儲(chǔ)的業(yè)務(wù)數(shù)據(jù)信息 acl: 記錄客戶(hù)端對(duì)znode節(jié)點(diǎn)的訪問(wèn)權(quán)限,如IP等。 child: 當(dāng)前節(jié)點(diǎn)的子節(jié)點(diǎn)引用 stat: 包含Znode節(jié)點(diǎn)的狀態(tài)信息,比如事務(wù)id、版本號(hào)、時(shí)間戳等等。
4.Zookeeper 的系統(tǒng)架構(gòu)又是怎么樣的?

ZooKeeper 分為服務(wù)器端(Server) 和客戶(hù)端(Client),客戶(hù)端可以連接到整個(gè) ZooKeeper 服務(wù)的任意服務(wù)器上(除非 leaderServes 參數(shù)被顯式設(shè)置,leader 不允許接受客戶(hù)端連接),客戶(hù)端使用并維護(hù)一個(gè) TCP 連接,通過(guò)這個(gè)連接發(fā)送請(qǐng)求、接受響應(yīng)、獲取觀察的事件以及發(fā)送信息。
組成 ZooKeeper 服務(wù)的服務(wù)器必須彼此了解。它們維護(hù)一個(gè)內(nèi)存中的狀態(tài)圖像,以及持久存儲(chǔ)中的事務(wù)日志和快照,只要大多數(shù)服務(wù)器可用,ZooKeeper 服務(wù)就可用;

Zookeeper 集群中Server有三種角色,Leader、Follower 和 Observer
Leader:負(fù)責(zé)投投票的發(fā)起與決議,更新系統(tǒng)狀態(tài),寫(xiě)數(shù)據(jù) Follower:用于接收客戶(hù)端請(qǐng)求并用來(lái)返回結(jié)果,在選主過(guò)程中參與投票 Observer:可以接受客戶(hù)端連接,將寫(xiě)請(qǐng)求轉(zhuǎn)發(fā)給leader節(jié)點(diǎn),但是不參與投票過(guò)程,只同步leader狀態(tài),主要存在目的就是為了提高讀取效率
將 server 分為三種是為了避免太多的從節(jié)點(diǎn)參與過(guò)半寫(xiě)的過(guò)程,導(dǎo)致影響性能,這樣 Zookeeper 只要使用一個(gè)幾臺(tái)機(jī)器的小集群就可以實(shí)現(xiàn)高性能了,如果要橫向擴(kuò)展的話,只需要增加 Observer 節(jié)點(diǎn)即可。
Zookeeper 建議集群節(jié)點(diǎn)個(gè)數(shù)為奇數(shù),只要超過(guò)一半的機(jī)器能夠正常提供服務(wù),那么整個(gè)集群都是可用的狀態(tài)。
ZooKeeper 啟動(dòng)時(shí),將從實(shí)例中選舉一個(gè) leader,Leader 負(fù)責(zé)處理數(shù)據(jù)更新等操作,一個(gè)更新操作成功的標(biāo)志是當(dāng)且僅當(dāng)大多數(shù) Server 在內(nèi)存中成功修改數(shù)據(jù)。每個(gè) Server 在內(nèi)存中存儲(chǔ)了一份數(shù)據(jù)。
Zookeeper 的數(shù)據(jù)一致性是依靠ZAB協(xié)議完成的。
5.那你繼續(xù)給我講講 ZAB 協(xié)議吧
ZAB(ZooKeeper Atomic Broadcast 原子廣播) 協(xié)議是為 ZooKeeper 特殊設(shè)計(jì)的一種支持崩潰恢復(fù)的原子廣播協(xié)議。在 ZooKeeper 中,主要依賴(lài) ZAB 協(xié)議來(lái)實(shí)現(xiàn)分布式數(shù)據(jù)一致性,基于該協(xié)議,ZooKeeper 實(shí)現(xiàn)了一種主備模式的系統(tǒng)架構(gòu)來(lái)保持集群中各個(gè)副本之間的數(shù)據(jù)一致性。
ZAB 協(xié)議包括有兩種模式,分別是 崩潰恢復(fù)和消息廣播。
崩潰恢復(fù):當(dāng)整個(gè)服務(wù)框架在啟動(dòng)過(guò)程中,或是當(dāng) Leader 服務(wù)器出現(xiàn)網(wǎng)絡(luò)中斷、崩潰退出與重啟等異常情況時(shí),ZAB 協(xié)議就會(huì)進(jìn)人恢復(fù)模式并選舉產(chǎn)生新的 Leader 服務(wù)器。當(dāng)選舉產(chǎn)生了新的 Leader 服務(wù)器,同時(shí)集群中已經(jīng)有過(guò)半的機(jī)器與該 Leader 服務(wù)器完成了狀態(tài)同步之后,ZAB 協(xié)議就會(huì)退出恢復(fù)模式。剩下未同步完成的機(jī)器會(huì)繼續(xù)同步,直到同步完成并加入集群后該節(jié)點(diǎn)的服務(wù)才可用。
消息廣播:當(dāng)集群中已經(jīng)有過(guò)半的 Follower 服務(wù)器完成了和 Leader 服務(wù)器的狀態(tài)同步,那么整個(gè)服務(wù)框架就可以進(jìn)人消息廣播模式了。當(dāng)一臺(tái)同樣遵守 ZAB 協(xié)議的服務(wù)器啟動(dòng)后加人到集群中時(shí),如果此時(shí)集群中已經(jīng)存在一個(gè) Leader 服務(wù)器在負(fù)責(zé)進(jìn)行消息廣播,那么新加人的服務(wù)器就會(huì)自覺(jué)地進(jìn)人數(shù)據(jù)恢復(fù)模式:找到 Leader 所在的服務(wù)器,并與其進(jìn)行數(shù)據(jù)同步,然后一起參與到消息廣播流程中去。ZooKeeper 設(shè)計(jì)成只允許唯一的一個(gè) Leader 服務(wù)器來(lái)進(jìn)行事務(wù)請(qǐng)求的處理。Leader 服務(wù)器在接收到客戶(hù)端的事務(wù)請(qǐng)求后,會(huì)生成對(duì)應(yīng)的事務(wù)提案并發(fā)起一輪廣播協(xié)議;而如果集群中的其他機(jī)器接收到客戶(hù)端的事務(wù)請(qǐng)求,那么這些非 Leader 服務(wù)器會(huì)首先將這個(gè)事務(wù)請(qǐng)求轉(zhuǎn)發(fā)給 Leader 服務(wù)器。
6.Zookeeper初始化是如何進(jìn)行Leader選舉的?

在集群初始化階段,只有兩臺(tái)以以上的 ZK 啟動(dòng)才會(huì)發(fā)生leader選舉,過(guò)程如下:
(1) 每個(gè) Server 發(fā)出一個(gè)投票。初始選舉 ZK1 和 ZK2 都會(huì)將自己作為 Leader 服務(wù)器來(lái)進(jìn)行投票,每次投票會(huì)包含所推舉的服務(wù)器的(myid, ZXID),此時(shí) ZK1 的投票為(1, 0),ZK2 的投票為(2, 0),然后各自將這個(gè)投票發(fā)給集群中其他機(jī)器。
(2) 收到投票。集群的每個(gè)服務(wù)器收到投票后,首先判斷該投票的有效性,如檢查是否是本輪投票、是否來(lái)自 LOOKING 狀態(tài)的服務(wù)器。
(3) 處理投票。每個(gè)發(fā)起投票的服務(wù)器需要將別人的投票和自己的投票進(jìn)行比較,規(guī)則如下:
優(yōu)先檢查 ZXID。ZXID 比較大的服務(wù)器優(yōu)先作為 Leader。如果 ZXID 相同,那么就比較 myid。myid 較大的服務(wù)器作為L(zhǎng)eader服務(wù)器。 (4) 統(tǒng)計(jì)投票。每次投票后,服務(wù)器都會(huì)統(tǒng)計(jì)投票信息,判斷是否已經(jīng)有過(guò)半機(jī)器接受到相同的投票信息,對(duì)于 ZK1、ZK2 而言,都統(tǒng)計(jì)出集群中已經(jīng)有兩臺(tái)機(jī)器接受了(2, 0)的投票信息,此時(shí)便認(rèn)為已經(jīng)選出 ZK2 作為L(zhǎng)eader。
(5) 改變服務(wù)器狀態(tài)。一旦確定了 Leader,每個(gè)服務(wù)器就會(huì)更新自己的狀態(tài),如果是Follower,那么就變更為 FOLLOWING,如果是 Leader,就變更為 LEADING。當(dāng)新的 Zookeeper 節(jié)點(diǎn) ZK3 啟動(dòng)時(shí),發(fā)現(xiàn)已經(jīng)有 Leader 了,不再選舉,直接將直接的狀態(tài)從 LOOKING 改為 FOLLOWING。
7.如果Leader掛了,進(jìn)入崩潰恢復(fù),怎么選舉Leader?

1.變更狀態(tài)。Leader 掛后,余下的非 Observer 服務(wù)器都會(huì)講自己的服務(wù)器狀態(tài)變更為 LOOKING,然后開(kāi)始進(jìn)入 Leader 選舉過(guò)程。
2.每個(gè)非 Observer 的 Server 會(huì)發(fā)出一個(gè)投票。和啟動(dòng)過(guò)程一致。
3.接收來(lái)自各個(gè)服務(wù)器的投票。與啟動(dòng)時(shí)過(guò)程相同。
4.處理投票。與啟動(dòng)時(shí)過(guò)程相同。
5.統(tǒng)計(jì)投票。與啟動(dòng)時(shí)過(guò)程相同。
6.改變服務(wù)器的狀態(tài)。與啟動(dòng)時(shí)過(guò)程相同。
8.說(shuō)說(shuō)Wather監(jiān)聽(tīng)機(jī)制和它的原理?

具體的步驟如下:
服務(wù)注冊(cè):Provider 啟動(dòng)時(shí),會(huì)向 zookeeper 服務(wù)端注冊(cè)服務(wù)信息,也就是創(chuàng)建一個(gè)節(jié)點(diǎn)。 服務(wù)發(fā)現(xiàn):Consumer 啟動(dòng)時(shí),根據(jù)自身配置的依賴(lài)服務(wù)信息,向 zookeeper 服務(wù)端獲取注冊(cè)的服務(wù)信息并設(shè)置 watch 監(jiān)聽(tīng),獲取到注冊(cè)的服務(wù)信息之后,將服務(wù)提供者的信息緩存在本地,并進(jìn)行服務(wù)的調(diào)用。 服務(wù)通知:一旦服務(wù)提供者因某種原因宕機(jī)不再提供服務(wù)之后,客戶(hù)端與 zookeeper 服務(wù)端斷開(kāi)連接,zookeeper 服務(wù)端上服務(wù)提供者對(duì)應(yīng)服務(wù)節(jié)點(diǎn)會(huì)被刪除,隨后 zookeeper 服務(wù)端會(huì)異步向所有注冊(cè)了該服務(wù),且設(shè)置了 watch 監(jiān)聽(tīng)的服務(wù)消費(fèi)者發(fā)出節(jié)點(diǎn)被刪除的通知,消費(fèi)者根據(jù)收到的通知拉取最新服務(wù)列表,更新本地緩存的服務(wù)列表。
簡(jiǎn)單的理解就是 client 會(huì)對(duì)某個(gè) znode 注冊(cè)一個(gè) watcher 事件,當(dāng)該 znode 發(fā)生變化時(shí),這些 client 會(huì)收到 ZooKeeper 的通知。
四個(gè)特性:
一次性:一旦一個(gè)Wather觸發(fā)之后,Zookeeper就會(huì)將它從存儲(chǔ)中移除,如果還要繼續(xù)監(jiān)聽(tīng)這個(gè)節(jié)點(diǎn),就需要我們?cè)诳蛻?hù)端的監(jiān)聽(tīng)回調(diào)中,再次對(duì)節(jié)點(diǎn)的監(jiān)聽(tīng)watch事件設(shè)置為T(mén)rue。否則客戶(hù)端只能接收到一次該節(jié)點(diǎn)的變更通知 客戶(hù)端串行:客戶(hù)端的Wather回調(diào)處理是串行同步的過(guò)程,不要因?yàn)橐粋€(gè)Wather的邏輯阻塞整個(gè)客戶(hù)端 輕量:Wather通知的單位是WathedEvent,只包含通知狀態(tài)、事件類(lèi)型和節(jié)點(diǎn)路徑,不包含具體的事件內(nèi)容,具體的時(shí)間內(nèi)容需要客戶(hù)端主動(dòng)去重新獲取數(shù)據(jù) 異步: Zookeeper服務(wù)器發(fā)送watcher的通知事件到客戶(hù)端是異步的,不能期望能夠監(jiān)控到節(jié)點(diǎn)每次的變化,Zookeeper只能保證最終的一致性,而無(wú)法保證強(qiáng)一致性。
9.Zookeeper有哪些特性呢?

順序一致性:leader會(huì)根據(jù)請(qǐng)求順序生成 ZXID 來(lái)嚴(yán)格保證請(qǐng)求順序的下發(fā)執(zhí)行。 原子性:所有事務(wù)請(qǐng)求的處理結(jié)果在整個(gè)集群中所有機(jī)器上的應(yīng)用情況是一致的,要么成功,要么就失敗。 單一視圖:無(wú)論客戶(hù)端連到哪一個(gè) ZooKeeper 服務(wù)器上,看到的數(shù)據(jù)都是一致的。 可靠性:一旦服務(wù)端成功地應(yīng)用了一個(gè)事務(wù),并完成對(duì)客戶(hù)端的響應(yīng),那么該事務(wù)所引起的服務(wù)端狀態(tài)變更將會(huì)被一直保留下來(lái)。 實(shí)時(shí)性:Zookeeper 僅僅能保證在段時(shí)間內(nèi)客戶(hù)端最終一定能夠從服務(wù)端上讀取到最新的數(shù)據(jù)狀態(tài)。
10.Zookeeper 如何識(shí)別請(qǐng)求的先后順序?

Leader 收到請(qǐng)求之后,會(huì)將每個(gè)請(qǐng)求分配一個(gè)全局唯一遞增的事務(wù)ID:zxid,然后把請(qǐng)求放入到一個(gè) FIFO 的隊(duì)列中,之后就會(huì)按照 FIFO 的策略發(fā)送給所有的 Follower。
11.選舉 leader 后是怎么進(jìn)行數(shù)據(jù)同步的

前面提到寫(xiě)數(shù)據(jù)是由 leader 負(fù)責(zé)的,而 leader 會(huì)將每個(gè)請(qǐng)求分配一個(gè) ZXID,放入一個(gè)隊(duì)列中,依次執(zhí)行,每次 leader 執(zhí)行完一個(gè)請(qǐng)求后,會(huì)記錄下執(zhí)行的這個(gè) ZXID。
我們將這個(gè)隊(duì)列中最大的 ZXID 稱(chēng)為 maxZXID,最小的 ZXID 稱(chēng)為 minZXID。
將 Observer 和 follower 中最新的 ZXID 稱(chēng)為lastSyncZXID
proposal : l其實(shí)就是將請(qǐng)求中的一些信息如請(qǐng)求頭,請(qǐng)求體以及 ZXID 等信息封裝到 proposal對(duì)象當(dāng)中
1.差異化同步
1).leader 向 Observer 和 follower 發(fā)送 DIFF 指令,之后就開(kāi)始差異化同步 2).然后把差異數(shù)據(jù) 提議 proposal 發(fā)送給 Observer 和 follower , Observer 和 follower 返回ACK表示已經(jīng)完成了同步 3).只要集群中過(guò)半的 Observer 和 follower 響應(yīng)了 ACK 就發(fā)送一個(gè) UPTODATE 命令 4).leader 返回 ACK,同步流程結(jié)束 觸發(fā)條件:minZXID < lastSyncZXID < maxZXID
同步過(guò)程:
2.回滾同步
1).直接回滾到 maxZXID 觸發(fā)條件 maxZXID < lastSyncZXID 舉個(gè)例子:a,b,c三臺(tái)服務(wù)服務(wù)器 a是leader,此時(shí)隊(duì)列里面最大的 ZXID 為100,a 收到請(qǐng)求,該 ZXID 為101,還沒(méi)來(lái)得及發(fā)送同步數(shù)據(jù) a 就掛了,b 變?yōu)閘eader,然后 a 恢復(fù)了,此時(shí)就需要 a 先將之前 ZXID 為101的數(shù)據(jù)回滾 同步過(guò)程: 3.回滾+差異化同步
1).Observer 和 follower 將數(shù)據(jù)回滾 2).進(jìn)行差異化同步 觸發(fā)條件:如果Leader剛生成一個(gè)proposal,還沒(méi)有來(lái)得及發(fā)送出去,此時(shí)Leader宕機(jī),重新選舉之后作為Follower,但是新的Leader沒(méi)有這個(gè)proposal數(shù)據(jù) 舉個(gè)例子:a,b,c三臺(tái)服務(wù)服務(wù)器 a是leader,此時(shí)隊(duì)列里面最大的 ZXID 為100,a 收到請(qǐng)求,該 ZXID 為101,還沒(méi)來(lái)得及發(fā)送同步數(shù)據(jù) a 就掛了,b 變?yōu)閘eader,b 又處理了3個(gè)請(qǐng)求,則 b 隊(duì)列中最大的 ZXID 為103,然后 a 恢復(fù)了,此時(shí)就需要 a 先將之前 ZXID 為101的數(shù)據(jù)回滾,再進(jìn)行同步 同步過(guò)程: 4.全量同步
1).lastSyncZXID < minZXID 2).Leader服務(wù)器上沒(méi)有緩存隊(duì)列,并且lastSyncZXID!=maxZXID 觸發(fā)條件 同步過(guò)程:leader 向 Observer 和 follower 發(fā)送SNAP命令,進(jìn)行數(shù)據(jù)全量同步
12.Zookeeper 會(huì)有數(shù)據(jù)不一致的情況發(fā)生嗎?
還是會(huì)有的,因?yàn)?Zookeeper 采用的是過(guò)半寫(xiě)機(jī)制,意味著3臺(tái)服務(wù)器只要有兩臺(tái)寫(xiě)成功就代表整個(gè)集群寫(xiě)成功,如果剛好有請(qǐng)求打在這臺(tái)還未寫(xiě)的服務(wù)器上就查詢(xún)不到該數(shù)據(jù),就會(huì)有數(shù)據(jù)不一致的情況產(chǎn)生。
往期推薦
