黄色网页视频 I 影音先锋日日狠狠久久 I 秋霞午夜毛片 I 秋霞一二三区 I 国产成人片无码视频 I 国产 精品 自在自线 I av免费观看网站 I 日本精品久久久久中文字幕5 I 91看视频 I 看全色黄大色黄女片18 I 精品不卡一区 I 亚洲最新精品 I 欧美 激情 在线 I 人妻少妇精品久久 I 国产99视频精品免费专区 I 欧美影院 I 欧美精品在欧美一区二区少妇 I av大片网站 I 国产精品黄色片 I 888久久 I 狠狠干最新 I 看看黄色一级片 I 黄色精品久久 I 三级av在线 I 69色综合 I 国产日韩欧美91 I 亚洲精品偷拍 I 激情小说亚洲图片 I 久久国产视频精品 I 国产综合精品一区二区三区 I 色婷婷国产 I 最新成人av在线 I 国产私拍精品 I 日韩成人影音 I 日日夜夜天天综合

Zookeeper 內容的一些概念

系統(tǒng) 2021 0

?

閱讀指南——如何利用 Zookeeper 構建上層應用?

本文將帶你如何利用 Zookeeper 實現(xiàn)某些分布式應用所必需的高級功能。所有功能均可以在客戶端按固定的模式實現(xiàn),不需要 Zookeeper 的特殊支持,也希望 Zookeeper 社區(qū)能將這些具有固定實現(xiàn)模式的功能集成到 Zookeeper 客戶端的程序庫中,可以簡化 Zookeeper 的使用并且還能使某些功能的實現(xiàn)標準化。

即便 Zookeeper 本身使用異步通知( asynchronous ?notifications),但卻可以基于此構建同步的( synchronous )一致性原語,如隊列和鎖。你將看到 Zookeeper 實現(xiàn)這些功能是完全可能的,因為 Zookeeper 提供了強制的全序更新,并對外提供了保序接口。?

注意下面的程序段試圖采取最佳的編程實踐,尤其是避免使用輪詢(polling),定時器(timers)和其他任何可能造成“羊群效應(herd effect)”機制(“羊群效應”一般會帶來網絡流量的突增,限制系統(tǒng)的可擴展性)。

除了本文所列舉的功能,我們還可以想象出其他很多實用的功能,比如可撤銷的讀寫優(yōu)先鎖。本文提到的某些構建方式——比如鎖,比較詳細的闡述了使用 Zookepper 的關鍵點,其實你可以找到其他的例子,如事件處理和隊列,但是,本節(jié)中的例子只是模擬相關的功能,在具體實踐中需要考慮其他方面的因素。

開箱即用的應用示例:命名服務,配置管理,組關系管理

命名服務和配置管理是 Zookeeper 提供的最基本的應用,這兩個功能可以直接用 Zookeeper 提供的 API 實現(xiàn)。

另外一個可以直接使用的功能是組關系管理,組在 Zookeeper 由一個 Znode 表示,組中的某個成員可以用組節(jié)點下的臨時節(jié)點(Ephemeral Nodes)表示,當 Zookeeper 檢測到節(jié)點故障時,節(jié)點成員中不正常的節(jié)點將會被自動地移除。

屏障(Barriers)

分布式系統(tǒng)使用屏障( barriers )來阻塞某一節(jié)點集的任務,直到滿足特定的條件該節(jié)點集的所有節(jié)點才能正常向前推進,就像屏障一樣,在當條件不滿足時,屏障阻塞了任務的執(zhí)行,只有當條件滿足后屏障才會被拆除,各節(jié)點才能推進自己正在執(zhí)行的任務。Zookeeper 中實現(xiàn)屏障時指定一個屏障節(jié)點(barrier node),如果屏障節(jié)點存在,屏障就會生效,下面是偽代碼:

  1. 客戶端在屏障節(jié)點上調用 ZooKeeper API?? exists(), watch 設置為 true .

  2. 如果? exists() ?返回 false,屏障消失,客戶端可以推進的自己的工作。

  3. 否則,? exists() ?返回 true,客戶端等待屏障節(jié)點上監(jiān)聽事件的到來。

  4. 如果監(jiān)聽事件被觸發(fā),客戶端重新執(zhí)行? exists( ), ?再一次重復上述 1-3 步,直到屏障節(jié)點被移除。

