簡介

​ 服務註冊中心本質上是為了解耦服務提供者和服務消費者。對於任何一個微服務,原則上都應存在或者支援多個提供者,這是由微服務的分散式屬性決定的。更進一步,為了支援彈性擴縮容特性,一個微服務的提供者的數量和分佈往往是動態變化的,也是無法預先確定的。因此,原本在單體應用階段常用的靜態LB機制就不再適用了,需要引入額外的元件來管理微服務提供者的註冊與發現,而這個元件就是服務註冊中心;

CAP理論

CAP理論是分散式架構中重要理論

一致性(Consistency) (所有節點在同一時間具有相同的資料)

可用性(Availability) (保證每個請求不管成功或者失敗都有響應)

分隔容忍(Partition tolerance) (系統中任意資訊的丟失或失敗不會影響系統的繼續運作)

​ 關於P的理解,我覺得是在整個系統中某個部分,掛掉了,或者宕機了,並不影響整個系統的運作或者說使用,

​ 而可用性是,某個系統的某個節點掛了,但是並不影響系統的接受或者發出請求,CAP 不可能都取,只能取其中2個;

​ 原因是如果C是第一需求的話,那麼會影響A的效能,因為要資料同步,不然請求結果會有差異,但是資料同步會消耗時間,期間可用性就會降低。

​ 如果A是第一需求,那麼只要有一個服務在,就能正常接受請求,但是對與返回結果變不能保證,原因是,在分散式部署的時候,資料一致的過程不可能想切線路那麼快。

​ 再如果,同時滿足一致性和可用性,那麼分割槽容錯就很難保證了,也就是單點,也是分散式的基本核心,好了,明白這些理論,就可以在相應的場景選取服務註冊與發現了

服務註冊中心解決方案

​ 設計或者選型一個服務註冊中心,首先要考慮的就是服務註冊與發現機制。縱觀當下各種主流的服務註冊中心解決方案,大致可歸為三類:

​ 應用內:直接整合到應用中,依賴於應用自身完成服務的註冊與發現,最典型的是Netflix提供的Eureka

應用外:把應用當成黑盒,通過應用外的某種機制將服務註冊到註冊中心,最小化對應用的侵入性,比如Airbnb的SmartStack,HashiCorp的Consul

​ DNS:將服務註冊為DNS的SRV記錄,嚴格來說,是一種特殊的應用外註冊方式,SkyDNS是其中的代表;

​ 對於第一類註冊方式,除了Eureka這種一站式解決方案,還可以基於ZooKeeper或者Etcd自行實現一套服務註冊機制,這在大公司比較常見,但對於小公司而言顯然價效比太低。

​ 由於DNS固有的快取缺陷,本文不對第三類註冊方式作深入探討。

​ 除了基本的服務註冊與發現機制,從開發和運維角度,至少還要考慮如下五個方面:

​ 測活:服務註冊之後,如何對服務進行測活以保證服務的可用性?

​ 負載均衡:當存在多個服務提供者時,如何均衡各個提供者的負載?

​ 整合:在服務提供端或者呼叫端,如何整合註冊中心?

​ 執行時依賴:引入註冊中心之後,對應用的執行時環境有何影響?

​ 可用性:如何保證註冊中心本身的可用性,特別是消除單點故障?

主流注冊中心產品

Apache Zookeeper --> CP

與 Eureka 有所不同,Apache Zookeeper 在設計時就緊遵CP原則,即任何時候對 Zookeeper 的訪問請求能得到一致的資料結果,同時系統對網路分割具備容錯性,但是 Zookeeper 不能保證每次服務請求都是可達的。

從 Zookeeper 的實際應用情況來看,在使用 Zookeeper 獲取服務列表時,如果此時的 Zookeeper 叢集中的 Leader 宕機了,該叢集就要進行 Leader 的選舉,又或者 Zookeeper 叢集中半數以上伺服器節點不可用(例如有三個節點,如果節點一檢測到節點三掛了 ,節點二也檢測到節點三掛了,那這個節點才算是真的掛了),那麼將無法處理該請求。所以說,Zookeeper 不能保證服務可用性。

當然,在大多數分散式環境中,尤其是涉及到資料儲存的場景,資料一致性應該是首先被保證的,這也是 Zookeeper 設計緊遵CP原則的另一個原因。​

但是對於服務發現來說,情況就不太一樣了,針對同一個服務,即使註冊中心的不同節點儲存的服務提供者資訊不盡相同,也並不會造成災難性的後果。

因為對於服務消費者來說,能消費才是最重要的,消費者雖然拿到可能不正確的服務例項資訊後嘗試消費一下,也要勝過因為無法獲取例項資訊而不去消費,導致系統異常要好(淘寶的雙十一,京東的618就是緊遵AP的最好參照);

當master節點因為網路故障與其他節點失去聯絡時,剩餘節點會重新進行leader選舉。問題在於,選舉leader的時間太長,30~120s,而且選舉期間整個zk叢集都是不可用的,這就導致在選舉期間註冊服務癱瘓。

在雲部署環境下, 因為網路問題使得zk叢集失去master節點是大概率事件,雖然服務能最終恢復,但是漫長的選舉事件導致註冊長期不可用是不能容忍的。

Spring Cloud Eureka --> AP

Spring Cloud Netflix 在設計 Eureka 時就緊遵AP原則(儘管現在2.0釋出了,但是由於其閉源的原因 ,但是目前 Ereka 1.x 任然是比較活躍的)。

