註冊中心搞什麼?

實現一個註冊中心我們要怎麼搞?搞些什麼呢?

服務註冊

註冊的 IP 和端口怎麼確定 ?

  • IP 如何確定

主流的 IP 獲取有這幾種方法:

  • 最簡單粗暴的方式,手動配置需要註冊的IP。當然這種方式基本無法在生產環境使用,因爲微服務基本都是支持水平擴容多機部署的,在配置中寫死 IP 地址的方式無法支持一份代碼水平擴容,會給運維帶來極大的成本。

  • 通過遍歷網卡的方式去獲取,找到第一個不爲本地環回地址的 IP 地址。絕大多數情況下,這個方式比較好用,dubbo 等框架採用的就是這種方法。

  • 在一些網絡規劃比較好的標準化機房中,我們還可以通過手動指定網卡名,即 interfaceName 的方式來指定使用哪一塊網卡所對應的 IP 地址進行註冊。

當上述三種方式都不能有效解決問題的時候,有一個方法就是直接與服務註冊中心建立 socket 連接,然後通過socket.getLocalAddress() 這種方式來獲取本機的 IP。

端口如何確定

端口的獲取,沒有標準化的方案。

  • 如果是 RPC 應用,啓動的時候都有一個配置來指定服務監聽的端口, 註冊的時候直接使用配置項的端口值。

  • 傳統的 WEB 容器所提供的 HTTP 的應用,同樣也存在一個配置文件來配置容器的監聽端口,註冊時候直接使用配置項的端口值。

  • 特別的,在 Java 應用的 Spring Boot 框架中,可以通過 EmbeddedServletContainerInitializedEvent. getEmbeddedServletContainer().getPort()來獲取。(Spring Boot 版本爲 1.x)。

實現服務治理還需要註冊哪些信息 ?

簡單地將 IP 和 port 信息註冊上去,可以滿足基本的服務調用的需求,但是在業務發展到一定程度的時候,我們還會有這些需求:

  • 想知道某個 HTTP 服務是否開啓了 TLS。
  • 對相同服務下的不同節點設置不同的權重,進行流量調度。
  • 將服務分成預發環境和生產環境,方便進行AB Test功能。
  • 不同機房的服務註冊時加上機房的標籤,以實現同機房優先的路由規則。 這些高級功能的實現,本質上是依賴於客戶端調用時候的負載均衡策略和調用策略,但是如果服務元數據沒有註冊上來,也只能是巧婦難爲無米之炊。一個良好的服務註冊中心在設計最初就應該支持這些擴展字段。

如何進行優雅的服務註冊與服務下線 ?

  • 優雅發佈 雖然服務註冊一般發生在服務的啓動階段,但是細分的話,服務註冊應該在服務已經完全啓動成功,並準備對外提供服務之後才能進行註冊。
  • 有些 RPC 框架自身提供了方法來判斷服務是否已經啓動完成,如 Thrift ,我們可以通過 Server.isServing() 來判斷。
  • 有一些 RPC 框架本身沒有提供服務是否啓動完成的方式,這時我們可以通過檢測端口是否已經處於監聽狀態來判斷。
  • 而對於 HTTP 服務,服務是否啓動完畢也可以通過端口是否處於監聽狀態來判斷。
  • 特別的,在 Java 應用的 Spring Boot 框架中,可以通過事件通知的形式來通知容器已經啓動完畢, EmbeddedServletContainerInitializedEvent 事件來通知容器已經啓動完成 (Spring Boot 版本爲 1.x)。
  • 優雅下線 絕大多數的服務註冊中心都提供了健康檢查功能,在應用停止後會自動摘除服務所對應的節點。但是我們也不能完全依賴此功能,應用應該在停止時主動調用服務註冊中心的服務下線接口。
  • 在 Java 應用中,通用的服務下線接口調用一般使用 JVM Shutdown Hook 的方式來實現。
  • 特別的,在 Java 應用中的 Spring 框架中,可以通過 Spring Bean LifeCycle 來實現應用停止時主動調用服務下線接口。

當然上述兩種方式還不夠優雅,因爲不能確保不出現 kill -9 這種粗暴的停止方式,而且應用調用服務下線接口也是嘗試去調用,對於網絡不通等異常場景並沒有做異常處理。因此,調用客戶端仍應該做好負載均衡與 failover 的處理。 更優雅的方式,先將即將停止的應用所對應的權重調成 0,此時上游將不再調用此應用。這時候的停止應用的操作對服務訂閱者完全沒有影響,當然這種場景需要訂閱者實現按權重的負載均衡和運維部署工具深度結合。

服務的健康檢查是如何做的 ?

健康檢查分爲客戶端心跳和服務端主動探測兩種方式。

  • 客戶端心跳