?

(雙屏障)Double Barriers

雙屏障(Double barriers)使得所有客戶端在進入和結束某一計算任務時都會得到同步。當足夠的進程processes(注:此處指節(jié)點)加入到屏障時,才啟動任務,然后當任務完成時,離開屏障區(qū),下面的代碼段示意如何使用 Zookeeper 創(chuàng)建屏障節(jié)點。

偽代碼中屏障節(jié)點用? b ?表示,每個客戶端進程(節(jié)點)?? p ?在進入屏障節(jié)點時注冊事件,然后在離開時取消注冊事件。進入屏障節(jié)點注冊事件的代碼如下表的? Enter 程序段所示, ?在繼續(xù)處理任務之前,它將等待客戶端? x ?進程的注冊。(此處的? x ?由你針對自己的系統(tǒng)決定)

Enter Leave
  1. 創(chuàng)建名稱為? b +“/”+ p 的 Znode 節(jié)點

  2. 設置監(jiān)視: exists( b ?+ ‘‘/ready’’, true)

  3. 創(chuàng)建子節(jié)點: create(? n , EPHEMERAL)

  4. L = getChildren(b, false)

  5. 如果L的孩子數(shù)目小于? x 的 , 則等待監(jiān)視事件

  6. 否則? create(b + ‘‘/ready’’, REGULAR)

  1. L = getChildren(b, false)

  2. 如果沒有任何子節(jié)點,則退出。

  3. 如果? p ?是 L 中唯一節(jié)點,則 delete(n) 并退出。

  4. 如果? p 是 L 中的序號最低的節(jié)點,則等待 P 中的序號最高節(jié)點。

  5. 否則 依然存在,則? delete( n ) ?并繼續(xù)等待L中的最低節(jié)點。

  6. 跳轉 1

在進入屏障時,所有的進程(節(jié)點)監(jiān)視一個準備好的節(jié)點(屏障節(jié)點),并創(chuàng)建一個臨時節(jié)點作為屏障節(jié)點的孩子。除了最后進入屏障的節(jié)點外,每個進程(節(jié)點)都等待屏障節(jié)點,直到第 5 行的條件出現(xiàn)。該進程(節(jié)點)創(chuàng)建第 x 個節(jié)點——即最后的進程(節(jié)點),它將會看到 x 個節(jié)點,并喚醒其他進程(節(jié)點),注意,所有的等待進程(節(jié)點)只是在退出的時候被喚醒,所以等待還是很高效的。

在退出屏障時,你不能設置 諸如? ready ?的標志,因為你在等待進程節(jié)點退出,通過使用臨時節(jié)點,進入屏障后失效的進程節(jié)點并不會阻止其他運行正確的節(jié)點完成任務。當進程節(jié)點準備推出屏障區(qū)時,它必須刪除它的進程節(jié)點,并等待其他進程刪除各自的進程節(jié)點。

當 b 沒有的進程子節(jié)點時,進程(節(jié)點)就會退出屏障區(qū)。然而,為了效率起見,你可以使用序號最低的進程節(jié)點作為 ready 標志。所有其他準備退出屏障區(qū)的進程(節(jié)點)都監(jiān)視序號最低的將要退出進程(節(jié)點)消失,序號最低的進程節(jié)點的擁有者則就等待其他任何一個節(jié)點的消失(選擇序號最高進程節(jié)點)。這意味著除了最后的一個進程節(jié)點外,其他的每個進程節(jié)點被刪除時只要喚醒一個進程節(jié)點即可,當它被刪除時就會喚醒其他的進程節(jié)點。

隊列(Queues)

分布式隊列是通用的數(shù)據(jù)結構,為了在 Zookeeper 中實現(xiàn)分布式隊列,首先需要指定一個 Znode 節(jié)點作為隊列節(jié)點(queue node), 各個分布式客戶端通過調用 create() 函數(shù)向隊列中放入數(shù)據(jù),調用create()時節(jié)點路徑名帶"queue-"結尾,并設置順序和臨時( sequence ?and ephemeral )節(jié)點標志。 由于設置了節(jié)點的順序標志,新的路徑名具有以下字符串模式:"_path-to-queue-node_/queue-X",X 是唯一自增號。需要從隊列中移除數(shù)據(jù)的客戶端首先調用? getChildren( ) ?函數(shù),同時在隊列節(jié)點(queue node)上將? watch ?設置為 true,并處理最小序號的節(jié)點(即從序號最小的節(jié)點中取數(shù)據(jù))。客戶端不需要再一次調用? getChildren( ), 隊列中的數(shù)據(jù)獲取完。如果隊列節(jié)點中沒有任何子節(jié)點,讀取隊列的客戶端需要等待隊列的監(jiān)視事件通知。

Priority Queues

為了實現(xiàn)優(yōu)先隊列,你在普通隊列上只需要簡單的改變兩處地方,首先,在某一元素被加入隊列時,路徑名以 "queue-YY" 結尾,YY 表示優(yōu)先級,YY越小優(yōu)先級越高,其次,從隊列中移除一個元素時,客戶端需要使用最新的孩子節(jié)點列表,這意味著如果隊列節(jié)點上監(jiān)視通知被觸發(fā),客戶端需要讓先前獲取的孩子節(jié)點列表無效。

鎖(Locks)

完全分布式鎖是全局同步的,這意味著在任何時刻沒有兩個客戶端會同時認為它們都擁有相同的鎖,使用 Zookeeper 可以實現(xiàn)分布式鎖,和優(yōu)先隊列一樣,我們需要首先定義一個鎖節(jié)點(lock node)。

需要獲得鎖的客戶端按照以下步驟來獲取鎖:

  1. 調用? create( ), 參數(shù) pathname 為 "_locknode_/lock-",并設置? sequence? 和? ephemeral ?標志。

  2. 在所節(jié)點(lock node)上調用? getChildren( ) ?,不需要設置監(jiān)視標志。 (為了避免“羊群效應”).

  3. 如果在第 1 步中創(chuàng)建的節(jié)點的路徑具有最小的序號后綴,那么該客戶端就獲得了鎖。

  4. 客戶端調用? exists( ) ?,并在鎖目錄路徑中下一個最小序號的節(jié)點上設置監(jiān)視標志。

  5. 如果? exists( ) ?返回 false,跳轉至第 2 步,否則,在跳轉至第 2 步之前等待前一部路徑上節(jié)點的通知消息。

解鎖協(xié)議非常簡單:需要釋放鎖的客戶端只需要刪除在第 1 步中創(chuàng)建的節(jié)點即可。

注意事項:

  • 一個節(jié)點的刪除只會導致一個客戶端被喚醒,因為每個節(jié)點只被一個客戶端監(jiān)視,這避免了羊群效應。

  • 沒有輪詢和超時。

  • 根據(jù)你實現(xiàn)鎖的方式不同,不同的實現(xiàn)可能會帶來大量的鎖競爭,鎖中斷,調試鎖等等。

Shared Locks

在基本的鎖協(xié)議之上,你只需要做一些小的改變就可以實現(xiàn)共享鎖(shared locks):

