分佈式系統中基於ZooKeeper的服務註冊中心設計

一、服務註冊中心

對於服務提供者,它需要發佈服務;由於應用系統的複雜性,服務的數量、類型不斷膨脹;對於服務消費者,它最關心的是如何獲取到它所需要的服務。對於服務提供方和消費方來說,它們還有可能兼具這兩種角色;既需要提供服務,又需要消費服務。

如何有效地管理服務訂閱/發佈,避免硬編碼地址信息是分佈式服務框架需要解決的一個問題。通過將服務統一管理起來,可以有效地優化內部應用對服務發佈/使用的流程和管理,服務註冊中心就是專門用來管理服務訂閱/發佈的配置管理節點。

二、幾個概念

1. 服務提供者

服務提供者是發佈服務的服務提供方,它通常就是一個普通的Java實現類。

<code><bean><service>/<bean>/<code>

2. 服務消費者

服務消費者是調用遠程服務的消費方,它可能是個簡單的客戶端、Web前臺,也可能嵌套在某個服務的內部。消費者的配置示例如下:

<code><reference><bean>    <property>/<bean>/<reference>/<code>

3. 服務註冊中心

服務註冊中心是分佈式服務框架的目錄服務器,相比於傳統的目錄服務器,它有如下幾個特點:

HA:支持數據持久化、支持集群 數據一致性問題:集群中所有的客戶端應用看到同一份數據,不能出現讀或者寫數據不一致 數據變更主動推送:當註冊中心的數據發生變更時需要能夠及時將變化的數據通知給客戶端

三、關鍵功能特性設計

工作原理圖示:

分佈式系統中基於ZooKeeper的服務註冊中心設計

角色 說明

Provider 暴露服務的服務提供方

Consumer 調用遠程服務的服務消費方

Registry 服務註冊與發現的註冊中心

Monitor 統計服務的調用次調和調用時間的監控中心

Container 服務運行容器

說明:

1. 服務提供者在啟動時,根據服務發佈文件中配置的服務發佈信息向註冊中心註冊自己提供的服務
2. 服務消費者在啟動時,根據消費者配置文件中配置的服務消費信息向註冊中心訂閱自己所需的服務,消費者刷新本地緩存的路由表
3. 註冊中心返回服務提供者地址列表給消費者,如果有變更,註冊中心主動推送變更數據給消費者,消費者刷新本地緩存的路由表
4. 服務消費者從本地緩存的服務提供者地址列表中,基於負載均衡算法選擇一臺服務提供者進行調用。

1. 支持對等集群

服務註冊中心需要支持對等集群,其中一個或多個服務註冊中心進程宕機,不會導致服務註冊中心集群功能不可用

對於客戶端,無論註冊中心集群配置多少個進程,客戶端只需要連接其中某一個即可

2. 提供CRUD接口

3. 安全加固

服務註冊中心需要進行安全加固,安全加固主要涉及兩部分:

鏈路的安全性 數據的安全性

鏈路的安全性指的是服務註冊中心對客戶端連接進行安全認證,認證策略非常多,最簡單的就是基於IP地址的黑名單校驗,更加複雜的有基於用戶名+密碼的認證,或者基於密鑰+數字證書的認證。

認證失敗,則關閉鏈路,拒絕客戶端連接。

數據的安全性主要針對服務註冊中心的數據進行權限控制:

非授權客戶端既不能讀也不能寫 普通運維人員只能讀,不能修改 管理員既可以讀也可以修改 不同的服務目錄可以設置不同的訪問權限,例如消費者只能查看它所在機房的服務

4. 訂閱發佈機制

服務註冊中心需要支持服務的訂閱發佈,對於服務提供者,可以根據服務名等信息動態發佈服務;對於消費者,可以根據訂閱關係主動獲得服務發佈者的地址信息等 。
訂閱發佈機制還且個比較重要的機制就是對變化的監聽有主動推送的能力。

5. 可靠性

四、 基於ZooKeeper的服務註冊中心設計

1. 服務訂閱發佈流程設計

第一步:ZooKeeper客戶端通過創建org.apache.zookeeper.ZooKeeper的一個實例對象連接ZooKeeper服務器,然後調用這個類提供的接口來和服務器交互
第二步:根據服務提供者發佈的服務列表,循環調用create(String path,byte[] data,List acl,createMode)接口,創建目錄節點,同時將服務屬性定稿目錄節點的內容中。create方法用於創建一個給定路徑的目錄節點,並給它設置數據。


第三步:與第一步相同
第四步:消費者根據消費的服務名,從ZooKeeper Server的服務發佈目錄中查詢已經發布的服務地址和屬性信息。getData(String path,boolean watch,Stat stat)方法用於獲取這個path對應的目錄節點存儲的數據,數據的版本等信息可以通過stat來指定,同時還可以設置是否監控這個目錄節點數據的狀態。獲得服務提供者信息之後,將其更新到本地緩存中,避免每次服務調用都要實時去ZooKeeper Server查詢。
第五步:消費者監聽服務提供者目錄列表,當有服務上下線時,可以獲取ZooKeeper Server的通知消息。
第六步:服務提供者調用 create(String path,byte[] data,List acl,CreateMode cretaeMode)方法動態註冊新的服務
第七步:消費者通過監聽器Watcher的process(WatchedEvent event)方法獲取變更的路徑信息,然後調用 getData(String path,boolean watch,Stat stat)接口獲取變更的數據,最後更新本地緩存的服務路由表。
第八步:服務提供者取消已發佈的服務,調用delete(String path,int version)方法刪除path對應的目錄節點,version為-1可以匹配任何版本,也就刪除了這個目錄節點的所有數據。
第九步:消費者接收到變更通知推送消息後,根據刪除的路徑獲取刪除的具體服務信息;更新緩存的服務路由表,將已經下線的服務從路由表中刪除
第十步:ZK客戶端與服務器的連接會話終止,存儲在ZK上的所有臨時數據與註冊的訂閱者都被自動移除

第十一步:消費者獲取服務列表被刪除的通知消息後,更新本地緩存的路由表,將發生會話超時的服務提供者從路由表中清除掉
實際項目中,消費者與服務提供者的啟動順序是無法控制的。

2. 服務健康狀態檢測

基於ZK客戶端和服務端的長連接和會話超時控制機制,可以非常方便 地實現服務健康狀態檢測。

3. 對等集群防止單點故障

4. 變更通知機制

服務提供者將服務註冊消息保存在ZooKeeper的某個服務目錄節點中,消費者監控服務配置信息的狀態,一旦配置信息發生變化,集群中的每個消費者實例就會收到ZooKeeper通知,然後從ZooKeeperServer獲取新的服務註冊信息應用到系統中。

五、dubbo服務註冊中心

分佈式系統中基於ZooKeeper的服務註冊中心設計

/dubbo:這是dubbo在ZooKeeper上創建的根節點; /dubbo/com.foo.BarService:這是服務節點,代表了Dubbo的一個服務; /dubbo/com.foo.BarService/providers:這是服務提供者的根節點,其子節點代表了每一個服務真正的提供者;

註冊中心的工作流程

1)服務提供方啟動

服務提供者在啟動的時候,會在ZooKeeper上註冊服務。所謂註冊服務,其實就是在ZooKeeper的/dubbo/com.foo.BarService/providers節點下創建一個子節點,並寫入自己的URL地址,這就代表了com.foo.BarService這個服務的一個提供者。

2)服務消費者啟動

服務消費者在啟動的時候,會向ZooKeeper註冊中心訂閱自己的服務。其實,就是讀取並訂閱ZooKeeper上/dubbo/com.foo.BarService/providers節點下的所有子節點,並解析出所有提供者的URL地址來作為該服務地址列表。

同時,服務消費者還會在ZooKeeper的/dubbo/com.foo.BarService/consumers節點下創建一個臨時節點,並寫入自己的URL地址,這就代表了com.foo.BarService這個服務的一個消費者。

3)消費者遠程調用提供者

服務消費者,從提供者地址列表中,基於軟負載均衡算法,選一個提供者進行調用,如果調用失敗,再選另一個提供者調用。

4)增加服務提供者

增加提供者,也就是在providers下面新建子節點。一旦服務提供方有變動,zookeeper就會把最新的服務列表推送給消費者。

5)減少服務提供者

所有提供者在ZooKeeper上創建的節點都是臨時節點,利用的是臨時節點的生命週期和客戶端會話相關的特性,因此一旦提供者所在的機器出現故障導致該提供者無法對外提供服務時,該臨時節點就會自動從ZooKeeper上刪除,同樣,zookeeper會把最新的服務列表推送給消費者。

6)ZooKeeper宕機之後

消費者每次調用服務提供方是不經過ZooKeeper的,消費者只是從zookeeper那裡獲取服務提供方地址列表。所以當zookeeper宕機之後,不會影響消費者調用服務提供者,影響的是zookeeper宕機之後如果提供者有變動,增加或者減少,無法把最新的服務提供者地址列表推送給消費者,所以消費者感知不到。


專注於技術熱點大數據,人工智能,JAVA、Python、 C 、GO、Javascript等語言最新前言技術,及業務痛點問題分析,請關注【編程我最懂】共同交流學習。


分享到:


相關文章: