為了支持彈性擴縮容特性,一個微服務的提供者的數量和分布往往是動態變化的,也是無法預先確定的。因此,原本在單體應用階段常用的靜態LB機制就不再適用了,需要引入額外的組件來管理微服務提供者的注冊與發現,而這個組件就是服務注冊中心。
CAP理論
CAP理論是分布式架構中重要理論
一致性(Consistency) (所有節點在同一時間具有相同的數據)
可用性(Availability) (保證每個請求不管成功或者失敗都有響應)
分隔容忍(Partition tolerance) (系統中任意信息的丟失或失敗不會影響系統的繼續運作)
關於
P的理解,我覺得是在整個系統中某個部分,掛掉了,或者宕機了,並不影響整個系統的運作或者說使用,
而可用性是,某個系統的某個節點掛了,但是並不影響系統的接受或者發出請求,CAP 不可能都取,只能取其中2個
原因是
如果C是第一需求的話,那么會影響A的性能,因為要數據同步,不然請求結果會有差異,但是數據同步會消耗時間,期間可用性就會降低。
如果A是第一需求,那么只要有一個服務在,就能正常接受請求,但是對與返回結果變不能保證,原因是,在分布式部署的時候,數據一致的過程不可能想切線路那么快。
再如果,同事滿足一致性和可用性,那么分區容錯就很難保證了,也就是單點,也是分布式的基本核心,好了,明白這些理論,就可以在相應的場景選取服務注冊與發現了
服務注冊中心解決方案
設計或者選型一個服務注冊中心,首先要考慮的就是服務注冊與發現機制。縱觀當下各種主流的服務注冊中心解決方案,大致可歸為三類:
應用內:直接集成到應用中,依賴於應用自身完成服務的注冊與發現,最典型的是Netflix提供的Eureka
應用外:把應用當成黑盒,通過應用外的某種機制將服務注冊到注冊中心,最小化對應用的侵入性,比如Airbnb的SmartStack,HashiCorp的Consul
DNS:將服務注冊為DNS的SRV記錄,嚴格來說,是一種特殊的應用外注冊方式,SkyDNS是其中的代表
注1:對於第一類注冊方式,除了Eureka這種一站式解決方案,還可以基於ZooKeeper或者Etcd自行實現一套服務注冊機制,這在大公司比較常見,但對於小公司而言顯然性價比太低。
注2:由於DNS固有的緩存缺陷,本文不對第三類注冊方式作深入探討。
除了基本的服務注冊與發現機制,從開發和運維角度,至少還要考慮如下五個方面:
測活:服務注冊之后,如何對服務進行測活以保證服務的可用性?
負載均衡:當存在多個服務提供者時,如何均衡各個提供者的負載?
集成:在服務提供端或者調用端,如何集成注冊中心?
運行時依賴:引入注冊中心之后,對應用的運行時環境有何影響?
可用性:如何保證注冊中心本身的可用性,特別是消除單點故障?
| Nacos | Eureka | Consul | CoreDNS | Zookeeper | |
|---|---|---|---|---|---|
| 一致性協議 | CP+AP | AP | CP | — | CP |
| 健康檢查 | TCP/HTTP/MYSQL/Client Beat | Client Beat | TCP/HTTP/gRPC/Cmd | — | Keep Alive |
| 負載均衡策略 | 權重/ metadata/Selector |
Ribbon | Fabio | RoundRobin | — |
| 雪崩保護 | 有 | 有 | 無 | 無 | 無 |
| 自動注銷實例 | 支持 | 支持 | 支持 | 不支持 | 支持 |
| 訪問協議 | HTTP/DNS | HTTP | HTTP/DNS | DNS | TCP |
| 監聽支持 | 支持 | 支持 | 支持 | 不支持 | 支持 |
| 多數據中心 | 支持 | 支持 | 支持 | 不支持 | 不支持 |
| 跨注冊中心同步 | 支持 | 不支持 | 支持 | 不支持 | 不支持 |
| SpringCloud集成 | 支持 | 支持 | 支持 | 不支持 | 支持 |
| Dubbo集成 | 支持 | 不支持 | 支持 | 不支持 | 支持 |
| K8S集成 | 支持 | 不支持 | 支持 | 支持 | 不支持 |
Consul是支持自動注銷服務實例, 請見文檔: https://www.consul.io/api-docs/agent/service,在check的 DeregisterCriticalServiceAfter 這個參數-- 感謝@超帥的菜鳥博主提供最新信息
新版本的Dubbo也擴展了對 Consul 的支持。 參考: https://github.com/apache/dubbo/tree/master/dubbo-registry
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節點是大概率事件,雖然服務能最終恢復,但是漫長的選舉事件導致注冊長期不可用是不能容忍的。
Eureka保證高可用(A)和最終一致性:
服務注冊相對要快,因為不需要等注冊信息replicate到其他節點,也不保證注冊信息是否replicate成功
當數據出現不一致時,雖然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配置中心。
