從0開始學微服務:05 如何註冊和發現服務?

從0開始學微服務:05 如何註冊和發現服務?

專欄上一期,我給你介紹了服務發佈和引用常用的三種方式:RESTful API、XML 配置以及 IDL 文件。假設你已經使用其中一種方式發佈了一個服務,並且已經在一臺機器上部署了服務,那我想問你個問題,如果我想調用這個服務,我該如何知道你部署的這臺機器的地址呢?

這個問題就跟我想去吃肯德基一樣,我可以去谷歌地圖上搜索肯德基,然後谷歌地圖會返回所有的肯德基店面的地址,於是我選擇距離最近的一家去吃。這裡面谷歌地圖就扮演了一個類似註冊中心的角色,收錄了所有肯德基店面的地址。

同理,我想知道這臺服務器的地址,那是不是可以去一個類似“谷歌地圖”的地方去查呢?是的,在分佈式系統裡,就有一個類似的概念,不過它的名字可不是叫什麼地圖,而是叫註冊中心。但原理和地圖其實差不多,就是將部署服務的機器地址記錄到註冊中心,服務消費者在有需求的時候,只需要查詢註冊中心,輸入提供的服務名,就可以得到地址,從而發起調用。

下面我來給你詳細講解下注冊中心的原理和實現方式。

註冊中心原理

在微服務架構下,主要有三種角色:服務提供者(RPC Server)、服務消費者(RPC Client)和服務註冊中心(Registry),三者的交互關係請看下面這張圖,我來簡單解釋一下。

  • RPC Server 提供服務,在啟動時,根據服務發佈文件 server.xml 中的配置的信息,向 Registry 註冊自身服務,並向 Registry 定期發送心跳彙報存活狀態。
  • RPC Client 調用服務,在啟動時,根據服務引用文件 client.xml 中配置的信息,向 Registry 訂閱服務,把 Registry 返回的服務節點列表緩存在本地內存中,並與 RPC Sever 建立連接。
  • 當 RPC Server 節點發生變更時,Registry 會同步變更,RPC Client 感知後會刷新本地內存中緩存的服務節點列表。
  • RPC Client 從本地緩存的服務節點列表中,基於負載均衡算法選擇一臺 RPC Sever 發起調用。
從0開始學微服務:05 如何註冊和發現服務?

註冊中心實現方式

註冊中心的實現主要涉及幾個問題:註冊中心需要提供哪些接口,該如何部署;如何存儲服務信息;如何監控服務提供者節點的存活;如果服務提供者節點有變化如何通知服務消費者,以及如何控制註冊中心的訪問權限。下面我來一一給你講解。

1. 註冊中心 API

根據註冊中心原理的描述,註冊中心必須提供以下最基本的 API,例如:

  • 服務註冊接口:服務提供者通過調用服務註冊接口來完成服務註冊。
  • 服務反註冊接口:服務提供者通過調用服務反註冊接口來完成服務註銷。
  • 心跳彙報接口:服務提供者通過調用心跳彙報接口完成節點存活狀態上報。
  • 服務訂閱接口:服務消費者通過調用服務訂閱接口完成服務訂閱,獲取可用的服務提供者節點列表。
  • 服務變更查詢接口:服務消費者通過調用服務變更查詢接口,獲取最新的可用服務節點列表。

除此之外,為了便於管理,註冊中心還必須提供一些後臺管理的 API,例如:

  • 服務查詢接口:查詢註冊中心當前註冊了哪些服務信息。
  • 服務修改接口:修改註冊中心中某一服務的信息。

2. 集群部署

註冊中心作為服務提供者和服務消費者之間溝通的橋樑,它的重要性不言而喻。所以註冊中心一般都是採用集群部署來保證高可用性,並通過分佈式一致性協議來確保集群中不同節點之間的數據保持一致。

以開源註冊中心 ZooKeeper 為例,ZooKeeper 集群中包含多個節點,服務提供者和服務消費者可以同任意一個節點通信,因為它們的數據一定是相同的,這是為什麼呢?這就要從 ZooKeeper 的工作原理說起:

  • 每個 Server 在內存中存儲了一份數據,Client 的讀請求可以請求任意一個 Server。
  • ZooKeeper 啟動時,將從實例中選舉一個 leader(Paxos 協議)。
  • Leader 負責處理數據更新等操作(ZAB 協議)。
  • 一個更新操作成功,當且僅當大多數 Server 在內存中成功修改 。

