什麼是Zookeeper?(動態的服務註冊和發現、Master選舉、分散式鎖)

書寫人生發表於2019-09-08
原文連結: https://mp.weixin.qq.com/s/J8erMBhiogXoQcn91SJcbw

轉自:碼農翻身(微訊號:coderising)

張大胖所在的公司這幾年發展得相當不錯,業務激增,人員也迅速擴充套件,轉眼之間,張大胖已經成為公司的“資深”員工了,更重要的是,經過這些年的不懈努力,他終於坐上了架構師的寶座。

但是大胖很快發現,這架構師真不是好當的,技術選型、架構設計,尤其是大家搞不定的技術難點,最終都得自己扛起來。溝通、說服、妥協、甚至爭吵都是家常便飯,比自己之前單純做開發的時候難多了。

公司的IT系統早已經從單機轉向了分散式,分散式系統帶來了巨大的挑戰。這週一剛上班,張大胖的郵箱裡已經塞滿了緊急郵件。

1、小梁的郵件

小梁的郵件裡說了一個RPC呼叫的問題,本來公司的架構組開發了一個RPC框架讓各個組去使用,但是各開發小組紛紛抱怨:這個RPC框架不支援動態的服務註冊和發現。

張大胖一看這個圖就明白怎麼回事了,為了支援高併發,OrderService被部署了4份,每個客戶端都儲存了一份服務提供者的列表,但是這個列表是靜態的(在配置檔案中寫死的),如果服務的提供者發生了變化,例如有些機器down了,或者又新增了OrderService的例項,客戶端根本不知道,可能還在傻乎乎地嘗試那些已經壞掉的例項呢!

想要得到最新的服務提供者的URL列表,必須得手工更新配置檔案才行,確實很不方便。

對於這樣的問題,大胖馬上就意識到,這就是客戶端和服務提供者的緊耦合啊。

想解除這個耦合,非得增加一箇中間層不可!

張大胖想到,應該有個註冊中心,首先給這些服務命名(例如orderService),其次那些OrderService 都可以在這裡註冊一下,客戶端就到這裡來查詢,只需要給出名稱orderService,註冊中心就可以給出一個可以使用的url, 再也不怕服務提供者的動態增減了。

 

不知道是不是下意識的行為, 張大胖把這個註冊中心的資料結構設計成為了一個樹形結構

/orderService 表達了一個服務的概念, 下面的每個節點表示了一個服務的例項。 例如/orderService/node2表示的order service 的第二個例項, 每個節點上可以記錄下該例項的url , 這樣就可以查詢了。

當然這個註冊中心必須得能和各個服務例項通訊,如果某個服務例項不幸down掉了,那它在樹結構中對於的節點也必須刪除, 這樣客戶端就查詢不到了。

嗯,可以在註冊中心和各個服務例項直接建立Session, 讓各個服務例項定期地傳送心跳,如果過了特定時間收不到心跳,就認為這個服務例項掛掉了,Session 過期, 把它從樹形結構中刪除。

張大胖把自己的想法回覆了小梁,接著看小王的郵件。

2、小王的Master選舉

小王郵件中說的是三個Batch Job的協調問題,這三個Batch Job 部署在三臺機器上,但是這三個Batch Job同一個時刻只能有一個執行,如果其中某個不幸down掉,剩下的兩個就需要做個選舉,選出來的那個Batch Job 需要“繼承遺志”,繼續工作。

 

其實這就是一個Master的選舉問題,張大胖一眼就看出了本質。

只是為了選舉出Master, 這三個Batch Job 需要互通有無,互相協調才行,這就麻煩了!

要不弄個資料庫表? 利用資料庫表主鍵不能衝突的特性,讓這三個Batch Job 都向同一個表中插入同樣的資料,誰先成功誰就是Master !

可是如果搶到Master的那個Batch Job掛掉了,別人永遠就搶不到了! 因為記錄已經存在了, 別的Batch Job 沒法插入資料了!

嗯,還得加上定期更新的機制,如果一段時間內沒有更新就認為Master死掉了,別的Batch Job可以繼續搶.....  不過這麼做好麻煩!

換個思路,讓他們也去一個註冊中心去大吼一聲:“我是master!”, 誰的聲音大誰是Master 。 

其實不是吼一聲,三個Batch Job啟動以後,都去註冊中心爭搶著去建立一個樹的節點(例如/master ),誰建立成功誰就是Master ( 當然註冊中心必須保證只能建立成功一次,其他請求就失敗了),其他兩個Batch Job就對這個節點虎視眈眈地監控,如果這個節點被刪除,就開始新一輪爭搶,去建立那個/master節點。

什麼時候節點會被刪除呢? 對,就是當前Master的機器down掉了 ! 很明顯,註冊中心也需要和各個機器通訊,看看他們是否活著。

等等,這裡還有一個複雜的情況, 如果機器1並沒有死掉,只是和註冊中心長時間連線不上,註冊中心會發現Session超時,會把機器1建立的/master刪除。 讓機器2和機器3去搶,如果機器3成為了master, 開始執行Batch Job,   但是機器1並不知道自己被解除了Master的職務, 還在努力的執行Batch Job,這就衝突了!

看來機器1必須得能感知到和註冊中心的連線斷開了,需要停止Batch Job才行,等到和註冊中心再次連線上以後,才知道自己已經不是master了,老老實實地等下一次機會吧。

無論哪種方案,實現起來都很麻煩,這該死的分散式!

先把思路給小王回覆一下吧。接著看小蔡的郵件。

3、小蔡的分散式鎖

小蔡的郵件裡說的問題更加麻煩,有多個不同的系統(當然是分佈在不同的機器上!),要對同一個資源操作。

這要是在一個機器上,使用某個語言內建的鎖就可以搞定,例如Java的synchronized , 但是現在是分散式啊,程式都跑在不同機器的不同程式中, synchcronized一點用都沒有了!

這是個分散式鎖的問題啊!

能不能考慮下Master選舉問題中的方式,讓大家去搶? 誰能搶先在註冊中心建立一個 /distribute_lock的節點就表示搶到這個鎖了,然後讀寫資源,讀寫完以後就把 /distribute_lock節點刪除,大家再來搶。

可是這樣的話某個系統可能會多次搶到,不太公平。

如果讓這些系統在註冊中心的/distribute_lock下都建立子節點, 然後給每個系統一個編號,會是這個樣子:

然後各個系統去檢查自己的編號,誰的編號小就認為誰持有了鎖, 例如系統1。

系統1持有了鎖,就可以對共享資源進行操作了, 操作完成以後process_01這個節點刪除, 再建立一個新的節點(編號變成process_04了):

 

  其他系統一看,編號為01的刪除了,再看看誰是最小的吧,是process_02,那就認為系統2持有了鎖,可以對共享資源操作了。 操作完成以後也要把process_02節點刪除,建立新的節點。這時候process_03就是最小的了,可以持有鎖了。

這樣迴圈往復下去......  分散式鎖就可以實現了!

看看,我設計的這個集中式的樹形結構很不錯吧,能解決各種各樣的問題! 張大胖不由得意起來。

好,先把這個想法告訴小蔡,實現細節下午開個會討論。

4、Zookeeper

正準備回覆小蔡的時候,大胖突然意識到,自己漏了一個重要的點,那就是 註冊中心的高可用性,如果註冊中心只有那麼一臺機器,一旦掛掉,整個系統就玩完了。

這個註冊中心也得有多臺機器來保證高可用性,那個自己頗為得意的樹形結構也需要在多個機器之間同步啊,要是有機器掛掉怎麼辦? 通訊超時怎麼辦? 樹形結構的資料怎麼在各個機器之間保證強一致性?

小王、小梁、小蔡的原始問題沒有解決,單單是這個註冊中心就要了命了。 以自己公司的技術實力,搞出一套這樣的註冊中心簡直是Mission Impossible !

大胖趕緊上網搜尋,看看有沒有類似的解決方案,讓大胖感到萬分幸運的是,果然有一個,叫做 Zookeeper

Zookeeper 所使用的樹形結構和自己想象的非常類似,更重要的是,人家實現了樹形結構資料在多臺機器之間的可靠複製,達到了資料在多臺機器之間的一致性。並且這多臺機器中如果有部分掛掉了/或者由於網路原因無法連線上了, 整個系統還可以工作。

大胖趕快去看Zookeeper的關鍵概念和API:

  1. Session : 表示某個客戶系統(例如Batch Job)和ZooKeeper之間的連線會話, Batch Job連上ZooKeeper以後會週期性地傳送心跳資訊, 如果Zookeepr在特定時間內收不到心跳,就會認為這個Batch Job已經死掉了, Session 就會結束。

  2. znode : 樹形結構中的每個節點叫做znode, 按型別可以分為 永久的znode(除非主動刪除,否則一直存在), 臨時的znode(Session結束就會刪除)和 順序znode(就是小蔡的分散式鎖中的process_01,process_02…)。

  3. Watch : 某個客戶系統(例如Batch Job)可以監控znode, znode節點的變化(刪除,修改資料等)都可以通知Batch Job, 這樣Batch Job可以採取相應的動作,例如爭搶著去建立節點。

嗯,這些概念和介面應該可以滿足我們的要求了, 就是它了,下午召集大家開會開始學習Zookeeper吧。

後記:本文從使用者的角度描述了Zookeeper有什麼用處,至於它內部是如何工作,那是另外一個Big topic了,我們以後再講。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69947338/viewspace-2656389/,如需轉載,請註明出處,否則將追究法律責任。

相關文章