Eureka Server 也可以執行多個例項來構建叢集,解決單點問題,但不同於 ZooKeeper 的選舉 leader 的過程,Eureka Server 採用的是Peer to Peer 對等通訊。這是一種去中心化的架構,無 master/slave 之分,每一個 Peer 都是對等的。在這種架構風格中,節點通過彼此互相註冊來提高可用性,每個節點需要新增一個或多個有效的 serviceUrl 指向其他節點。每個節點都可被視為其他節點的副本。

在叢集環境中如果某臺 Eureka Server 宕機,Eureka Client 的請求會自動切換到新的 Eureka Server 節點上,當宕機的伺服器重新恢復後,Eureka 會再次將其納入到伺服器叢集管理之中。當節點開始接受客戶端請求時,所有的操作都會在節點間進行復制(replicate To Peer)操作,將請求複製到該 Eureka Server 當前所知的其它所有節點中。

當一個新的 Eureka Server 節點啟動後,會首先嚐試從鄰近節點獲取所有註冊列表資訊,並完成初始化。Eureka Server 通過 getEurekaServiceUrls() 方法獲取所有的節點,並且會通過心跳契約的方式定期更新。

預設情況下,如果 Eureka Server 在一定時間內沒有接收到某個服務例項的心跳(預設週期為30秒),Eureka Server 將會登出該例項(預設為90秒, eureka.instance.lease-expiration-duration-in-seconds 進行自定義配置)。

當 Eureka Server 節點在短時間內丟失過多的心跳時,那麼這個節點就會進入自我保護模式。

Eureka的叢集中,只要有一臺Eureka還在,就能保證註冊服務可用(保證可用性),只不過查到的資訊可能不是最新的(不保證強一致性)。除此之外,Eureka還有一種自我保護機制,如果在15分鐘內超過85%的節點都沒有正常的心跳,那麼Eureka就認為客戶端與註冊中心出現了網路故障,此時會出現以下幾種情況:

1 . Eureka不再從登錄檔中移除因為長時間沒有收到心跳而過期的服務;

2 . Eureka仍然能夠接受新服務註冊和查詢請求,但是不會被同步到其它節點上(即保證當前節點依然可用);

3 . 當網路穩定時,當前例項新註冊的資訊會被同步到其它節點中;

因此,Eureka可以很好的應對因網路故障導致部分節點失去聯絡的情況,而不會像zookeeper那樣使得整個註冊服務癱瘓。

Consul

Consul 是 HashiCorp 公司推出的開源工具,用於實現分散式系統的服務發現與配置。Consul 使用 Go 語言編寫,因此具有天然可移植性(支援Linux、windows和Mac OS X)。​

Consul 內建了服務註冊與發現框架、分佈一致性協議實現、健康檢查、Key/Value 儲存、多資料中心方案,不再需要依賴其他工具(比如 ZooKeeper 等),使用起來也較為簡單。

Consul 遵循CAP原理中的CP原則,保證了強一致性和分割槽容錯性,且使用的是Raft演算法,比zookeeper使用的Paxos演算法更加簡單。雖然保證了強一致性,但是可用性就相應下降了,例如服務註冊的時間會稍長一些,因為 Consul 的 raft 協議要求必須過半數的節點都寫入成功才認為註冊成功 ;在leader掛掉了之後,重新選舉出leader之前會導致Consul 服務不可用;

Consul本質上屬於應用外的註冊方式,但可以通過SDK簡化註冊流程。而服務發現恰好相反,預設依賴於SDK,但可以通過Consul Template(下文會提到)去除SDK依賴。

Consul Template

Consul,預設服務呼叫者需要依賴Consul SDK來發現服務,這就無法保證對應用的零侵入性。​

所幸通過Consul Template,可以定時從Consul叢集獲取最新的服務提供者列表並重新整理LB配置(比如nginx的upstream),這樣對於服務呼叫者而言,只需要配置一個統一的服務呼叫地址即可

Consul強一致性(C)帶來的是:

  1. 服務註冊相比Eureka會稍慢一些。因為Consul的raft協議要求必須過半數的節點都寫入成功才認為註冊成功
  2. Leader掛掉時,重新選舉期間整個consul不可用。保證了強一致性但犧牲了可用性。

Eureka保證高可用(A)和最終一致性:

1 . 服務註冊相對要快,因為不需要等註冊資訊replicate到其他節點,也不保證註冊資訊是否replicate成功

2 . 當資料出現不一致時,雖然A, B上的註冊資訊不完全相同,但每個Eureka節點依然能夠正常對外提供服務,這會出現查詢服務資訊時如果請求A查不到,但請求B就能查到。如此保證了可用性但犧牲了一致性。

其他方面,eureka就是個servlet程式,跑在servlet容器中; Consul則是go編寫而成。

Nacos

Nacos是阿里開源的,Nacos 支援基於 DNS 和基於 RPC 的服務發現。在Spring Cloud中使用Nacos,只需要先下載 Nacos 並啟動 Nacos server,Nacos只需要簡單的配置就可以完成服務的註冊發現。​

Nacos除了服務的註冊發現之外,還支援動態配置服務。動態配置服務可以讓您以中心化、外部化和動態化的方式管理所有環境的應用配置和服務配置。動態配置消除了配置變更時重新部署應用和服務的需要,讓配置管理變得更加高效和敏捷。配置中心化管理讓實現無狀態服務變得更簡單,讓服務按需彈性擴充套件變得更容易。

一句話概括就是Nacos = Spring Cloud註冊中心 + Spring Cloud配置中心。