談談注冊中心 zookeeper 和 eureka中的CP和 AP


談談注冊中心 zookeeper 和 eureka中的CP和 AP

前言

在分布式架構中往往伴隨CAP的理論。因為分布式的架構,不再使用傳統的單機架構,多機為了提供可靠服務所以需要冗余數據因而會存在分區容忍性P。

冗余數據的同時會在復制數據的同時伴隨着可用性A 和強一致性C的問題。是選擇停止可用性達到強一致性還是保留可用性選擇最終一致性。通常選擇后者。

其中 zookeeper 和 eureka分別是注冊中心CP AP 的兩種的實踐。他們都提供服務注冊中心的功能。建議使用AP。不強求數據的強一致性,達成數據的最終一致性。

服務注冊中心的數據也就是返回的可用服務節點(ip+端口號) 服務A開了0-9十個服務節點,服務B需要調用服務A,兩次查詢返回0-8,1-9 不一致的數據。產生的影響就是0 和9 節點的負載不均衡

只要注冊中心在 SLA 承諾的時間內(例如 1s 內)將數據收斂到一致狀態(即滿足最終一致),流量將很快趨於統計學意義上的一致,所以注冊中心以最終一致的模型設計在生產實踐中完全可以接受。

1 eureka AP

eureka 保證了可用性,實現最終一致性。

Eureka各個節點都是平等的,幾個節點掛掉不會影響正常節點的工作,剩余的節點依然可以提供注冊和查詢服務。而Eureka的客戶端在向某個Eureka注冊或時如果發現連接失敗,則會自動切換至其它節點,只要有一台Eureka還在,就能保證注冊服務可用(保證可用性),只不過查到的信息可能不是最新的(不保證強一致性),其中說明了,eureka是不滿足強一致性,但還是會保證最終一致性

2 zookeeper CP

zookeeper在選舉leader時,會停止服務,直到選舉成功之后才會再次對外提供服務,這個時候就說明了服務不可用,但是在選舉成功之后,因為一主多從的結構,zookeeper在這時還是一個高可用注冊中心,只是在優先保證一致性的前提下,zookeeper才會顧及到可用性

2.1 zookeeper 應用場景

  • 感知消息隊列異步操作后的結果
  • 分布式鎖
  • 元數據 或者配置中心 如 dubbo 和Kafka 都需要zookeeper
    • dubbo 也可以不使用zookeeper 采用直連提供的方式,但限制了分布式的拓展性。

  • HA高可用
    • 主備切換 (兩個服務分別為主備,備用平時不提供服務,當主的掛掉后,備用頂上作為新主。當原來的主恢復后作為新備)

選型依據

在粗粒度分布式鎖,分布式選主,主備高可用切換等不需要高 TPS 支持的場景下有不可替代的作用,而這些需求往往多集中在大數據、離線任務等相關的業務領域,因為大數據領域,講究分割數據集,並且大部分時間分任務多進程 / 線程並行處理這些數據集,但是總是有一些點上需要將這些任務和進程統一協調,這時候就是 ZooKeeper 發揮巨大作用的用武之地。

但是在交易場景交易鏈路上,在主業務數據存取,大規模服務發現、大規模健康監測等方面有天然的短板,應該竭力避免在這些場景下引入 ZooKeeper,在阿里巴巴的生產實踐中,應用對 ZooKeeper 申請使用的時候要進行嚴格的場景、容量、SLA 需求的評估。

所以可以使用 ZooKeeper,但是大數據請向左,而交易則向右,分布式協調向左,服務發現向右。

2.2 不建議使用zookeeper 的場景和原因

不建議使用zookeeper 的原因是當它沒滿足A帶來的影響。

當機房 3 出現網絡分區 (Network Partitioned) 的時候,即機房 3 在網絡上成了孤島,我們知道雖然整體 ZooKeeper 服務是可用的,但是節點 ZK5 是不可寫的,因為聯系不上 Leader。

也就是說,這時候機房 3 的應用服務 svcB 是不可以新部署,重新啟動,擴容或者縮容的,但是站在網絡和服務調用的角度看,機房 3 的 svcA 雖然無法調用機房 1 和機房 2 的 svcB, 但是與機房 3 的 svcB 之間的網絡明明是 OK 的啊,為什么不讓我調用本機房的服務?

現在因為注冊中心自身為了保腦裂 (P) 下的數據一致性(C)而放棄了可用性,導致了同機房的服務之間出現了無法調用,這是絕對不允許的!可以說在實踐中,注冊中心不能因為自身的任何原因破壞服務之間本身的可連通性,這是注冊中心設計應該遵循的鐵律

2.3 zookeeper 的拓展

ZooKeeper 的寫並不是可擴展的,不可以通過加節點解決水平擴展性問題。

要想在 ZooKeeper 基礎上硬着頭皮解決服務規模的增長問題,一個實踐中可以考慮的方法是想辦法梳理業務,垂直划分業務域,將其划分到多個 ZooKeeper 注冊中心,但是作為提供通用服務的平台機構組,因自己提供的服務能力不足要業務按照技術的指揮棒配合划分治理業務,真的可行么?

而且這又違反了因為注冊中心自身的原因(能力不足)破壞了服務的可連通性,舉個簡單的例子,1 個搜索業務,1 個地圖業務,1 個大文娛業務,1 個游戲業務,他們之間的服務就應該老死不相往來么?也許今天是肯定的,那么明天呢,1 年后呢,10 年后呢?誰知道未來會要打通幾個業務域去做什么奇葩的業務創新?注冊中心作為基礎服務,無法預料未來的時候當然不能妨礙業務服務對未來固有聯通性的需求。

2.4 zookeeper 的持久化存儲

ZooKeeper 的 ZAB 協議對每一個寫請求,會在每個 ZooKeeper 節點上保持寫一個事務日志,同時再加上定期的將內存數據鏡像(Snapshot)到磁盤來保證數據的一致性和持久性,以及宕機之后的數據可恢復,這是非常好的特性,但是我們要問,在服務發現場景中,其最核心的數據 - 實時的健康的服務的地址列表是不需要數據持久化的

需要持久化存儲的地方在於一個完整的生產可用的注冊中心,除了服務的實時地址列表以及實時的健康狀態之外,還會存儲一些服務的元數據信息,例如服務的版本,分組,所在的數據中心,權重,鑒權策略信息,service label 等元信息,這些數據需要持久化存儲,並且注冊中心應該提供對這些元信息的檢索的能力。

2.5 容災能力

如果注冊中心(Registry)本身完全宕機了,服務A 調用 服務B 鏈路應該受到影響么?

是的,不應該受到影響。

服務調用(請求響應流)鏈路應該是弱依賴注冊中心,必須僅在服務發布,機器上下線,服務擴縮容等必要時才依賴注冊中心。

這需要注冊中心仔細的設計自己提供的客戶端,客戶端中應該有針對注冊中心服務完全不可用時做容災的手段,例如設計客戶端緩存數據機制(我們稱之為 client snapshot)就是行之有效的手段。另外,注冊中心的 health check 機制也要仔細設計以便在這種情況不會出現諸如推空等情況的出現。

ZooKeeper 的原生客戶端並沒有這種能力,所以利用 ZooKeeper 實現注冊中心的時候我們一定要問自己,如果把 ZooKeeper 所有節點全干掉,你生產上的所有服務調用鏈路能不受任何影響么?而且應該定期就這一點做故障演練。

zookeeper 的健康檢查

使用 ZooKeeper 作為服務注冊中心時,服務的健康檢測常利用 ZooKeeper 的 Session 活性 Track 機制 以及結合 Ephemeral ZNode 的機制,簡單而言,就是將服務的健康監測綁定在了 ZooKeeper 對於 Session 的健康監測上,或者說綁定在 TCP 長鏈接活性探測上了。

這在很多時候也會造成致命的問題,ZK 與服務提供者機器之間的 TCP 長鏈接活性探測正常的時候,該服務就是健康的么?答案當然是否定的!注冊中心應該提供更豐富的健康監測方案,服務的健康與否的邏輯應該開放給服務提供方自己定義,而不是一刀切搞成了 TCP 活性檢測!

健康檢測的一大基本設計原則就是盡可能真實的反饋服務本身的真實健康狀態,否則一個不敢被服務調用者相信的健康狀態判定結果還不如沒有健康檢測。

參考博客


免責聲明!

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



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