摘要:本文主要介紹了服務註冊與發現的原理,以及常用的幾種服務註冊與發現元件介紹對比。
在單體應用向微服務架構演進的過程中,原本的巨石型應用會按照業務需求被拆分成多個微服務,每個服務提供特定的功能,並可能依賴於其他的微服務。每個微服務例項都可以動態部署,服務例項之間的呼叫通過輕量級的遠端呼叫方式(HTTP、訊息佇列等)實現,它們之間通過預先定義好的介面進行訪問。
由於服務例項是動態部署,每個服務例項的地址和服務資訊都可能動態變化,勢必需要一箇中心化的元件對各個服務例項的資訊進行管理,該元件管理了各個部署好的服務例項後設資料,包括不僅限於服務名、IP 地址、埠號、服務描述和服務狀態等。
什麼是服務註冊與發現?
服務註冊與發現主要包含兩部分:服務註冊與服務發現。服務註冊是指服務例項啟動時將自身資訊註冊到服務註冊與發現中心,並在執行時通過心跳等方式向服務註冊與發現中心彙報自身服務狀態;服務發現是指服務例項向服務註冊與發現中心獲取其他服務例項資訊,用於進行接下來的遠端呼叫。接下來讓我們介紹服務註冊與發現中心的職責和服務例項進行服務註冊的基本流程,以及分散式系統中資料同步的基本原理 CAP。
服務註冊與發現中心有什麼功能?
在傳統單體應用中,應用都是部署在固定的物理機器或者雲平臺上,他們之間的呼叫一般是通過固定在程式碼內部或者配置檔案的服務地址和埠直接發起。由於應用數量較少,系統結構複雜度不高,開發人員和運維人員可以較為輕鬆地進行管理和配置。
隨著應用架構向微服務架構遷移,服務數量的增加和動態部署動態擴充套件的特性,使得服務地址和埠在執行時是隨時可變的。對此,我們需要一個額外的中心化元件統一管理動態部署的微服務應用的服務例項後設資料,一般稱它為服務註冊與發現中心。服務註冊與發現中心主要有以下的職責:
- 管理當前註冊到服務註冊與發現中心的微服務例項後設資料資訊,包括服務例項的 服務名、IP 地址、埠號、服務描述和服務狀態等;
- 與註冊到服務發現與註冊中心的微服務例項維持心跳,定期檢查登錄檔中的服務例項是否線上,並剔除無效服務例項資訊;
- 提供服務發現能力,為服務呼叫方提供服務提供方的服務例項後設資料。
通過服務發現與註冊中心,可以很方便地管理系統中動態變化的服務例項資訊。與此同時,它也可能成為系統的瓶頸和故障點。因為服務之間的呼叫資訊來自於服務註冊與發現中心,當它不可用時,服務之間的呼叫可能無法正常進行。因此服務發現與註冊中心一般會叢集化部署,提供高可用性和高穩定性。
分散式中的 CAP 理論
在本質上來講,微服務應用屬於分散式系統的一種落地實踐,而分散式系統最大的難點是處理各個節點之間資料狀態的一致性。即使是倡導無狀態的 HTTP RESTful API 請求,在處理多服務例項情況下的修改資料狀態請求,也是需要通過資料庫或者分散式快取等外部系統維護資料的一致性。CAP 原理是描述分散式系統下節點資料同步的基本定理。
CAP 原理由加州大學的 Eric Brewer 教授提出,分別指 Consistency (一致性)、Availablity (可用性)、Partition tolerance (分割槽容忍性)。Eric Brewer 認為,以上三個指標最多同時滿足兩個。
- Consistency,指資料一致性,表示一個系統的資料資訊(包括備份資料)在同一時刻都是一致的。在分散式系統下,同一份資料可能存在於多個不同的例項中,在資料強一致性的要求下,對其中一份資料的修改必須同步到它的所有備份中。在資料同步的任何時候,都需要保證所有對該份資料的請求將返回同樣的狀態。
- Availablity,指服務可用性,要求服務在接受到客戶端請求後,都能夠給出響應。服務可用性考量的是系統的可用性,要求系統在高併發情況下和部分節點當機的情況下,系統整體依然能夠響應客戶端的請求。
- Partition tolerance,指分割槽容忍性。在分散式系統中,不同節點之間是通過網路進行通訊。基於網路的不可靠性,位於不同網路分割槽的服務節點可能會通訊失敗,如果系統能夠容忍這種情況,說明它是滿足分割槽容忍性的。如果系統不能夠滿足分割槽容忍性,那麼將會限制分散式系統的擴充套件性,即服務節點的部署數量和地區都會受限,違背了分散式系統設計的初衷,所以一般來講分散式系統都會滿足分割槽容忍性。
在滿足了分割槽容忍性的前提下,分散式系統並不能同時滿足資料一致性和服務可用性。假設服務A現在有兩個例項A1和A2,它們之間的網路通訊出現了異常,基於分割槽容忍性,這並不會影響A1和A2獨立的正常執行。假如此時客戶端請求A1,請求將資料B從B1狀態修改為B2,由於網路的不可用,資料B的修改並不能通知到例項A2。如果此時另一個客戶端向A2請求資料B,如果A2返回資料B1,將滿足服務可用性,但並不能滿足資料一致性;如果A2需要等待A1的通知之後才能夠返回資料B的正確狀態,雖然滿足了資料一致性,但並不能響應客戶端請求,違背了服務可用性的指標。
基於分散式系統的基本特質,P 是必須要滿足,接下來需要考慮滿足 C 還是 A。在類似銀行之類對金額資料要求強一致性的系統中,要優先考慮滿足資料一致性;而類似大眾網頁之類的系統,使用者對網頁版本的新舊不會有特別的要求,在這種場景下服務可用性高於資料一致性。
如何選擇服務註冊與發現框架?
隨著近幾年微服務框架高速發展,目前業界已經開源出了大量優秀的服務註冊與發現元件,包括不僅限於 Consul、Etcd、Zookeeper、Eureka。它們之間各有千秋,在元件選型時可以根據自身業務的需要進行選擇和改造,接下來我們主要對 Consul、Etcd、Zookeeper 作一些簡單的介紹和比較。
基於 Raft 演算法、開箱即用的服務發現系統 Consul
Consul 由 HashiCorp 開源,是支援多個平臺的分散式高可用系統。Consul 使用 Golang 語言實現,主要用於實現分散式系統的服務發現與配置,滿足 AP 特性。Consul 是分散式、高可用和可橫向擴充套件的,提供以下主要特性:
- 服務發現:可以使用 HTTP 或者 DNS 的方式將服務例項的後設資料註冊到 Consul,和通過 Consul 發現所依賴服務的後設資料列表。
- 檢查檢查:Consul 提供定時的健康檢查機制,定時請求註冊到 Consul 中的服務例項提供的健康檢查介面,將異常返回的服務例項標記為不健康。
- Key/Value:Consul 提供了 Key/Value 儲存功能,可以通過簡單的 HTTP 介面進行使用。
- 多資料中心:Consul 使用 Raft演算法來保證資料一致性,提供了開箱即用的多資料中心功能。
服務例項與 Consul 的互動如下圖所示:
Consul 與服務例項的互動過程
通過 Consul 實現服務註冊與發現中心的呼叫過程如下:
- Producer在啟動之初會通過 /register 介面將自己的服務例項後設資料註冊到 Consul 中;
- Consul 通過 Producer 提供的健康檢查介面 /health 定時檢查 Producer 的服務例項狀態;
- Consumer 請求 Consul 的介面獲取 Producer 服務的後設資料;
- Consumer 從 Consul 中返回的 Producer 服務例項後設資料列表中選擇合適的服務例項,使用其配置的 IP 和埠資訊發起服務呼叫,如圖 7-1 中 Consumer 呼叫 Producer 的 /service 介面。
Consul 是一個高可用的分散式系統,支援多資料中心部署。一個 Consul 叢集由多個部署和執行了 Consul Agent 的節點組成。Consul 叢集中存在兩種角色,Server 和 Client。每個 Consul Agent 負責對本地的服務進行監控檢查,並將查詢請求轉發到 Server 中進行處理。Consul 簡單的架構圖如下圖所示:
Consul 架構圖
從上圖可知,Consul 主要由 Consul Client 和 Consul Server 組成,且 Consul 使用 Gossip 協議來管理成員和廣播訊息到叢集。
Consul 作為一個開箱即用、高可用分散式服務發現和配置系統,可以很方便地為微服務的服務治理提供強有力的支援。在後面的課時中,我們將實現一個 Consul 的客戶端,將我們自身的 Web 服務註冊到 Consul 中,以供其他服務或者閘道器呼叫。
基於 HTTP 協議的分散式 key/Value 儲存系統 Etcd
Etcd 是由 CoreOS 開源,採用 Golang 語言編寫的分散式、高可用的 Key/Value 儲存系統,主要用於服務發現和配置共享。Ectd 的經典應用場景有:
- Key/Value 儲存:Etcd 支援 HTTP RESTful API,提供強一致性、高可用的資料儲存能力。
- 服務發現:通過在 Etcd 中註冊某個服務的目錄,服務例項連線 Etcd 並在目錄下發布對應 IP 和 Port 以供呼叫方使用,可以有效實現服務註冊與發現的功能;
- 訊息釋出與訂閱:通過 Etcd 的 Watcher 機制,可以使訂閱者訂閱他們關心的目錄。當訊息釋出者修改被監控的目錄內容時,可以將變化實時通知給訂閱者。
Etcd 的叢集的基本架構圖
相對於其他的元件來講,Etcd 更為輕量級,部署簡單,支援 HTTP 介面。它可以為服務發現提供一個穩定高可用的訊息註冊倉庫,為微服務協同工作提供了有力的支援。
重量級一致性服務系統 Zookeeper
Zookeeper 作為 Hadoop 和 Hbase 的重要元件,是一個開源的分散式應用協調服務,目前由 Apache 基金會維護,採用 Java 語言開發。Zookeeper 致力於為分散式應用提供一致性服務,它的設計目標是將分散式系統中那些複雜且容易出錯的服務封裝為簡單高效的介面以供開發人員使用。
Zookeeper 底層只提供了兩個功能,管理客戶端提交的資料和為客戶端程式提供資料節點的監聽服務。它是一個典型的分散式資料一致性解決方案,基於 ZooKeeper 可以實現服務發現與註冊、訊息釋出與訂閱、分散式協調與通知、分散式鎖、Master 選舉、叢集管理和分散式佇列等諸多功能。
Zookeeper 叢集中存在三種角色,分別為 Leader、Follower 和 Observer,架構圖如圖所示:
Zookeeper 架構圖
Zookeeper 通過 ZAB 協議來保證其資料一致性。ZAB 不是一種通用的分散式一致性演算法,它是在 Paxos 演算法的基礎上,為 Zookeeper 特別設計的崩潰可恢復的原子訊息廣播協議。ZAB 協議主要包含兩種基本模式,崩潰恢復和訊息廣播:
- 崩潰恢復模式:在服務啟動或者 Leader 伺服器崩潰時,ZAB協議就會進入崩潰恢復模式,在所有的 Follower 中選舉出 Leader。當選舉了新的 Leader 後,叢集中有半數與新的Leader 完成狀態同步後就會退出恢復模式,進入到訊息廣播模式。
- 訊息廣播模式:ZAB協議訊息廣播過程使用的是一個原子廣播協議,類似於一個二階段提交,但是又有所不同,並非所有 Follower 節點都返回 Ack 才進行一致性事務完成,而是隻需要半數以上即可提交完成一個事務廣播。
Zookeeper 為分散式系統提供協調服務,能夠有效地支援微服務架構的服務註冊和發現機制。同時 Zookeeper 中提供的其他資料一致性解決方案,能夠有力支撐微服務中分散式業務的開發。
服務註冊與發現元件的對比
以上介紹的三種服務註冊與發現元件在業界都已經有了廣泛的應用,在很多大公司的專案中都能看到它們的身影,比如 Zookeeper 在 Hadoop 體系中發揮了極其重要的分散式協調作用。下面將從特性方面比較他們的異同:
從軟體的生態出發,Consul 是以服務發現和配置作為主要功能目標,附帶提供了 Key/Value 儲存,相對於 Etcd 和 Zookeeper 來講業務範圍較小,更適合於服務註冊與發現。Etcd 和 Zookeeper 屬於通用的分散式一致性儲存系統,被應用於分散式系統的協調工作中,使用範圍抽象,具體的業務場景需要開發人員自主實現,如服務發現、分散式鎖等。Zookeeper 具備廣大的周邊生態,在分散式系統中得到了廣泛的使用;而 Etcd 以簡單易用的特性吸引了大量開發人員,在目前火熱的 Kubernetes 中也有應用。僅從服務註冊與發現元件的需求來看,選擇 Consul 作為服務註冊與發現中心能夠取得更好的效果;如果系統存在其他分散式一致性協作需求,選擇 Etcd 和 Zookeeper 反而能夠提供更多的服務支援。
小結
本文主要介紹了服務註冊與發現的原理,以及常用的幾種服務註冊與發現元件介紹對比。服務註冊與發現在微服務架構中是各個微服務之間的協調者,因此掌握服務註冊與發現的基本原理,正確使用服務註冊與發現元件是非常重要的一件事。在接下來的文章中,我們將基於 Consul 實現 Go 微服務的服務註冊與發現。
本文分享自華為雲社群《【華為雲專家原創】 服務註冊與發現如何滿足服務治理?》,原文作者:aoho 。