通過上面這種方式,ZooKeeper 保證了高可用性以及數據一致性。

從0開始學微服務:05 如何註冊和發現服務?

3. 目錄存儲

還是以 ZooKeeper 為例,註冊中心存儲服務信息一般採用層次化的目錄結構:

  • 每個目錄在 ZooKeeper 中叫作 znode,並且其有一個唯一的路徑標識。
  • znode 可以包含數據和子 znode。
  • znode 中的數據可以有多個版本,比如某一個 znode 下存有多個數據版本,那麼查詢這個路徑下的數據需帶上版本信息。
從0開始學微服務:05 如何註冊和發現服務?

4. 服務健康狀態檢測

註冊中心除了要支持最基本的服務註冊和服務訂閱功能以外,還必須具備對服務提供者節點的健康狀態檢測功能,這樣才能保證註冊中心裡保存的服務節點都是可用的。

還是以 ZooKeeper 為例,它是基於 ZooKeeper 客戶端和服務端的長連接和會話超時控制機制,來實現服務健康狀態檢測的。

在 ZooKeeper 中,客戶端和服務端建立連接後,會話也隨之建立,並生成一個全局唯一的 Session ID。服務端和客戶端維持的是一個長連接,在 SESSION_TIMEOUT 週期內,服務端會檢測與客戶端的鏈路是否正常,具體方式是通過客戶端定時向服務端發送心跳消息(ping 消息),服務器重置下次 SESSION_TIMEOUT 時間。如果超過 SESSION_TIMEOUT 後服務端都沒有收到客戶端的心跳消息,則服務端認為這個 Session 就已經結束了,ZooKeeper 就會認為這個服務節點已經不可用,將會從註冊中心中刪除其信息。

5. 服務狀態變更通知

一旦註冊中心探測到有服務提供者節點新加入或者被剔除,就必須立刻通知所有訂閱該服務的服務消費者,刷新本地緩存的服務節點信息,確保服務調用不會請求不可用的服務提供者節點。

繼續以 ZooKeeper 為例,基於 ZooKeeper 的 Watcher 機制,來實現服務狀態變更通知給服務消費者的。服務消費者在調用 ZooKeeper 的 getData 方法訂閱服務時,還可以通過監聽器 Watcher 的 process 方法獲取服務的變更,然後調用 getData 方法來獲取變更後的數據,刷新本地緩存的服務節點信息。

6. 白名單機制

在實際的微服務測試和部署時,通常包含多套環境,比如生產環境一套、測試環境一套。開發在進行業務自測、測試在進行迴歸測試時,一般都是用測試環境,部署的 RPC Server 節點註冊到測試的註冊中心集群。但經常會出現開發或者測試在部署時,錯誤的把測試環境下的服務節點註冊到了線上註冊中心集群,這樣的話線上流量就會調用到測試環境下的 RPC Server 節點,可能會造成意想不到的後果。

為了防止這種情況發生,註冊中心需要提供一個保護機制,你可以把註冊中心想象成一個帶有門禁的房間,只有擁有門禁卡的 RPC Server 才能進入。在實際應用中,註冊中心可以提供一個白名單機制,只有添加到註冊中心白名單內的 RPC Server,才能夠調用註冊中心的註冊接口,這樣的話可以避免測試環境中的節點意外跑到線上環境中去。

總結

註冊中心可以說是實現服務化的關鍵,因為服務化之後,服務提供者和服務消費者不在同一個進程中運行,實現瞭解耦,這就需要一個紐帶去連接服務提供者和服務消費者,而註冊中心就正好承擔了這一角色。此外,服務提供者可以任意伸縮即增加節點或者減少節點,通過服務健康狀態檢測,註冊中心可以保持最新的服務節點信息,並將變化通知給訂閱服務的服務消費者。

註冊中心一般採用分佈式集群部署,來保證高可用性,並且為了實現異地多活,有的註冊中心還採用多 IDC 部署,這就對數據一致性產生了很高的要求,這些都是註冊中心在實現時必須要解決的問題。

思考題

最後請你思考一下,你覺得采用註冊中心來實現服務發現與傳統的 DNS 實現服務發現有什麼不同嗎?

歡迎你在留言區寫下自己的思考,與我一起討論。


分享到:


相關文章: