秒懂zookeeper

前言

看了很多zookeeper的文章和視頻,幾乎前篇一律先講一遍基本使用再講使用場景,看完還是云里霧里。
所以本文換一個角度講解zookeeper,從它出現的背景,要解決的問題入手,一步步反推它的功能。用大白話的方式試著從設計者的角度思考zookeeper為何如此設計。

注:本文只是幫助理解zookeeper,具體的搭建和操作可以參考官方文檔或百度,從設計者的角度思考也只是一種假設,只是為了方便理解,實際上zookeeper最初的定位可能壓根沒考慮這么多

協調者

現如今上網用戶越來越多,單機服務無法滿足各種高并發場景帶來的壓力,所以采用多個物理節點來共同完成任務,組成一個分布式應用,而zookeeper就是分布式應用的協調者。
什么是協調者?你們公司的領導就是協調者,負責協調每個人的工作。
如果把公司比做動物園,每個員工是一個動物,那么負責協調工作的領導就是動物園管理員(zookeeper的直譯)。
分布式應用也是這樣,比如有n個訂單服務、n個用戶服務,兩種服務雖然各處理一類事情但總歸是需要配合的,需要配合就有公共的數據(比如節點的信息,公共的配置),那這公共的數據存哪里好?單獨交給任何一個服務都不合適,因為大家都是平等的,如果所有服務都給,一致性怎么保證,萬一不一樣到底以哪個為準。
所以就需要一個中間件來協調,就是zookeeper,它的存在就是給分布式應用提供一致性服務。


zookeeper

服務

如果我們是zookeeper的設計者,現在用戶的痛點找到了,產品的定位也有了:協調分布式應用
那么接下來就要想了,要提供怎樣的服務,或者說分布式應用中哪些工作需要協調?

分布式注冊中心

比如分布式應用有A服務、B服務,A服務需要調用B服務,那A怎么知道B服務在哪些臺機器吶?ip是多少?port是多少?
如果想簡單解決,那就把B服務的ip和port在A服務存儲一份就可以了,但是如果有多個B服務就需要存儲多份,某個B服務宕機了還要改。如果又加了個依賴B服務的C服務,又要再C服務存一份,甚至以后有更多服務彼此依賴,那光維護這些信息就能累死。
zookeeper作為分布式協調者,這種事情肯定要管,怎么管吶,所有服務都到我這里注冊(ip、port等信息),這樣每臺機器的每個服務只需注冊一次,將來A想調用B,先來注冊中心找到一個B的位置,然后去調用就可以了,某個服務宕機了,就把它注冊的信息刪掉,起到一個注冊中心的作用。

文件系統數據結構

有了具體的需求,下面就是設計了,如果自己來設計zookeeper,這個數據結構如何設計合理?
假設場景如下:

  • 當前有多個項目
  • 每個項目按功能拆分成多個微服務
  • 每個微服務有多個節點,節點信息包含ip和port等所在機器信息

如果人工處理,把這些信息交給某個人(注冊員)來用電腦存儲記錄,那么他有兩種選擇:1.建一個文件夾把所有節點信息存入。2.建多個文件夾把節點信息分類存儲。
很明顯第一種一但信息多了,找太費勁了,所以一定會用第二種,存儲的信息大概如下:

注冊員記錄

這樣存的好處一看便知:方便歸納,方便查找
這時候再回頭看zookeeper的數據結構,就能理解為什么要這么設計了:
zookeeper數據結構

上例中分為文件夾txt文件,zookeeper統稱為節點,任何節點都可以包含信息(文件),任何節點也可以包含子節點(文件夾),節點本身可以createdelete來創建刪除,也可以通過setget存放獲取數據(所以也是一個key-value模式)。

接下來展示兩個使用zookeeper做注冊中心的數據存儲

  • spring使用zookeeper做注冊中心:


    spring-zookeeper
  • dubbo使用zookeeper做注冊中心:


    dubbo-zookeeper

可以看到有些信息直接用節點名來存儲,有些信息用set存儲,其實隨意,怎么存怎么取唄,但節點名太長如果再有子節點就很不方便

問題?

以上只能算是一個基礎版的注冊中心,可以注冊可以獲取僅此而已,但在微服務開發中會有這樣的場景,比如1個A服務,2個B服務,A調用B且從zookeeper處獲取了2個B服務的位置并緩存起來,可以選一個調用或者負載均衡輪番調用,這時突然有一個B服務宕機了,就會出現問題:

  • 問題1,此時zookeeper中存儲的兩個B的節點信息有一個是錯誤信息,因為服務已經停了,你不可能依靠宕機的B主動來刪除,那么zookeeper如何感知B的掉線?
  • 問題2,即使zookeeper中的宕機節點信息刪除了,由于A緩存了B的信息,無法知道有一個B服務宕機了,那么如何通知A?
長鏈接和臨時節點

zookeeper的解決問題1是這樣的,作為一個注冊中心,他要求所有客戶端與其保持長鏈接,一次鏈接稱為一次會話,并通過心跳(ping,pong)不斷的檢驗會話是否依然存在,如果某個鏈接長時間不響應,那就說明服務掉線了,就可以把其注冊的節點信息刪除。
實際上刪除的方式并不是主動去刪,而是zookeeper給每個節點添加一個是否是臨時節點的屬性,并規定一個臨時節點在會話結束后自動刪除,所以每個服務注冊的都是臨時節點信息,如果服務長時間不響應代表會話結束,臨時節點就會被自動刪除(后臺刪除,有一定延時)

建立連接創建臨時節點

會話結束刪除臨時節點