客戶端每隔一定時間主動發送“心跳”的方式來向服務端表明自己的服務狀態正常,心跳可以是 TCP 的形式,也可以是 HTTP 的形式。 也可以通過維持客戶端和服務端的一個 socket 長連接自己實現一個客戶端心跳的方式。 ZooKeeper 並沒有主動的發送心跳,而是依賴了組件本身提供的臨時節點的特性,通過 ZooKeeper 連接的 session 來維持臨時節點。 但是客戶端心跳中,長連接的維持和客戶端的主動心跳都只是表明鏈路上的正常,不一定是服務狀態正常。 服務端主動調用服務進行健康檢查是一個較爲準確的方式,返回結果成功表明服務狀態確實正常。

  • 服務端主動探測 服務端調用服務發佈者某個 HTTP 接口來完成健康檢查。 對於沒有提供 HTTP 服務的 RPC 應用,服務端調用服務發佈者的接口來完成健康檢查。 可以通過執行某個腳本的形式來進行綜合檢查。 服務端主動探測也存在問題。服務註冊中心主動調用 RPC 服務的某個接口無法做到通用性;在很多場景下服務註冊中心到服務發佈者的網絡是不通的,服務端無法主動發起健康檢查。

所以如何取捨,還是需要根據實際情況來決定,根據不同的場景,選擇不同的策略。

服務發現

怎麼找到服務發現服務端的地址?

在應用的配置文件中指定服務註冊中心的地址,類似於 zookeeper 和 eureka。 指定一個地址服務器的地址,然後通過這個地址服務器來獲取服務註冊中心的地址,地址服務器返回的結果會隨着服務註冊中心的擴縮容及時更新。

當服務有節點退出或新的節點加入時,訂閱者如何及時收到通知 ?

很經典的 Push 和 Pull 問題。

Push 的經典實現有兩種,基於 socket 長連接的 notify,典型的實現如 zookeeper;另一種爲 HTTP 連接所使用 Long Polling。 但是基於 socket 長連接的 notify 和基於 HTTP 協議的 Long Polling 都會存在notify消息丟失的問題。

所以通過 Pull 的方式定時輪詢也必不可少,時間間隔的選擇也很關鍵,頻率越高服務註冊中心所承受的壓力也越大。需要結合服務端的性能和業務的規模進行權衡。

還有一種方式,真實的 Push,客戶端開啓一個 UDP server,服務註冊中心通過 UDP 的方式進行數據推送,當然這個也受限於網絡的連通性。

我能方便地查看我發佈和訂閱了哪些服務,訂閱的服務有哪些節點嗎 ?

一個好的產品,用戶使用體驗和運維體驗必須是優雅的,如果查看本機發布和訂閱的服務,只能通過查看日誌,甚至是 jmap 的方式來獲取,顯然體驗非常糟糕。 服務註冊中心應該提供了豐富的接口,支持根據應用名、IP、訂閱服務名、發佈服務名,來進行多層次的組合查詢。 同時,客戶端的內存裏,同樣也應該保留服務發佈與訂閱的各種信息,並提供方式供人方便地查詢。

比如在 Java 中的 Spring Boot 的應用,可以結合 actuator endpoint,通過 HTTP 的方式來提供本機服務查詢功能,查詢此應用發佈的服務,以及訂閱的服務及各服務的對應節點。

容災和高可用

性能如何

當服務節點數越來越多時,服務註冊中心的性能會成爲瓶頸,這時候就需要通過水平擴容來提升服務註冊中心集羣的性能。

對於那些採用了類 Paxos 協議的強一致性的組件,如ZooKeeper,由於每次寫操作需要過半的節點確認。水平擴容不能提升整個集羣的寫性能,只能提升整個集羣的讀性能。 而對於採用最終一致性的組件來說,水平擴容可以同時提升整個集羣的寫性能和讀性能。

客戶端容災策略

首先,本地內存緩存,當運行時與服務註冊中心的連接丟失或服務註冊中心完全宕機,仍能正常地調用服務。

然後,本地緩存文件,當應用與服務註冊中心發生網絡分區或服務註冊中心完全宕機後,應用進行了重啓操作,內存裏沒有數據,此時應用可以通過讀取本地緩存文件的數據來獲取到最後一次訂閱到的內容。

最後,本地容災文件夾。正常的情況下,容災文件夾內是沒有內容的。當服務端完全宕機且長時間不能恢復,同時服務提供者又發生了很大的變更時,可以通過在容災文件夾內添加文件的方式來開啓本地容災。此時客戶端會忽略原有的本地緩存文件,只從本地容災文件中讀取配置。

服務端容災與高可用

當有新節點加入集羣時,節點啓動後能自動添加到地址服務器中,並通過地址服務器找到其他節點,自動從其他節點同步數據,以達到數據的最終一致性。

當某個節點宕機時,此服務註冊中心節點的信息會自動地址服務器中摘除,客戶端能及時感知到此節點已下線。

服務端的無狀態性保證了服務的容災和高可用可以做的很薄。

服務端安全是如何做的 ?

鏈路安全,對於使用 HTTP 連接的服務註冊中心,保護鏈路安全的最好方式是使用 HTTPS。而使用 TCP 連接的服務註冊中心來說,由於應用層協議一般使用的是私有協議,不一定存在現成的 TLS 支持方案。

在業務安全方面,應該在每一次的發佈、訂閱、心跳,都帶上鑑權的信息就行驗籤和鑑權,確保業務信息的安全性。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章