1、前言微服務(wù)的注冊中心目前主流的有以下五種:
Zookeeper Eureka Consul Nacos Kubernetes 那么實際開發(fā)中到底如何選擇呢?這是一個值得深入研究的事情,別著急,今天陳某就帶大家深入了解一下這五種注冊中心以及如何
選型 的問題。
2、為什么需要注冊中心?隨著單體應(yīng)用拆分,首當(dāng)面臨的第一份挑戰(zhàn)就是服務(wù)實例的數(shù)量較多,并且服務(wù)自身對外暴露的訪問地址也具有動態(tài)性??赡芤驗榉?wù)擴(kuò)容、服務(wù)的失敗和更新等因素,導(dǎo)致服務(wù)實例的運(yùn)行時狀態(tài)經(jīng)常變化,如下圖:
商品詳情需要調(diào)用
營銷 、
訂單 、
庫存 三個服務(wù),存在問題有:
營銷、訂單、庫存這三個服務(wù)的地址都可能動態(tài)的發(fā)生改變,單存只使用配置的形式需要頻繁的變更,如果是寫到配置文件里面還需要重啟系統(tǒng) ,這對生產(chǎn)來說太不友好了; 服務(wù)是集群部署的形式調(diào)用方負(fù)載均衡如何去實現(xiàn); 解決第一個問題辦法就是用我們用偉人說過一句話,
沒有什么是加一個中間層解決不了的 ,這個中間層就是我們的注冊中心。解決第二問題就是關(guān)于負(fù)載均衡的實現(xiàn),這個需要結(jié)合我們中間層老大哥來實現(xiàn)。
3、如何實現(xiàn)一個注冊中心?對于如何實現(xiàn)注冊中心這個問題,首先將服務(wù)之間是如何交互的模型抽象出來,我們結(jié)合實際的案例來說明這個問題,以商品服務(wù)為例:
當(dāng)我們搜索商品的時候商品服務(wù)就是提供者; 當(dāng)我們查詢商品詳情的時候即服務(wù)的提供者又是服務(wù)的消費(fèi)者,消費(fèi)是訂單、庫存等服務(wù);由此我們需要引入的三個角色就是:中間層(注冊中心)、生產(chǎn)者、消費(fèi)者,如下圖: 整體的執(zhí)行流程如下:
在服務(wù)啟動時,服務(wù)提供者通過內(nèi)部的注冊中心客戶端應(yīng)用自動將自身服務(wù)注冊到注冊中心,包含主機(jī)地址、服務(wù)名稱等等信息; 在服務(wù)啟動或者發(fā)生變更的時候,服務(wù)消費(fèi)者的注冊中心客戶端程序則可以從注冊中心中獲取那些已經(jīng)注冊的服務(wù)實例信息或者移除已下線的服務(wù); 上圖還多一個設(shè)計緩存本地路由,緩存本地路由是為了提高服務(wù)路由的
效率 和
容錯性 ,服務(wù)消費(fèi)者可以配備緩存機(jī)制以加速服務(wù)路由。更重要的是,當(dāng)服務(wù)注冊中心不可用時,服務(wù)消費(fèi)者可以利用本地緩存路由實現(xiàn)對現(xiàn)有服務(wù)的可靠調(diào)用。在整個執(zhí)行的過程中,其中有點(diǎn)有一點(diǎn)是比較難的,就是服務(wù)消費(fèi)者如何及時知道服務(wù)的生產(chǎn)者如何及時變更的,這個問題也是經(jīng)典的生產(chǎn)者消費(fèi)者的問題,解決的方式有兩種:
發(fā)布-訂閱模式 :服務(wù)消費(fèi)者能夠?qū)崟r監(jiān)控服務(wù)更新狀態(tài),通常采用監(jiān)聽器以及回調(diào)機(jī)制,經(jīng)典的案例就是Zookeeper ;主動拉取策略 :服務(wù)的消費(fèi)者定期調(diào)用注冊中心提供的服務(wù)獲取接口獲取最新的服務(wù)列表并更新本地緩存,經(jīng)典案例就是Eureka ;對于如何選擇這兩種方式,其實還有一個
數(shù)據(jù)一致性 問題可以聊聊,比如選擇定時器肯定就拋棄了一致性,最求的是最終一致,這里就不深入展開了,另外你可能還會說服務(wù)的移除等等這些功能都沒介紹,在我看來那只是一個附加功能,注冊中心重點(diǎn)還是在于服務(wù)注冊和發(fā)現(xiàn),其他都是錦上添花罷了。
4、如何解決負(fù)載均衡的問題?負(fù)載均衡的實現(xiàn)有兩種方式:
服務(wù)端的負(fù)載均衡; 客戶端的負(fù)載均衡; 對于實現(xiàn)的方案來說本質(zhì)上是差不多的,只是說承接的載體不一樣,一個是服務(wù)端,一個客戶端,如下圖: 服務(wù)端的負(fù)載均衡,給服務(wù)提供者更強(qiáng)的流量控制權(quán),但是無法滿足不同的消費(fèi)者希望使用不同負(fù)載均衡策略的需求。客戶端的負(fù)載均衡則提供了這種靈活性,并對用戶擴(kuò)展提供更加友好的支持。但是客戶端負(fù)載均衡策略如果配置不當(dāng),可能會導(dǎo)致服務(wù)提供者出現(xiàn)熱點(diǎn),或者壓根就拿不到任何服務(wù)提供者。服務(wù)端負(fù)載均衡典型的代表就是
Nginx ,客戶端負(fù)載均衡典型代表是
Ribbon ,每種方式都有經(jīng)典的代表,我們都是可以深入學(xué)習(xí)的。常見的負(fù)載均衡器的算法的實現(xiàn),常見的算法有以下
六種 :
1、輪詢法 將請求按順序輪流地分配到后端服務(wù)器上,它均衡地對待后端的每一臺服務(wù)器,而不關(guān)心服務(wù)器實際的連接數(shù)和當(dāng)前的系統(tǒng)負(fù)載。
2、隨機(jī)法 通過系統(tǒng)的隨機(jī)算法,根據(jù)后端服務(wù)器的列表大小值來隨機(jī)選取其中的一臺服務(wù)器進(jìn)行訪問。由概率統(tǒng)計理論可以得知,隨著客戶端調(diào)用服務(wù)端的次數(shù)增多;其實際效果越來越接近于平均分配調(diào)用量到后端的每一臺服務(wù)器,也就是輪詢的結(jié)果。
3、哈希算法 哈希的思想是根據(jù)獲取客戶端的IP地址,通過哈希函數(shù)計算得到的一個數(shù)值,用該數(shù)值對服務(wù)器列表的大小進(jìn)行取模運(yùn)算,得到的結(jié)果便是客服端要訪問服務(wù)器的序號。采用源地址哈希法進(jìn)行負(fù)載均衡,同一IP地址的客戶端,當(dāng)后端服務(wù)器列表不變時,它每次都會映射到同一臺后端服務(wù)器進(jìn)行訪問。
4、加權(quán)輪詢法 不同的后端服務(wù)器可能機(jī)器的配置和當(dāng)前系統(tǒng)的負(fù)載并不相同,因此它們的抗壓能力也不相同。給配置高、負(fù)載低的機(jī)器配置更高的權(quán)重,讓其處理更多的請;而配置低、負(fù)載高的機(jī)器,給其分配較低的權(quán)重,降低其系統(tǒng)負(fù)載,加權(quán)輪詢能很好地處理這一問題,并將請求順序且按照權(quán)重分配到后端。
5.加權(quán)隨機(jī)法 與加權(quán)輪詢法一樣,加權(quán)隨機(jī)法也根據(jù)后端機(jī)器的配置,系統(tǒng)的負(fù)載分配不同的權(quán)重。不同的是,它是按照權(quán)重隨機(jī)請求后端服務(wù)器,而非順序。
6.最小連接數(shù)法 最小連接數(shù)算法比較靈活和智能,由于后端服務(wù)器的配置不盡相同,對于請求的處理有快有慢,它是根據(jù)后端服務(wù)器當(dāng)前的連接情況,動態(tài)地選取其中當(dāng)前 積壓連接數(shù)最少的一臺服務(wù)器來處理當(dāng)前的請求,盡可能地提高后端服務(wù)的利用效率,將負(fù)責(zé)合理地分流到每一臺服務(wù)器。
5、注冊中心如何選型 ?現(xiàn)在注冊中心的選擇也是五花八門,現(xiàn)階段比較流行有以下幾種:
在介紹這個之前大家有些需要了解的知識有
CAP 、
Paxos 、Raft
算法 這里我就不進(jìn)行過多介紹了。開始介紹以上5種實現(xiàn)注冊中心的方式。
1、Zookeeper這個說起來有點(diǎn)意思的是官方并沒有說他是一個注冊中心,但是國內(nèi)Dubbo場景下很多都是使用Zookeeper來完成了注冊中心的功能。
當(dāng)然這有很多歷史原因,這里我們就不追溯了,我還是來聊聊作為注冊中心使用的情況下,Zookeeper有哪些表現(xiàn)吧。
Zookeeper基礎(chǔ)概念1、三種角色 Leader 角色 :一個Zookeeper集群同一時間只會有一個實際工作的Leader,它會發(fā)起并維護(hù)與各Follwer及Observer間的心跳。所有的寫操作必須要通過Leader完成再由Leader將寫操作廣播給其它服務(wù)器。
Follower角色 :一個Zookeeper集群可能同時存在多個Follower,它會響應(yīng)Leader的心跳。Follower可直接處理并返回客戶端的讀請求,同時會將寫請求轉(zhuǎn)發(fā)給Leader處理,并且負(fù)責(zé)在Leader處理寫請求時對請求進(jìn)行投票。
Observer角色 :與Follower類似,但是無投票權(quán)。
2、四種節(jié)點(diǎn) PERSISTENT-持久節(jié)點(diǎn) :除非手動刪除,否則節(jié)點(diǎn)一直存在于Zookeeper上
EPHEMERAL-臨時節(jié)點(diǎn) :臨時節(jié)點(diǎn)的生命周期與客戶端會話綁定,一旦客戶端會話失效,那么這個客戶端創(chuàng)建的所有臨時節(jié)點(diǎn)都會被移除。
PERSISTENT_SEQUENTIAL-持久順序節(jié)點(diǎn) :基本特性同持久節(jié)點(diǎn),只是增加了順序?qū)傩?,?jié)點(diǎn)名后邊會追加一個由父節(jié)點(diǎn)維護(hù)的自增整型數(shù)字。
EPHEMERAL_SEQUENTIAL-臨時順序節(jié)點(diǎn) :基本特性同臨時節(jié)點(diǎn),增加了順序?qū)傩裕?jié)點(diǎn)名后邊會追加一個由父節(jié)點(diǎn)維護(hù)的自增整型數(shù)字。
3、一種機(jī)制 Zookeeper的Watch機(jī)制 ,是一個輕量級的設(shè)計。因為它采用了一種推拉結(jié)合的模式。一旦服務(wù)端感知主題變了,那么只會發(fā)送一個事件類型和節(jié)點(diǎn)信息給關(guān)注的客戶端,而不會包括具體的變更內(nèi)容,所以事件本身是輕量級的,這就是推的部分。然后,收到變更通知的客戶端需要自己去拉變更的數(shù)據(jù),這就是拉的部分。
Zookeeper如何實現(xiàn)注冊中心? 簡單來講,Zookeeper可以充當(dāng)一個服務(wù)注冊表(Service Registry),讓多個服務(wù)提供者形成一個集群,讓服務(wù)消費(fèi)者通過服務(wù)注冊表獲取具體的服務(wù)訪問地址(ip 端口)去訪問具體的服務(wù)提供者。如下圖所示:
每當(dāng)一個服務(wù)提供者部署后都要將自己的服務(wù)注冊到zookeeper的某一路徑上:
/{service}/{version}/{ip:port} 。比如我們的
HelloWorldService 部署到兩臺機(jī)器,那么Zookeeper上就會創(chuàng)建兩條目錄:
/HelloWorldService/1.0.0/100.19.20.01:16888 HelloWorldService/1.0.0/100.19.20.02:16888。 這么描述有點(diǎn)不好理解,下圖更直觀,
在Zookeeper中,進(jìn)行服務(wù)注冊,實際上就是在Zookeeper中創(chuàng)建了一個Znode節(jié)點(diǎn),該節(jié)點(diǎn)存儲了該服務(wù)的IP、端口、調(diào)用方式(協(xié)議、序列化方式)等。該節(jié)點(diǎn)承擔(dān)著最重要的職責(zé),它由服務(wù)提供者(發(fā)布服務(wù)時)創(chuàng)建,以供服務(wù)消費(fèi)者獲取節(jié)點(diǎn)中的信息,從而定位到服務(wù)提供者真正IP,發(fā)起調(diào)用。通過IP設(shè)置為臨時節(jié)點(diǎn),那么該節(jié)點(diǎn)數(shù)據(jù)不會一直存儲在 ZooKeeper 服務(wù)器上。當(dāng)創(chuàng)建該臨時節(jié)點(diǎn)的客戶端會話因超時或發(fā)生異常而關(guān)閉時,該節(jié)點(diǎn)也相應(yīng)在 ZooKeeper 服務(wù)器上被刪除,剔除或者上線的時候會觸發(fā)Zookeeper的Watch機(jī)制,會發(fā)送消息給消費(fèi)者,因此就做到消費(fèi)者信息的及時更新。Zookeeper從設(shè)計上來說的話整體遵循的CP的原則,在任何時候?qū)?Zookeeper 的訪問請求能得到一致的數(shù)據(jù)結(jié)果,同時系統(tǒng)對網(wǎng)絡(luò)分區(qū)具備容錯性,在使用 Zookeeper 獲取服務(wù)列表時,如果此時的 Zookeeper 集群中的 Leader 宕機(jī)了,該集群就要進(jìn)行 Leader 的選舉,又或者 Zookeeper 集群中半數(shù)以上服務(wù)器節(jié)點(diǎn)不可用(例如有三個節(jié)點(diǎn),如果節(jié)點(diǎn)一檢測到節(jié)點(diǎn)三掛了 ,節(jié)點(diǎn)二也檢測到節(jié)點(diǎn)三掛了,那這個節(jié)點(diǎn)才算是真的掛了),那么將無法處理該請求。
所以說,Zookeeper 不能保證服務(wù)可用性。 2、EurekaNetflix我感覺應(yīng)該是在醞釀更好的東西的,下面我們重點(diǎn)還是來介紹Ereka 1.x相關(guān)的設(shè)計。
Eureka由兩個組件組成:
Eureka服務(wù)端 和
Eureka客戶端 。Eureka服務(wù)器用作服務(wù)注冊服務(wù)器。Eureka客戶端是一個java客戶端,用來簡化與服務(wù)器的交互、作為輪詢負(fù)載均衡器,并提供服務(wù)的故障切換支持。Eureka的基本架構(gòu),由3個角色組成:
1、Eureka Server: 提供服務(wù)注冊和發(fā)現(xiàn)功能; 2、Service Provider 服務(wù)提供方,將自身服務(wù)注冊到Eureka,從而使服務(wù)消費(fèi)方能夠找到;
3、Service Consumer 服務(wù)消費(fèi)方,從Eureka獲取注冊服務(wù)列表,從而能夠消費(fèi)服務(wù)
Eureka 在設(shè)計時就緊遵
AP 原則,Eureka Server 可以運(yùn)行多個實例來構(gòu)建集群,解決單點(diǎn)問題,實例之間通過彼此互相注冊來提高可用性,是一種去中心化的架構(gòu),無 master/slave 之分,每一個實例 都是對等的,每個節(jié)點(diǎn)都可被視為其他節(jié)點(diǎn)的副本。在集群環(huán)境中如果某臺 Eureka Server 宕機(jī),Eureka Client 的請求會自動切換到新的 Eureka Server 節(jié)點(diǎn)上,當(dāng)宕機(jī)的服務(wù)器重新恢復(fù)后,Eureka 會再次將其納入到服務(wù)器集群管理之中。當(dāng)節(jié)點(diǎn)開始接受客戶端請求時,所有的操作都會在節(jié)點(diǎn)間進(jìn)行復(fù)制操作,將請求復(fù)制到該 Eureka Server 當(dāng)前所知的其它所有節(jié)點(diǎn)中。當(dāng)一個新的 Eureka Server 節(jié)點(diǎn)啟動后,會首先嘗試從鄰近節(jié)點(diǎn)獲取所有注冊列表信息,并完成初始化。Eureka Server 通過 getEurekaServiceUrls() 方法獲取所有的節(jié)點(diǎn),并且會通過心跳契約的方式定期更新。默認(rèn)情況下,如果 Eureka Server 在一定時間內(nèi)沒有接收到某個服務(wù)實例的心跳(默認(rèn)周期為30秒),Eureka Server 將會注銷該實例(默認(rèn)為90秒, eureka.instance.lease-expiration-duration-in-seconds 進(jìn)行自定義配置)。當(dāng) Eureka Server 節(jié)點(diǎn)在短時間內(nèi)丟失過多的心跳時,那么這個節(jié)點(diǎn)就會進(jìn)入自我保護(hù)模式,這個測試環(huán)境的時候需要注意一下。Eureka的集群中,只要有一臺Eureka還在,就能保證注冊服務(wù)可用,只不過查到的信息可能不是最新的(不保證強(qiáng)一致性)。除此之外,Eureka還有一種自我保護(hù)機(jī)制,如果在
15分鐘 內(nèi)超過**85%**的節(jié)點(diǎn)都沒有正常的心跳,那么Eureka就認(rèn)為客戶端與注冊中心出現(xiàn)了網(wǎng)絡(luò)故障,此時會出現(xiàn)以下幾種情況:
Eureka不再從注冊表中移除因為長時間沒有收到心跳而過期的服務(wù); Eureka仍然能夠接受新服務(wù)注冊和查詢請求,但是不會被同步到其它節(jié)點(diǎn)上(即保證當(dāng)前節(jié)點(diǎn)依然可用) 當(dāng)網(wǎng)絡(luò)穩(wěn)定時,當(dāng)前實例新注冊的信息會被同步到其它節(jié)點(diǎn)中。 3、NacosNacos 無縫支持一些主流的開源生態(tài),如下圖:
Nacos 致力于幫助您發(fā)現(xiàn)、配置和管理微服務(wù)。Nacos 提供了一組簡單易用的特性集,幫助您快速實現(xiàn)動態(tài)服務(wù)發(fā)現(xiàn)、服務(wù)配置、服務(wù)元數(shù)據(jù)及流量管理。Nacos 幫助您更敏捷和容易地構(gòu)建、交付和管理微服務(wù)平臺。Nacos 是構(gòu)建以“服務(wù)”為中心的現(xiàn)代應(yīng)用架構(gòu) (例如微服務(wù)范式、云原生范式) 的服務(wù)基礎(chǔ)設(shè)施。Nacos除了服務(wù)的注冊發(fā)現(xiàn)之外,還支持
動態(tài)配置服務(wù) 。動態(tài)配置服務(wù)可以讓您以中心化、外部化和動態(tài)化的方式管理所有環(huán)境的應(yīng)用配置和服務(wù)配置。動態(tài)配置消除了配置變更時重新部署應(yīng)用和服務(wù)的需要,讓配置管理變得更加高效和敏捷。配置中心化管理讓實現(xiàn)無狀態(tài)服務(wù)變得更簡單,讓服務(wù)按需彈性擴(kuò)展變得更容易。
Nacos特點(diǎn)服務(wù)發(fā)現(xiàn)和服務(wù)健康監(jiān)測 Nacos 支持基于 DNS 和基于 RPC 的服務(wù)發(fā)現(xiàn)。服務(wù)提供者使用 原生SDK、OpenAPI、或一個獨(dú)立的Agent TODO注冊 Service 后,服務(wù)消費(fèi)者可以使用DNS TODO 或HTTP