來源以及完整的文章:https://yq.aliyun.com/articles/601745?spm=a2c4e.11153940.blogcont604028.19.6daf2a38OLvUBo
注冊中心需求分析及關鍵設計考量
接下來,讓我們回歸對服務發現的需求分析,結合阿里巴巴在關鍵場景上的實踐,來一一分析,一起探討為何說 ZooKeeper 並不是最合適的注冊中心解決方案。
注冊中心是 CP 還是 AP 系統?
CAP 和 BASE 理論相信讀者都已經耳熟能詳,其業已成了指導分布式系統及互聯網應用構建的關鍵原則之一,在此不再贅述其理論(CAP以及BASE理論),我們直接進入對注冊中心的數據一致性和可用性需求的分析。
數據一致性需求分析
注冊中心最本質的功能可以看成是一個Query函數 Si = F(service-name),以 service-name 為查詢參數,service-name 對應的服務可用的 endpoints (ip:port) 列表為返回值.
注: 后文將 service 簡寫為 svc。
先來看看關鍵數據 endpoints (ip:port) 不一致性帶來的影響,即 CAP 中的 C 不滿足帶來的后果 :

如上圖所示,如果一個 svcB 部署了10個節點 (副本/Replica),如果對於同一個服務名 svcB, 調用者 svcA 的2個節點的2次查詢返回了不一致的數據,例如: S1 = { ip1,ip2,ip3...,ip9 }, S2 = { ip2,ip3,....ip10 }, 那么這次不一致帶來的影響是什么?
其實影響很小,只是服務提供者svcB 的各個節點流量會有一點不均衡。
ip1和ip10相對其它8個節點{ip2...ip9},請求流量小了一點,但很明顯,在分布式系統中,即使是對等部署的服務,因為請求到達的時間,硬件的狀態,操作系統的調度,虛擬機的 GC 等,任何一個時間點,這些對等部署的節點狀態也不可能完全一致,而流量不一致的情況下,只要注冊中心在SLA承諾的時間內(例如1s內)將數據收斂到一致狀態(即滿足最終一致),流量將很快趨於統計學意義上的一致,所以注冊中心以最終一致性的模型設計在生產實踐中完全可以接受。
分區容忍及可用性需求分析
接下來我們看一下網絡分區(Network Partition)情況下注冊中心不可用對服務調用產生的影響,即 CAP 中的A不滿足時帶來的影響。
考慮一個典型的ZooKeeper三機房容災5節點部署結構 (即2-2-1結構),如下圖:

如上圖,3個機房分別都有Zookeeper注冊中心和應用服務集群,應用服務優先注冊到同機房的Zookeeper注冊中心;
當同機房的ZK注冊中心不可用,應用服務svcB無法注冊到同機房ZK,就會訪問ZK集群的其他節點,上圖由於出現了網絡分區故障,機房3無法與其他機房通信,所以svcB不能注冊到任何ZK上,而且應用服務svcA也無法訪問任何ZK,無法調用svcB;
此時,當機房3出現網絡分區(Network Partitioned)的時候,即機房3在網絡上成了孤島,我們知道雖然整體 ZooKeeper 服務是可用的,但是機房3的節點ZK5是不可寫的,因為聯系不上 Leader。
因為機房3節點ZK5不可寫,這時候機房3的應用服務 svcB 是不可以新部署,重新啟動,擴容或者縮容的,但是站在網絡和服務調用的角度看,機房3的 svcA 雖然無法調用機房1和機房2的 svcB,但是與機房3的svcB之間的網絡明明是 OK 的啊,為什么不讓我調用本機房的服務?
現在因為注冊中心自身為了保腦裂(P)下的數據一致性(C)而放棄了可用性,導致了同機房的服務之間出現了無法調用,這是絕對不允許的!可以說在實踐中,注冊中心不能因為自身的任何原因破壞服務之間本身的可連通性,這是注冊中心設計應該遵循的鐵律! 后面在注冊中心客戶端災容上我們還會繼續討論。
同時我們再考慮一下這種情況下的數據不一致性,如果機房1,2,3之間都成了孤島,那么如果每個機房的svcA都只拿到本機房的 svcB 的ip列表,也即在各機房svcB 的ip列表數據完全不一致,影響是什么?
其實沒啥大影響,只是這種情況下,全都變成了同機房調用,我們在設計注冊中心的時候,有時候甚至會主動利用這種注冊中心的數據可以不一致性,來幫助應用主動做到同機房調用,從而優化服務調用鏈路 RT 的效果!
通過以上我們的闡述可以看到,在 CAP 的權衡中,注冊中心的可用性比數據強一致性更寶貴,所以整體設計更應該偏向 AP,而非 CP,數據不一致在可接受范圍,而P下舍棄A卻完全違反了注冊中心不能因為自身的任何原因破壞服務本身的可連通性的原則。
服務調用(請求響應流)鏈路應該是弱依賴注冊中心,必須僅在服務發布,機器上下線,服務擴縮容等必要時才依賴注冊中心
Service Health Check
使用 ZooKeeper 作為服務注冊中心時,服務的健康檢測常利用 ZooKeeper 的 Session 活性 Track機制 以及結合 Ephemeral ZNode的機制,簡單而言,就是將服務的健康監測綁定在了 ZooKeeper 對於 Session 的健康監測上,或者說綁定在TCP長鏈接活性探測上了。
這在很多時候也會造成致命的問題,ZK 與服務提供者機器之間的TCP長鏈接活性探測正常的時候,該服務就是健康的么?答案當然是否定的!注冊中心應該提供更豐富的健康監測方案,服務的健康與否的邏輯應該開放給服務提供方自己定義,而不是一刀切搞成了 TCP 活性檢測!
健康檢測的一大基本設計原則就是盡可能真實的反饋服務本身的真實健康狀態,否則一個不敢被服務調用者相信的健康狀態判定結果還不如沒有健康檢測。
