zookeeper 入門指導


 
zookeeper數據模型
zookeeper有一個層級命名空間,和一個分布式文件系統非常相似 。唯一的不同是每個節點可以有關聯的數據,子節點也是。就像有一個文件系統,並且允許文件可以是一個目錄。
一個規范的,絕對的,斜杠分割的路徑來表示一個節點路徑。沒有相對路徑。
任何符合下列規范的Unicode字符可以被使用:
  • null字符串(\u0000)不能是一個路徑名稱。
  • 下列字符不能使用,以為不能很好的被展示:\u0001-\u001F,\u007F-\u009F.
  • 下列字符是不允許的:\ud800-uF8FF,\uFFF0-uFFFF.
  • "."字符可以作為另一個名字被使用,但是“.”和“..”不能作為一個單獨節點路徑被使用,因為zookeeper不使用相對路徑。下列是無效的:“a/b/./c”或者“a/b/../c”。
  • “zookeeper”標記被保留。
ZNodes
在zookeeper樹中的每一個節點被稱為一個znode。ZNodes包含了一個stat數據結構,這個數據結構包含了數據變更的版本號,acl變更。stat數據結構也有時間戳,版本號和時間戳一起來允許zookeeper校驗緩存和協調更新。每當一個znode數據變更,版本號就會增加。例如:當一個客戶端取得數據,它同樣也接收數據的版本。並且,當一個執行一個更新或刪除操作,它必須提供數據的版本號。如果客戶端提供的版本號和實際的版本號不匹配,更新操作將會失敗。
 
注意:在分布應用中,node一詞可以被用來表示一台主機,一台服務器,集中中的一個,一個客戶端進程等。
早ZooKeeper這邊文檔中, znodes  表示一個數據節點, Servers表示組成ZooKeeper服務中的機器, quorum peers 表示組成集合的機器,客戶端表示使用一個ZooKeeper服務的主機或進程。
 
Znodes是一個程序訪問的主要實體,在這里有許多值得提到的特性:
 
Watches:
客戶端可以在znodes上設置監聽器,znode的改變觸發這個監聽器然后清空這個監聽器。當一個監聽器被觸發,Zookeeper發送給客戶端一個通知。更多信息可以查看watches章節。
 
數據訪問:
每個znode上存儲的數據的讀寫都是原子的,讀操作取出所有的和這個znode有關的所有數據,寫操作替換所有數據。每個節點有一個訪問權限列表(ACL)限制誰可以做這些事。
 
zookeeper沒有被設計成一個一般的數據庫,或者大型對象存儲。它管理協調數據,數據可以是狀態,配置信息,集合點等的形式。各種各樣的數據有一個共同的屬性就是它們都很小:以千字節為標准。
 
ZooKeeper客戶端和服務器有一個健康檢查來確保znodes的數據少於1M,但是數據平均應該更小。操作較大的數據將導致一些操作花費更多的時 間,並且會影響一些操作的延遲,因為在網絡和存儲媒介中移動更多的數據將需要額外的時間。如果需要存儲大數據,通常的處理是把數據存儲在一個大容量存儲系 統中,並把存儲位置的指針存儲到ZooKeeper上。
 
臨時節點:
zookeeper也有臨時節點的概念。這些znodes存活的時間和創建這個節點的會話有效期是一樣的。當會話結束,節點被刪除。因為這種臨時節點的特性,臨時節點不允許有子節點。
 
順序節點——唯一名稱:
當創建一個節點的時候,也可以請求zookeeper在路徑后面增加一個自增的計數器。對父節點來說,這個計數器是唯一的。計數器是%010d的格式( 十進制整數輸出,寬度10位,不足前面補0;)——是一個十位數,比如:<path>0000000001。
 
 
zookeeper中的時間
 