通過長鏈接和臨時節點的設計者,解決了zookeeper如何感知某服務的掉線,并自動刪除掉線服務注冊的節點信息

創建臨時節點的方法:

create -e /ephemeral data // 其中-e代表臨時節點,非臨時節點會一直保存

那么問題1解決了,問題2:如何通知其它服務某服務的掉線事件

監聽通知機制

問題2解決也很簡單,既然有了長鏈接保持會話,B服務掉了,zookeeper直接把掉線事件推送給A就行了。
但關鍵是zookeeper中有那么多節點,比如A只依賴B,那A只關心B服務的所有節點掉沒掉,其它節點跟我也沒關系啊,推送過多的垃圾信息浪費啊,但zookeeper也不知道誰關心誰啊,所以就推出了監聽通知機制

  • 監聽: 你告訴zookeeper你關心那些節點
  • 通知: 你關心的節點發生變化,zookeeper負責通知你

通過這種方式,A監聽B節點,當B節點下有某個節點掉了zookeeper通知A,到此問題解決~
為了實現各種維度的監控,zookeeper提供了多種監聽方法:

  • 針對節點監聽
get  -w  /path   // 注冊監聽的同時獲取數據
stat -w /path   // 對節點進行監聽,且獲取元數據信息
  • 針對目錄監聽,目錄的變化,會觸發事件,且一旦觸發,對應的監聽也會被移除,后續對節點的創建沒有觸發監聽事件
ls -w /path
  • 針對遞歸子目錄的監聽
ls -R -w /path : -R 區分大小寫,一定用大寫 

注:zookeeper的監聽是一次性的

總結

通過文件系統數據結構長鏈接臨時節點監聽通知機制,zookeeper就形成了一個完整的注冊中心。
實際使用我們可以用zookeeper配合spring來做微服務的注冊中心,dubbo也可以使用zookeeper做注冊中心,這兩個都有相關的支持。
類似的注冊中心還有eureka,nacos,目前主流應該是nacos吧,我現在用的也是nacos。

分布式配置中心

這個其實很好理解了,集群里的每個節點都有一樣的配置,為了避免每個節點都去維護,還不如直接存在一個配置中心里,zookeeper的文件系統結構可以使用各種配置信息分類存儲,還可以通過監聽機制來實時感知配置的變化。

發布/訂閱

有了監聽通知機制,自然就支持了分布式發布/訂閱

分布式鎖

分布式應用中還有一個需要協調的場景就是分布式鎖,比如給某個商品減庫存,分布式鎖的作用就是保證隸屬于不同服務所有線程同時要操作商品庫存時,只有拿到鎖的那個線程才可以操作,或者可以理解為只能排著隊一個個操作。
實際應用中可能會有多個鎖,通過文件系統可以對鎖歸類整理,如下:


順序編號

如何實現吶,比如有A,B兩個線程都要操作商品1,B看/商品1鎖節點下沒有子節點,好,那B建一個臨時子節點B排,此時A線程又來了,看到/商品1鎖下有一個節點了,那說明B在操作商品1了,那就建一個臨時節點A排,并監聽B排節點,B線程操作完之后刪除了B排,此時A線程感知到了,證明A排上號獲得鎖了,A開始操作商品1,操作完了刪除A排

商品庫存鎖

但是問題出現了,又來了個線程C,此時下面兩個節點A排,B排都在,線程C進來監聽誰啊,我們都只到肯定是A,但問題是C不知道這些信息,A排B排對它來講都是一樣的,沒有辦法選擇了。
問題的根源是C不知道A和B誰先誰后,所以如果我們是zookeeper設計者,那么就要給節點加順序了:一個類似mysql自增主鍵的可以標識先后的順序值。
這樣的話,C進程根據順序就知道他要跟在A后面了

分布式鎖

實際上這種結構就好比排隊買票,排隊就有了順序,隊伍的第一個人(順序號最小)就是正在買票的人(獲取到了鎖),隊伍里的每個人都只關注前面的人即可,如果前面的人走了,證明排到自己了(獲得鎖),而自己買完票自然也要離開隊伍(刪除節點)。

總結

以上通過注冊中心配置中心分布式鎖等場景介紹了zookeeper主要特性:文件系統數據結構CS長鏈接監聽通知機制臨時節點有序節點等主要特性,相信到此就對zookeeper有個基本的概念了。
粗暴總結一下不過就是一個:可監控的文件系統結構的數據庫,當你的分布式應用有數據要統一存儲,只要它的結構合適,就可以用它存。

其他

除此之外zookeeper還有一些其它使用場景和特性,簡單提一下就不細說了:

持久化

zookeeper的持久化是日志+快照,這點和redis很相似

集群

zookeeper作為配置中心肯定不能輕易掛掉,為了高可用,提供了集群功能,并可以實現選舉,這也是一個大課題,篇幅有限,以后單說

樂觀鎖

節點信息包含版本號,做樂觀鎖再合適不過了(mysql為了實現樂觀鎖往往還要建一個版本號字段)

TTL

類似redis那種可以設置過期時間的節點,但是好像不準確

權限控制

zookeeper作為數據存儲中心,如果暴露在非局域網中那就有點太可怕了,所以加了針對節點的權限控制,有些節點需要登錄才訪問,有些節點需要秘鑰,有些限制固定ip訪問,總之就是像要保證數據的安全

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,622評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,716評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,746評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,991評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,706評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,036評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,029評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,203評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,725評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,451評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,677評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,161評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,857評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,266評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,606評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,407評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,643評論 2 380

推薦閱讀更多精彩內容