獲取讀鎖: 獲取寫鎖:
  1. Call? create( ) ?to create a node with pathname " _locknode_/read-". This is the lock node use later in the protocol. Make sure to set both the? sequence ?and? ephemeral ?flags.

  2. Call? getChildren( ) ?on the lock node? without ?setting the? watch flag - this is important, as it avoids the herd effect.

  3. If there are no children with a pathname starting with " write-" and having a lower sequence number than the node created in step? 1 , the client has the lock and can exit the protocol.

  4. Otherwise, call? exists( ) , with? watch ?flag, set on the node in lock directory with pathname staring with " write-" having the next lowest sequence number.

  5. If? exists( ) ?returns? false , goto step? 2 .

  6. Otherwise, wait for a notification for the pathname from the previous step before going to step? 2

  1. Call? create( ) ?to create a node with pathname " _locknode_/write-". This is the lock node spoken of later in the protocol. Make sure to set both? sequence ?and? ephemeral ?flags.

  2. Call? getChildren( )? on the lock node? without ?setting the? watch ?flag - this is important, as it avoids the herd effect.

  3. If there are no children with a lower sequence number than the node created in step? 1 , the client has the lock and the client exits the protocol.

  4. Call? exists( ), ?with? watch ?flag set, on the node with the pathname that has the next lowest sequence number.

  5. If? exists( ) ?returns? false , goto step? 2 . Otherwise, wait for a notification for the pathname from the previous step before going to step? 2 .

Recoverable Shared Locks

對共享鎖做一些細小的改變,我們就可以使共享鎖變成可撤銷的共享鎖:

在第 1 步,在獲取讀者和寫者的鎖協(xié)議中,在調用? create( ) 后, 立即調用 getData( ) ,并設置監(jiān)視。如果客戶端稍后收到了它在第一步創(chuàng)建節(jié)點的通知,它會再一次在該節(jié)點上調用? getData( ) ,并設置監(jiān)視,查找 “unlock” 串。該信號會通知客戶端必須釋放鎖。這是因為,依據(jù)共享鎖協(xié)議,你可以通過在鎖節(jié)點(lock node)上調用 setData()(將“unlock”寫入該節(jié)點) 請求擁有該鎖的客戶端放棄該鎖 。

注意該協(xié)議要求鎖的擁有者也同意釋放該鎖,該協(xié)定非常重要,尤其是鎖的擁有者需要在釋放該鎖前做一些處理。 當然,你也可以通過約定“撤銷者可以在鎖的擁有者一段時間沒有刪除該鎖的情況下刪除該鎖節(jié)點”來實現(xiàn)可撤銷的共享鎖。

兩階段提交(Two-phased Commit)

兩階段提交協(xié)議可以讓分布式系統(tǒng)的所有客戶端決定究竟提交某一事務或還是終止該事務。

在 Zookeeper 中,你可以讓協(xié)調者(coordinator)創(chuàng)建事務節(jié)點,比如,"/app/Tx",從而實現(xiàn)一個兩階段提交協(xié)議。 當協(xié)調者(coordinator)創(chuàng)建了子節(jié)點時,子節(jié)點內容是未定義的,由于每個事務參與方都會從協(xié)調者接收事務,參與方讀取每個子節(jié)點并設置監(jiān)視。然后每個參與方通過向與自身相關的 Znode 節(jié)點寫入數(shù)據(jù)來投票“提交(commit)”或“中止(abort)”事務。一旦寫入完成,其他的參與方會被通知到,當所有的參與方都投完票后,協(xié)調者就可以決定究竟是“提交(commit)”或“中止(abort)”事務。注意,如果某些參與方投票“中止”,節(jié)點是可以決定提前“中止”事務的。

該實現(xiàn)方法有趣的地方在于協(xié)調者的唯一作用是決定參與方的組(the group of sites),創(chuàng)建 Zookeeper 節(jié)點, 將事務傳播到相應的參與方,實際上,Zookeeper 可以通過將消息寫入事務節(jié)點來傳播事務。

上述討論的方法存在兩個明顯的缺點,一是消息的復雜性,復雜度為 O(n2),另外一個是僅通過臨時節(jié)點不能判斷某些參與方是否失效,為了利用臨時節(jié)點檢測參與方是否失效,必須參與方創(chuàng)建該節(jié)點。

