來源:https://blog.csdn.net/fly910905/article/details/100023415
服務(wù)注冊中心本質(zhì)上是為了解耦服務(wù)提供者和服務(wù)消費(fèi)者。對于任何一個(gè)微服務(wù),原則上都應(yīng)存在或者支持多個(gè)提供者,這是由微服務(wù)的分布式屬性決定的。更進(jìn)一步,為了支持彈性擴(kuò)縮容特性,一個(gè)微服務(wù)的提供者的數(shù)量和分布往往是動(dòng)態(tài)變化的,也是無法預(yù)先確定的。因此,原本在單體應(yīng)用階段常用的靜態(tài)LB機(jī)制就不再適用了,需要引入額外的組件來管理微服務(wù)提供者的注冊與發(fā)現(xiàn),而這個(gè)組件就是服務(wù)注冊中心。
一致性(Consistency),所有節(jié)點(diǎn)在同一時(shí)間具有相同的數(shù)據(jù)
可用性(Availability),保證每個(gè)請求不管成功或者失敗都有響應(yīng)
分隔容忍(Partition tolerance),系統(tǒng)中任意信息的丟失或失敗不會(huì)影響系統(tǒng)的繼續(xù)運(yùn)作
關(guān)于P的理解,我覺得是在整個(gè)系統(tǒng)中某個(gè)部分,掛掉了,或者宕機(jī)了,并不影響整個(gè)系統(tǒng)的運(yùn)作或者說使用,而可用性是,某個(gè)系統(tǒng)的某個(gè)節(jié)點(diǎn)掛了,但是并不影響系統(tǒng)的接受或者發(fā)出請求,CAP不可能都取,只能取其中2個(gè)。原因是如果C是第一需求的話,那么會(huì)影響A的性能,因?yàn)橐獢?shù)據(jù)同步,不然請求結(jié)果會(huì)有差異,但是數(shù)據(jù)同步會(huì)消耗時(shí)間,期間可用性就會(huì)降低。如果A是第一需求,那么只要有一個(gè)服務(wù)在,就能正常接受請求,但是對與返回結(jié)果變不能保證,原因是,在分布式部署的時(shí)候,數(shù)據(jù)一致的過程不可能想切線路那么快。再如果,同時(shí)滿足一致性和可用性,那么分區(qū)容錯(cuò)就很難保證了,也就是單點(diǎn),也是分布式的基本核心,好了,明白這些理論,就可以在相應(yīng)的場景選取服務(wù)注冊與發(fā)現(xiàn)了。
設(shè)計(jì)或者選型一個(gè)服務(wù)注冊中心,首先要考慮的就是服務(wù)注冊與發(fā)現(xiàn)機(jī)制。縱觀當(dāng)下各種主流的服務(wù)注冊中心解決方案,大致可歸為三類:應(yīng)用內(nèi):直接集成到應(yīng)用中,依賴于應(yīng)用自身完成服務(wù)的注冊與發(fā)現(xiàn),最典型的是Netflix提供的Eureka
應(yīng)用外:把應(yīng)用當(dāng)成黑盒,通過應(yīng)用外的某種機(jī)制將服務(wù)注冊到注冊中心,最小化對應(yīng)用的侵入性,比如Airbnb的SmartStack,HashiCorp的Consul
DNS:將服務(wù)注冊為DNS的SRV記錄,嚴(yán)格來說,是一種特殊的應(yīng)用外注冊方式,SkyDNS是其中的代表
注1:對于第一類注冊方式,除了Eureka這種一站式解決方案,還可以基于ZooKeeper或者etcd自行實(shí)現(xiàn)一套服務(wù)注冊機(jī)制,這在大公司比較常見,但對于小公司而言顯然性價(jià)比太低。注2:由于DNS固有的緩存缺陷,本文不對第三類注冊方式作深入探討。除了基本的服務(wù)注冊與發(fā)現(xiàn)機(jī)制,從開發(fā)和運(yùn)維角度,至少還要考慮如下五個(gè)方面:測活:服務(wù)注冊之后,如何對服務(wù)進(jìn)行測活以保證服務(wù)的可用性?
負(fù)載均衡:當(dāng)存在多個(gè)服務(wù)提供者時(shí),如何均衡各個(gè)提供者的負(fù)載?
集成:在服務(wù)提供端或者調(diào)用端,如何集成注冊中心?
運(yùn)行時(shí)依賴:引入注冊中心之后,對應(yīng)用的運(yùn)行時(shí)環(huán)境有何影響?
可用性:如何保證注冊中心本身的可用性,特別是消除單點(diǎn)故障?
軟件產(chǎn)品特性并非一成不變,如果發(fā)現(xiàn)功能特性有變更,歡迎評論指正。
| Nacos | Eureka | Consul
| CoreDNS | ZooKeeper
|
一致性協(xié)議
| CP+AP
| AP
| CP
| -
| CP
|
健康檢查
| TCP/HTTP/MYSQL/Client Beat
| Client Beat
| TCP/HTTP/gRPC/Cmd
| -
| Keep Alive
|
負(fù)載均衡策略
| 權(quán)重/metadata/Selector
| Ribbon
| Fabio
| RoundRobin
| -
|
雪崩保護(hù)
| 有
| 有
| 無 | 無
| 無
|
自動(dòng)注銷實(shí)例
| 支持
| 支持
| 支持
| 不支持
| 支持
|
訪問協(xié)議
| HTTP/DNS
| HTTP
| HTTP/DNS
| DNS
| TCP
|
監(jiān)聽支持
| 支持
| 支持
| 支持
| 不支持
| 支持
|
多數(shù)據(jù)中心
| 支持
| 支持
| 支持
| 不支持
| 不支持
|
跨注冊中心同步
| 支持
| 不支持
| 支持
| 不支持
| 不支持
|
Spring Cloud集成
| 支持
| 支持
| 支持
| 不支持
| 支持
|
Dubbo集成
| 支持
| 不支持
| 支持
| 不支持
| 支持
|
Kubernetes集成
| 支持
| 不支持
| 支持
| 支持
| 不支持 |
Consul是支持自動(dòng)注銷服務(wù)實(shí)例,請見文檔:https://www.consul.io/api-docs/agent/service,在check的 DeregisterCriticalServiceAfter 這個(gè)參數(shù)-- 感謝@超帥的菜鳥博主提供最新信息
新版本的Dubbo也擴(kuò)展了對 Consul 的支持。參考:https://github.com/apache/dubbo/tree/master/dubbo-registry
與Eureka有所不同,Apache ZooKeeper在設(shè)計(jì)時(shí)就緊遵CP原則,即任何時(shí)候?qū)ooKeeper的訪問請求能得到一致的數(shù)據(jù)結(jié)果,同時(shí)系統(tǒng)對網(wǎng)絡(luò)分割具備容錯(cuò)性,但是ZooKeeper不能保證每次服務(wù)請求都是可達(dá)的。從ZooKeeper的實(shí)際應(yīng)用情況來看,在使用ZooKeeper獲取服務(wù)列表時(shí),如果此時(shí)的ZooKeeper集群中的Leader宕機(jī)了,該集群就要進(jìn)行Leader的選舉,又或者ZooKeeper集群中半數(shù)以上服務(wù)器節(jié)點(diǎn)不可用(例如有三個(gè)節(jié)點(diǎn),如果節(jié)點(diǎn)一檢測到節(jié)點(diǎn)三掛了 ,節(jié)點(diǎn)二也檢測到節(jié)點(diǎn)三掛了,那這個(gè)節(jié)點(diǎn)才算是真的掛了),那么將無法處理該請求。所以說,ZooKeeper不能保證服務(wù)可用性。當(dāng)然,在大多數(shù)分布式環(huán)境中,尤其是涉及到數(shù)據(jù)存儲的場景,數(shù)據(jù)一致性應(yīng)該是首先被保證的,這也是ZooKeeper設(shè)計(jì)緊遵CP原則的另一個(gè)原因。但是對于服務(wù)發(fā)現(xiàn)來說,情況就不太一樣了,針對同一個(gè)服務(wù),即使注冊中心的不同節(jié)點(diǎn)保存的服務(wù)提供者信息不盡相同,也并不會(huì)造成災(zāi)難性的后果。因?yàn)閷τ诜?wù)消費(fèi)者來說,能消費(fèi)才是最重要的,消費(fèi)者雖然拿到可能不正確的服務(wù)實(shí)例信息后嘗試消費(fèi)一下,也要?jiǎng)龠^因?yàn)闊o法獲取實(shí)例信息而不去消費(fèi),導(dǎo)致系統(tǒng)異常要好(淘寶的雙十一,京東的618就是緊遵AP的最好參照)。當(dāng)Master節(jié)點(diǎn)因?yàn)榫W(wǎng)絡(luò)故障與其他節(jié)點(diǎn)失去聯(lián)系時(shí),剩余節(jié)點(diǎn)會(huì)重新進(jìn)行Leader選舉。問題在于,選舉Leader的時(shí)間太長,30~120s,而且選舉期間整個(gè)ZooKeeper集群都是不可用的,這就導(dǎo)致在選舉期間注冊服務(wù)癱瘓。在云部署環(huán)境下, 因?yàn)榫W(wǎng)絡(luò)問題使得ZooKeeper集群失去Master節(jié)點(diǎn)是大概率事件,雖然服務(wù)能最終恢復(fù),但是漫長的選舉事件導(dǎo)致注冊長期不可用是不能容忍的。Spring Cloud Eureka -> APSpring Cloud Netflix在設(shè)計(jì)Eureka時(shí)就緊遵AP原則(盡管現(xiàn)在2.0發(fā)布了,但是由于其閉源的原因 ,但是目前Ereka 1.x任然是比較活躍的)。Eureka Server也可以運(yùn)行多個(gè)實(shí)例來構(gòu)建集群,解決單點(diǎn)問題,但不同于ZooKeeper的選舉Leader的過程,Eureka Server采用的是Peer to Peer對等通信。這是一種去中心化的架構(gòu),無Master/Slave之分,每一個(gè)Peer都是對等的。在這種架構(gòu)風(fēng)格中,節(jié)點(diǎn)通過彼此互相注冊來提高可用性,每個(gè)節(jié)點(diǎn)需要添加一個(gè)或多個(gè)有效的serviceUrl指向其他節(jié)點(diǎn)。每個(gè)節(jié)點(diǎn)都可被視為其他節(jié)點(diǎn)的副本。在集群環(huán)境中如果某臺Eureka Server宕機(jī),Eureka Client的請求會(huì)自動(dòng)切換到新的Eureka Server節(jié)點(diǎn)上,當(dāng)宕機(jī)的服務(wù)器重新恢復(fù)后,Eureka會(huì)再次將其納入到服務(wù)器集群管理之中。當(dāng)節(jié)點(diǎn)開始接受客戶端請求時(shí),所有的操作都會(huì)在節(jié)點(diǎn)間進(jìn)行復(fù)制(replicate To Peer)操作,將請求復(fù)制到該Eureka Server當(dāng)前所知的其它所有節(jié)點(diǎn)中。當(dāng)一個(gè)新的Eureka Server節(jié)點(diǎn)啟動(dòng)后,會(huì)首先嘗試從鄰近節(jié)點(diǎn)獲取所有注冊列表信息,并完成初始化。Eureka Server通過getEurekaServiceUrls()方法獲取所有的節(jié)點(diǎn),并且會(huì)通過心跳契約的方式定期更新。默認(rèn)情況下,如果Eureka Server在一定時(shí)間內(nèi)沒有接收到某個(gè)服務(wù)實(shí)例的心跳(默認(rèn)周期為30秒),Eureka Server將會(huì)注銷該實(shí)例(默認(rèn)為90秒, eureka.instance.lease-expiration-duration-in-seconds進(jìn)行自定義配置)。當(dāng)Eureka Server節(jié)點(diǎn)在短時(shí)間內(nèi)丟失過多的心跳時(shí),那么這個(gè)節(jié)點(diǎn)就會(huì)進(jìn)入自我保護(hù)模式。Eureka的集群中,只要有一臺Eureka還在,就能保證注冊服務(wù)可用(保證可用性),只不過查到的信息可能不是最新的(不保證強(qiáng)一致性)。除此之外,Eureka還有一種自我保護(hù)機(jī)制,如果在15分鐘內(nèi)超過85%的節(jié)點(diǎn)都沒有正常的心跳,那么Eureka就認(rèn)為客戶端與注冊中心出現(xiàn)了網(wǎng)絡(luò)故障,此時(shí)會(huì)出現(xiàn)以下幾種情況:Eureka不再從注冊表中移除因?yàn)殚L時(shí)間沒有收到心跳而過期的服務(wù);
Eureka仍然能夠接受新服務(wù)注冊和查詢請求,但是不會(huì)被同步到其它節(jié)點(diǎn)上(即保證當(dāng)前節(jié)點(diǎn)依然可用);
當(dāng)網(wǎng)絡(luò)穩(wěn)定時(shí),當(dāng)前實(shí)例新注冊的信息會(huì)被同步到其它節(jié)點(diǎn)中。
因此,Eureka可以很好的應(yīng)對因網(wǎng)絡(luò)故障導(dǎo)致部分節(jié)點(diǎn)失去聯(lián)系的情況,而不會(huì)像ZooKeeper那樣使得整個(gè)注冊服務(wù)癱瘓。Consul是HashiCorp公司推出的開源工具,用于實(shí)現(xiàn)分布式系統(tǒng)的服務(wù)發(fā)現(xiàn)與配置。Consul使用Go語言編寫,因此具有天然可移植性(支持Linux、Windows和Mac OS X)。Consul內(nèi)置了服務(wù)注冊與發(fā)現(xiàn)框架、分布一致性協(xié)議實(shí)現(xiàn)、健康檢查、Key/Value存儲、多數(shù)據(jù)中心方案,不再需要依賴其他工具(比如ZooKeeper等),使用起來也較為簡單。Consul遵循CAP原理中的CP原則,保證了強(qiáng)一致性和分區(qū)容錯(cuò)性,且使用的是Raft算法,比ZooKeeper使用的Paxos算法更加簡單。雖然保證了強(qiáng)一致性,但是可用性就相應(yīng)下降了,例如服務(wù)注冊的時(shí)間會(huì)稍長一些,因?yàn)?Consul 的 raft 協(xié)議要求必須過半數(shù)的節(jié)點(diǎn)都寫入成功才認(rèn)為注冊成功;在Leader掛掉了之后,重新選舉出Leader之前會(huì)導(dǎo)致Consul服務(wù)不可用。Consul本質(zhì)上屬于應(yīng)用外的注冊方式,但可以通過SDK簡化注冊流程。而服務(wù)發(fā)現(xiàn)恰好相反,默認(rèn)依賴于SDK,但可以通過Consul Template(下文會(huì)提到)去除SDK依賴。Consul默認(rèn)服務(wù)調(diào)用者需要依賴Consul SDK來發(fā)現(xiàn)服務(wù),這就無法保證對應(yīng)用的零侵入性。所幸通過Consul Template,可以定時(shí)從Consul集群獲取最新的服務(wù)提供者列表并刷新LB配置(比如Nginx的Upstream),這樣對于服務(wù)調(diào)用者而言,只需要配置一個(gè)統(tǒng)一的服務(wù)調(diào)用地址即可。Consul強(qiáng)一致性(C)帶來的是:服務(wù)注冊相對要快,因?yàn)椴恍枰茸孕畔eplicate到其他節(jié)點(diǎn),也不保證注冊信息是否Replicate成功
當(dāng)數(shù)據(jù)出現(xiàn)不一致時(shí),雖然A,B上的注冊信息不完全相同,但每個(gè)Eureka節(jié)點(diǎn)依然能夠正常對外提供服務(wù),這會(huì)出現(xiàn)查詢服務(wù)信息時(shí)如果請求A查不到,但請求B就能查到。如此保證了可用性但犧牲了一致性。
其他方面,Eureka就是個(gè)servlet程序,跑在servlet容器中;Consul則是Go編寫而成。Nacos是阿里開源的,Nacos支持基于DNS和基于RPC的服務(wù)發(fā)現(xiàn)。在Spring Cloud中使用Nacos,只需要先下載Nacos并啟動(dòng)Nacos server,Nacos只需要簡單的配置就可以完成服務(wù)的注冊發(fā)現(xiàn)。Nacos除了服務(wù)的注冊發(fā)現(xiàn)之外,還支持動(dòng)態(tài)配置服務(wù)。動(dòng)態(tài)配置服務(wù)可以讓您以中心化、外部化和動(dòng)態(tài)化的方式管理所有環(huán)境的應(yīng)用配置和服務(wù)配置。動(dòng)態(tài)配置消除了配置變更時(shí)重新部署應(yīng)用和服務(wù)的需要,讓配置管理變得更加高效和敏捷。配置中心化管理讓實(shí)現(xiàn)無狀態(tài)服務(wù)變得更簡單,讓服務(wù)按需彈性擴(kuò)展變得更容易。一句話概括就是Nacos = Spring Cloud注冊中心 + Spring Cloud配置中心。- END -
點(diǎn)亮,服務(wù)器三年不宕機(jī)