Zookeeper以多種方式跟蹤時間:
  • Zxid: ZooKeeper狀態的每次變化都接收一個zxid(ZooKeeper事務id)形式的標記。這個展示了所有的ZooKeeper的變更順序。每次變更會有一個唯一的zxid,如果zxid1小於zxid2說明zxid1在zxid2之前發生。
  • Version numbers: 節點的每次變化都會引起這個節點版本號之一的一次增加。這三個版本號是:version(一個節點的數據變化次數),cversion(一個節點的子節點變化次數),aversion(一個節點的ACL 變化次數)。
  • Tricks: 當使用多個ZooKeeper服務,服務器使用ticks來確定事件的時間,比如說狀態上傳、會話超時、連接超時等。這個tick時間僅僅通過最小會話超 時時間間接的暴露出來;如果一個客戶端請求會話的超時時間小於最小超時時間,服務器將會告訴客戶端實際的會話超時時間是最小超時時間。
  • Real Time:  ZooKeeper不使用實時、時鍾時間。除了把時間戳放在stat結構中。
 
 ZooKeeper Stat 結構

每個節點的Stat結構由下列字段組成:

  • czxid:該數據節點被創建時的事務id。
  • mzxid:該節點最后一次被更新時的事務id。
  • ctime:節點被創建時的時間。
  • mtime:節點最后一次被更新時的時間。
  • version:這個節點的數據變化的次數。
  • cversion:這個節點的子節點 變化次數。
  • aversion:這個節點的ACL變化次數。
  • ephemeralOwner:如果這個節點是臨時節點,表示創建者的會話id。如果不是臨時節點,這個值是0。
  • dataLength:這個節點的數據長度。
  • numChildren:這個節點的子節點個數。
 
zookeeper 會話
通過使用一種語言綁定來創建服務端的句柄,一個zookeeper客戶端可以和zookeeper服務創建會話。一旦創建,句柄開始在CONNECTING狀態,客戶端庫嘗試連接組成zookeeper服務中的一個服務器,並且切換到CONNECTED狀態。在正常的操作期間將會是這兩種狀態之一。如果一個不可恢復的錯誤發生了,比如說會話過期或者授權失敗,或者應用顯示的關閉了句柄,句柄將會到CLOSED狀態。下圖展示了一個zookeeper可能的狀態轉變。
 

為了創建一個客戶端會話,應用程序代碼必須提供一個連接字符串列表以逗號分隔開,主機:端口號成對出現,每個都相當於一個ZooKeeper服務器 (例如:”127.0.0.1:4545″  或 “127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002″)。

 
ZooKeeper客戶端將會選擇任意一個服務器並嘗試連接他。如果連接失敗,或如果客戶端由於某些原因從服務器斷開連接,客戶端將會自動嘗試列表中的下一個服務器,直到一個連接建立。
 
3.2.0新增:“chroot”后綴可以被加在連接字符串后面,這會運行客戶端命令導致所有的路徑都和這個跟路徑相關。如果使用像下面的示 例:”127.0.0.1:4545/app/a或 “127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002 /app/a” ,客戶端將把”/app/a”作為跟路徑,並且所有的路徑都與這個根路徑相關,比如getting、setting等。”/foo/bar” 將導致操作在”/app/a/foo/bar”(從服務端的觀點來看)。這個特性在多租戶下面是非常也有用的,ZooKeeper服務的每個用戶可以有不 同的根路徑。這讓再使用變得非常簡單,因為每個用戶都可以編寫代碼讓他的應用好像在”/”根路徑下,但實際的位置能在部署時決定。
 

當一個客戶端從ZooKeeper服務得到一個句柄,ZooKeeper創建了一個會話,表現為一個64位的數字,並把 它分配給客戶端。如果客戶端連接到一個不同的服務端,在連接握手的時候它將發送這個會話id。作為一個安全措施,服務端給會話id創建了一個密碼,讓服務 端能夠校驗。當客戶端建立會話的時候,這個密碼隨着會話id一起發送給客戶端。每當客戶端與一個新的服務端恢復會話的時候,密碼會隨着會話id一起發送過 去。

 
客戶端調用創建會話的時候有一個參數是會話超時時間(毫秒),客戶端發送一個要求的超時時間,服務端回復一個他能給客戶端的超時時間。當前實現要求 超時時間至少是2倍的tickTime,最大是20倍的tickTime。ZooKeeper客戶端API允許使用一個協商的超時時間。
 