為了解決第一個問題,你可以將系統(tǒng)設置成只有一個協(xié)調者可以收到事務節(jié)點狀態(tài)的變化,一旦協(xié)調者達成意見后通知其他參與方, 該方法可擴展性較強,但是速度很慢,因為所有的通信都指向協(xié)調者。

為了解決第二個問題,你可以讓參與方把事務傳播到參與方,并讓每個參與方創(chuàng)建自己的臨時節(jié)點。

Leader 選舉(Leader Election)

Zookeeper 實現(xiàn) Leader 選舉簡單做法是在創(chuàng)建代表 “proposals” 客戶端的 Znode 節(jié)點時設置? SEQUENCE|EPHEMERAL ?標志。基本想法是創(chuàng)建一個節(jié)點,比如 "/election",然后在創(chuàng)建子節(jié)點時"/election/n_"設置標志 SEQUENCE|EPHEMERAL. 當設置順序節(jié)點 SEQUENCE 標志時,Zookeeper 會在 "/election" 子節(jié)點的創(chuàng)建過程中自增子節(jié)點名稱后綴的序號,最小后綴序號的 Znode 節(jié)點表示Leader。

然而,還沒完,監(jiān)視 Leader 失效也是非常重要的,當前的 Leader 失效后需要一個新的客戶端起來接替舊的 Leader 的位置。一個簡單的方式是讓所有的應用進程監(jiān)視當前序號最小的 Znode 節(jié)點, 并在當前 序號最小的 Znode 節(jié)點失效是檢查他們是否為新的 Leader(注意當前序號最小的節(jié)點可能會隨著 Leader 的消失而消失,他們可能是該Leader 節(jié)點的臨時子節(jié)點). 但是這會導致'羊群效應(herd effect)":在當前 Leader 失效后,其他所有的進程(節(jié)點)將會收到通知,并在 "/election" 節(jié)點上執(zhí)行 getChildren()來獲取"/election"節(jié)點的子節(jié)點列表,如果客戶端數(shù)目很大,它會使得Zookeeper服務器處理的操作次數(shù)急劇上升。為了避免羊群效應,客戶端只需要監(jiān)視 Znode 節(jié)點中的下一個節(jié)點就足夠。如果某個客戶端收到了它正在監(jiān)視的節(jié)點消失的通知,它將成為新的 Leader,因為此時沒有其它的 Znode 節(jié)點的序號比它小。所以這就避免了羊群效應,并且客戶端也沒有必要監(jiān)視同一個最小的 Znode 節(jié)點。

以下是偽代碼:

假設 ELECTION 成為Leader 選舉應用的路徑,對于想要成為 Leader 的 Volunteer而言:

  1. 創(chuàng)建 Znode 節(jié)點 z,路徑名稱為"ELECTION/n_"并設置 SEQUENCE 和 EPHEMERAL 標志。

  2. 假設 C 是"ELECTION"的子節(jié)點集合,? i 是 z 節(jié)點的序號。

  3. 監(jiān)視節(jié)點 "ELECTION/n_j" 的改變,j 是滿足 j < i 最小的序號,n_j 是 C 節(jié)點集合中的某個節(jié)點。

當收到 Znode 節(jié)點刪除的通知時:

  1. 假設 C 是 “ELECTION” 新的子節(jié)點集合。

  2. 如果 z 是 C 中的最小節(jié)點,則執(zhí)行 Leader 選舉流程。

  3. 否則,監(jiān)視節(jié)點 "ELECTION/n_j" 的改變,j 是滿足 j < i 最小的序號,n_j 是 C 節(jié)點集合中的某個節(jié)點。

注意,在子節(jié)點列表中沒有先遣節(jié)點的 Znode 并不意味著該節(jié)點的創(chuàng)建者知道它就是當前的Leader,應用程序可能需要考慮創(chuàng)建一個單獨的 Znode 來確認該 Leader 已經執(zhí)行了選舉流程。

Zookeeper 內容的一些概念


更多文章、技術交流、商務合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論