如何在多區域執行Zookeeper?- Ankur

banq發表於2021-08-19

Zookeeper將自己定義為“用於維護配置資訊的集中式服務”等。為了對資料建模,它使用具有路徑作為識別符號並儲存值的znode。在 Flipkart,我們使用 zookeeper 作為為多個應用程式提供配置管理的平臺的首選後端。代表每個配置物件的 znode 儲存一個小的 JSON 有效負載。該平臺還將配置更改傳播給感興趣的客戶端,並在時間敏感的用例中影響他們的執行時行為。
在 Flipkart,我們經常以主-主模式部署應用程式,為來自多個區域的使用者或內部流量提供服務。這確保了我們對一個資料中心或可用性區域的故障保持彈性,以便我們可以繼續為我們的客戶和賣家提供服務。支援這種持續可用的應用程式通常需要我們的平臺提供全域性配置物件,即可用於跨區域讀取和寫入。
在本文中,我們首先對 Zookeeper 的相關功能和事實進行說明性的回顧。我們進一步描述了一組經過編譯的最佳實踐,這些實踐在 Flipkart 部署時對我們很有效,以確保以下方面:
  1. 跨區域強一致性寫入:Zookeeper 在多區域仲裁中實現協調。
  2. 處理單區域故障或連結故障:即使一個區域完全當機或暫時與其他區域斷開連線,Zookeeper 仍可用於其他區域的讀寫。
  3. 在隔離區域中保持讀取可用:如果一個區域與其他區域隔離(多個連結故障),Zookeeper 可用於讀取。


 

Zookeeper:說明性的回顧

  • 從記憶體中提供服務的 KV 儲存

Zookeeper 只能充當小資料集的 KV 儲存,因為無論叢集中的例項數量如何,整個資料都必須適合單個例項的記憶體。另一方面是讀取速度很快。
  • 任何寫操作都需要多數人的確認

寫入必須由至少 1 個從節點跟隨者確認(因為領導者無論如何都會處理寫入請求)。從使用者的角度來看,這可能會導致其他跟隨者在一段時間內提供陳舊資料。您可以在此處閱讀有關 zookeeper 提供的順序讀取一致性的更多資訊。
  • 寫入是有序的

每個 znode 都有一個版本,該版本會在成功寫入操作時更新。該版本用於檢測對 znode 進行的任何併發修改。Zookeeper 拒絕這樣的寫提議並確保一致性。
  • 支援在znodes增加watch

它支援在 Zookeeper 之上構建變更傳播系統,同時不需要客戶端不斷輪詢。客戶端使用 znode 路徑和已知版本與 Zookeeper 叢集中的任何例項連線以設定監視。每當 znode 更新/刪除或建立時(如果 znode 不存在),伺服器都會通知客戶端。
 

多區域 Zookeeper:什麼、為什麼和如何
我們將多區域 zookeeper 定義為一種部署,其中叢集的投票成員分佈在多個區域。它允許我們為主動-主動應用程式提供集中配置,並使平臺免受資料中心/區域故障和網路分割槽的影響。
在本節中,我們將介紹在生產環境中跨區域部署 zookeeper 時的一些有用的最佳實踐。

  • 跨至少 3 個區域部署例項

Zookeeper 是一個基於共識的資料儲存。該叢集由參與法定人數的投票成員和可選的非投票成員組成,稍後將介紹這些成員。一旦被大多數投票成員在內部確認,寫入就會成功地向客戶端確認。這意味著只要 Zookeeper 叢集中有 (n/2) + 1 個可用例項,它就仍然可用於寫入和讀取。
通常,zookeeper 與大小為 5 或 7 的集合一起執行。對於多區域 zookeeper,如果將 5 個例項公平地分佈在兩個區域中,則意味著在區域 1 (R1) 中部署了 3 個例項,在 R2 中部署了 2 個例項。這種設定有一個主要缺點。如果 R1(擁有叢集的大多數例項)出現鏈路故障或區域故障,區域 R2 中的客戶端將無法使用,因為它們無法執行寫入或讀取操作。
如果 zookeeper 例項部署在三個區域,則即使單個區域故障(任何)或三個區域之間的任何兩個區域之間的連結故障,也可以保持對客戶端可用。
對於大小為 5 的叢集,這意味著在 R1 中部署 2 個例項,在 R2 中部署 2 個例項,在 R3 中部署 1 個例項。
任何區域都不應該擁有多數:經驗法則是任何一個區域都不應該擁有多數例項。這確保了可用性,儘管區域或鏈路故障。對於 size=7 節點的集合,一些可行的放置策略是:
3,3,1
3,2,2


 

避免跨區域客戶端連線
客戶端可以連線到任何 zookeeper 例項以進行讀取和寫入。當寫入請求被轉發到領導者時,讀取是由例項從其記憶體快取中提供的。
如果客戶端最終連線到不在同一可用性區域中的 zookeeper 例項,則每個請求/響應都會產生跨區域延遲。
這可以透過確保可用性區域中的客戶端僅發現多區域 zookeeper 叢集的本地例項來避免(假設 zookeeper 在該區域中有例項)。一種方法是為 zookeeper 叢集保留特定於區域的域。
警告:如果存在區域性災難或網路分割槽導致本地 zookeeper 例項無法訪問,則部署在該區域的客戶端將無法使用,除非他們可以發現其他區域的 zookeeper 例項。
 

使用觀察者擴充套件讀取
如果不首選跨區域客戶端連線,則意味著在跨 3 個區域的 5 個例項叢集中,對於任何讀/寫請求,客戶端只能連線到 2 個例項。由於zookeeper 通常用於讀取密集型工作負載,因此通常需要將“get”和“watch”請求擴充套件到超出現有zookeeper 例項所能提供的範圍。
觀察者透過充當集合的非投票成員來實現這一點,並且可以為客戶端的任何讀取請求提供最終一致的保證,與投票成員提供的保證相同。主要區別在於觀察員不參與提案的法定人數。
 

啟用zookeeper讀取模式
當一個 zookeeper 例項從叢集的其餘部分被分割槽時,它不提供讀取或寫入服務,並且客戶端斷開連線。我們使用zookeeper作為後端儲存的一些應用程式可以在短時間內處理過時讀取(雖然不是亂序),但不會影響讀取可用性。
在這種情況下,zookeeper 讀取模式可以成為救星。如果在 zookeeper 例項上啟用,它允許在從叢集分割槽時為連線的客戶端提供陳舊的讀取服務。當連線恢復時,這個 zookeeper 例項透過客戶端設定的watch傳送錯過的更新。
當您擁有僅跨 2 個區域的多區域 zookeeper 叢集時,這尤其方便。啟用讀取模式允許區域中的 zk 例項可用於讀取,即使該區域與其他區域在短時間內分割槽也是如此。流行的客戶端庫“curator”提供了一個顯式事件,當它們連線到的 zookeeper 例項進入只讀模式時,客戶端可以偵聽該事件以獲取通知。
 

配置滴答時間

Tick 時間是 zk 叢集中的時間度量單位,直接管理客戶端會話處理和例項間的心跳。例如,如果 Zookeeper 叢集中的一個例項沒有在足夠的滴答聲中以心跳響應,則認為它不健康/不可用。
雖然預設值 2 秒通常已經足夠了,但是根據區域間網路連結的延遲特性,為多區域 zookeeper 調整 `tickTime`。
 

避免寫入繁重的工作負載
考慮到如何將寫入委託給叢集中的領導者,以及每次寫入如何需要來自大多數集合的 ack 來維護全域性排序,zookeeper 不是針對為主要處理建立/更新/刪除的訪問模式。
讀取請求應該至少比叢集中的寫入多一個數量級。事實上,我們努力在我們的生產設定中的讀取和寫入請求數量之間有 2-3 個數量級的差異。在多區域 zookeeper 中,由於增加了跨區域延遲,大量寫入降低叢集的可能性進一步放大。
Zookeeper 沒有內建速率限制。如果您不控制客戶端的行為,那麼謹慎的做法是使用 API 層與您的客戶端進行互動。透過這種方式,您可以控制對 zookeeper 的底層訪問,並保護它免受惡意或意外濫用。
 

進入流量優先順序結構
這可能並不適用於所有人。如果您擁有私有資料中心並維護/管理網路基礎設施以實現跨這些連線的網路基礎設施,您很可能會構建或加入流量優先順序,以確保關鍵網路流量獲得一定的頻寬。這可確保惡意應用程式不會使跨區域網路連結的可用總頻寬飽和。
當您執行多區域 zookeeper 時,如果存在流量優先順序結構,它們可以確保以更高的優先順序處理 zk 例項之間的 chatter 並保證一定的 QoS。
 

概括
一個zookeeper叢集,當部署在至少三個區域時,使得大多數例項不在任何一個區域內,在面對網路分割槽和區域級災難時,可以確保讀寫可用性。像這樣部署的全域性 zookeeper 叢集可以充當雙活應用程式的底層配置儲存。這種跨區域部署還可以利用:

  • Zookeeper 讀取模式可確保更高的讀取可用性
  • 用於擴充套件讀取的觀察器
  • 降低請求/響應延遲的本地例項發現


 

相關文章