當一個客戶端從ZK服務集群成為分區,它將開始尋找在會話創建時期指定的服務端列表。最終,當客戶端和至少一個服務端聯通重新建立的時候,會話要么 轉變成“connected”狀態(如果在會話超時時間內恢復連接),要么轉變成“expired”狀態(如果在超時時間之外恢復連接)。在斷開時創建一 個新的會話是不可取的。ZK客戶端庫將處理連接。尤其是客戶端內部有方法來處理像“羊群效應”之類的事情。僅僅在你被通知會話過期的時候去創建一個新的會 話。

 
ZooKeeper集群自己管理會話過期,而不是由客戶端管理。當ZK客戶端和一個集群建立會話,它提供一個“超時時間”。這個值被集群使用來決定 客戶端的會話是否過期。當集群不能在指定的會話超時時間內從客戶端收到信息,過期發生。在會話過期期間,集群將刪除由這個會話創建的所有的臨時節點,並且 立即通知連接的客戶端這個改變。此時,會話過期的客戶端依然和集群式斷開的,它不會收到通知直到它能和集群重新建立連接。這個客戶端將保持斷開狀態直到和 集群的TCP連接重新建立,並且在這個時候,過期會話的監聽將會收到“會話過期”通知。
 

對於一個過期的會話,監聽器所看到的狀態轉變:

  1. “connected”:會話被建立,並且客戶端能和集群交流
  2. ……客戶端從集群被分割
  3. “disconnected”:客戶端與集群丟失了聯系
  4. ……時間流逝,在超時時間之后,集群已經讓這個會話過期,而客戶端沒看到什么,因為它已經從集群斷開連接了
  5. ……時間流逝,客戶端恢復網絡和集群聯通
  6. “expired”:最后客戶端與集群重新連接,然后收到過期的通知
 
ZooKeeper會話建立的另一個參數是默認監聽器。當客戶端的一些狀態改變發生,監聽器會收到通知。比如如果客戶端丟失與服務端的連接,客戶端將會收到通知,或客戶端的會話到期等。這個監聽器應該考慮初始狀態到斷開連接。對於一個新的連接,第一個發給監聽器的事件就是會話連接事件。
 
客戶端通過發送請求保持會話存活。如果會話在一段時間內空閑將會導致會話超時,客戶端將會發送PING請求保持會話存活。這個PING請求不僅僅讓 ZooKeeper服務端知道客戶端是存活的,而且讓客戶端檢查它的和ZooKeeper 服務端的連接也是存活的。PING的時間是足夠保守的合理時間,來發現死掉的連接和一個新的服務端重新連接。
 

一旦成功建立一個到服務端的連接,當客戶端發生connectionloss異常 時有兩種基本的情況,在執行一個同步或者非同步的操作時:

  1. 應用調用一個操作,但是會話不再存活。
  2. 當等待一個操作的時候ZooKeeper客戶端從服務端斷開連接,比如說:等待一個異步調用。
 
 
3.2.0新增——SessionMovedException。有一個內部的異常,通常不會被客戶端發現,被稱為 SessionMovedException。一個已經連接的會話但是重新連接到了一個不同的服務器上接收了一個請求,這個異常就會發生。這個錯誤的正常 原因是一個客戶端發送了一個請求到一個服務端,但是網絡數據包延遲了,所以客戶端超時並連接到了一個新的服務器。當延遲的數據包到達了第一個服務器,這個 服務端發現這個會話已經被移除了並且關閉了這個客戶端連接。客戶端一般不會發現這個錯誤因為它們不在從老的連接讀取數據(老的連接一般被關閉了)。這種事情發生的另一種情況是當兩個客戶端使用一個保存的會話id和密碼來嘗試恢復相同的連接時,只有一個客戶端能夠恢復連接,另一個客戶端將會斷開。
 
更新服務器列表。我們允許一個客戶端更新連接字符串通過提供一個新的逗號分隔的主機:端口號列表,每個都是一個服務器。函數調用一個概率負載均衡算法會引起客戶端斷開與當前主機的連接,來使在新列表中的每個服務器達到與預期一致的數量。萬一客戶端連接的當前主機不在新的列表中,這個調用會引起連接被刪除。另外,這個決定基於是否服務器的數量增加或減少了多少。
 
 
比如說,如果之前的連接包含三個主機,現在的連接多了兩個主機,連接到每個主機的客戶端的40%為了負載均衡將會移動到新的主機上去。這個算法會引起客戶端斷掉它當前與服務器的連接,這個概率是0.4,並且客戶端隨機選擇兩個新主機中的一個連接。

另一個例子,假設我們有5個主機,然后現在更新列表移除兩個主機,連接到剩余三台主機的客戶端依然保持連接,然而所有連接到已被移除主機的客戶端都 需要移到剩下三台主機的一台上,並且這種選擇是隨機的。如果連接斷開,客戶端進入一個特殊的模式並使用概率算法選擇一個新的服務器,而不僅僅只是循環。

 
在第一個例子中,每個客戶端決定斷開連接的概率為0.4,但是一旦做了決定,它將會隨機的連接到一個新的服務器,僅僅當它不能連接到任何一台新的服 務器上時,它將嘗試連接舊的服務器。當找到一個服務器或者新列表中所有的服務器都連接失敗的時候,客戶端回到操作正常模式,選擇一個任意的服務器並嘗試連接它,如果連接失敗,它會繼續嘗試不同的隨機的服務器,並一直循環下去。
 
 
ZooKeeper Watches
 
ZooKeeper中所有的讀操作——getData(), getChildren()和 exists()—可以選擇設置 一個監聽器。這是ZooKeeper’s一個監聽器的定義:一個監聽事件是一次性觸發,當一個被設置監聽的數據改變時,發送給設置這個監聽器的客戶端。在這個監聽器的定義中,有三個要點:
 
  • 一次性觸發:當數據改變的時候一個監聽事件會被發送給客戶端。比如說,如果一個客戶端做了getData(“/znode1″, true)操作,然后 /znode1下的數據被改變或者刪除了,客戶端將得到/znode1的一個監聽事件。如果/znode1節點再次發生改變,沒有監聽事件會被發送,除非客戶端做了別的,設置了一個新的監聽器。
 
  • 發送到客戶端:這意味着事件正在發送給客戶端的途中,但是在操作成功的返回碼到達發起這個變更操作的客戶端之前,事件可能還沒到達監聽的客戶端。 ZooKeeper提供了一個有序保證:在它第一次看到監聽事件之前,它永遠不會看到它設置的監聽改變。網絡延遲或別的因素,可能會引起不同的客戶端看見監聽器和更新操作的返回碼,在不同的時間。關鍵得一點是不同的客戶端看見的每件事有一個一致的順序。
 
  • 被設置監聽的數據:這是指一個節點能變化的不同方式。可以認為ZooKeeper有兩個監聽器列表:數據監聽和子節點監聽。getData()和 exists()設置數據監聽器。 getChildren()設置子節點監聽器。二選一,根據返回數據的類型來設置監聽器。getData()和exists()返回節點的數據信息,然而 getChildren()返回一個子節點列表。因此,setData()會觸發數據監聽器。一個成功的 create()會觸發一個數據監聽器。一個delete()會觸發數據監聽器和子節點監聽器。
 
在ZooKeeper服務器中,當客戶端連接的時候,監聽器被保存在本地。這使得監聽器輕量級的被設置、保存、分發。當一個客戶端連接一個新的服務器,監聽器會觸發一些會話事件。當從服務器斷開連接的時候,不會收到監聽器。當一個客戶端重新連接,如果需要的話,之前注冊的監聽器會被注冊和觸發。有一個監聽器可能丟失的情況:如果在斷開連接期間,一個節點被創建和刪除,一個已存在的節點的監聽器還沒有創建,將丟失。
 

監聽器的意思

 
我們能在三種調用讀取ZooKeeper狀態的情況下設置監聽器:exists,getData和getChildren,下面的列表是一個監聽器觸發的事件的詳細情況:
 
  • 創建事件:exists的調用
  • 刪除事件:exists,getData和getChildren的調用
  • 改變事件:exists,getData的調用
  • 子節點事件:getChildren的調用
 

移除監聽器

 
我們可以調用removeWatches來移除一個注冊在節點上的監聽器。同樣的,一個ZooKeeper客戶端在沒有服務器連接的情況下能移除本地的監聽器,通過設置本地的標記為true。下面是事件的詳細列表監聽器成功的被移除后觸發:
 
  • 子節點移除事件:調用getChildren增加的監聽器。
  • 數據移除事件:調用exists或getData增加的監聽器。

ZooKeeper對監聽器的保證

對於監聽器,ZooKeeper有下列的保障:

  • 監聽器和另外的事件,另外的監聽器和異步的回復是有序的。ZooKeeper 客戶端庫確保每件事都有序分發。
  • 一個客戶端看到這個節點的新的數據之前,會先看到他監聽的節點的一個監聽事件。
  • 從ZooKeeper 來的監聽事件的順序對應於ZooKeeper 服務看到的更新的順序。
 
關於監聽器要記住的事情
 
  • 監聽器是一次觸發的,如果你得到了一個監聽事件並且想繼續得到未來的事件通知,你必須設置一個另外的監聽器。
  • 因為監聽器是一次觸發的,就會在得到事件和發送請求設置新的監聽器之間有一個延遲,你不能看到ZooKeeper的節點上每次 改變。准備好處理在得到事件和設置監聽器之間節點多次改變的情況(你或許不太關心,但至少要意識這會發生)。
  • 一個監聽器對象或一個函數/上下文對,為一個事件只會被觸發一次。比如說,如果相同的監聽器在一次exists或getData調用中被注冊到了相同的文件,並且文件被刪除,對於該文件刪除的通知,監聽器對象只會被調用一次。
  • 當你從服務器斷開連接,在恢復連接之前,你不會得到任何監聽器。由於這個原因,會話事件會被發送給所有的未處理的監聽器。使用會話事件進入一個安全模式:在斷開期間,你不會收到事件,所以你的進程在這種模式下應該小心行事。
 
ZooKeeper使用ACLs控制訪問
 

ZooKeeper使用ACLs來控制訪問它的節點(ZooKeeper數據樹上的數據節點)。ACL的實現和UNIX文件訪問權限非常相似:它使 用權限位來允許/拒絕對節點和位適用范圍的各種操作。不像標准的UNIX權限,一個ZooKeeper節點沒有限制在這三個標准的范圍:user (文件擁有者)、group、world 。ZooKeeper沒有節點擁有者的概念,取而代之的是,一個ACL指定ids和id相關的權限的集合。

還請注意一個ACL只適用於一個指定的節點,它也不適用於子節點。比如說,如果 /app節點只能被ip:172.16.16.1讀取, /app/status是全部可讀的,任何人都 可以讀取/app/status。ACLs不是遞歸的。

ZooKeeper支持可插拔式的認證方案。Ids指定使用這個形式scheme:idscheme是id對應的授權方案,比如說,ip:172.16.16.1是一個主機地址為172.16.16.1的id

當一個客戶端連接ZooKeeper並進行認證,ZooKeeper把符合這個客戶端的所有ids聯系起來。當客戶端嘗試存取一個節點的時候,這些ids用來檢查一個節點的ACLs。ACLs由成對(scheme:expression, perms)的組成。expression的格式指定了權限,比如說,(ip:19.22.0.0/16, READ)給所有的以19.22開頭的IP地址的客戶端讀的權限。

 
ZooKeeper支持下列權限:
 
  • CREATE:可以創建一個子節點
  • READ:可以從一個節點讀取數據並展示子節點
  • WRITE:可以設置一個節點的數據
  • DELETE:可以刪除一個子節點
  • ADMIN:可以設置權限


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM