對(duì)于微服務(wù)的治理而言,,核心就是服務(wù)的注冊(cè)和發(fā)現(xiàn)。所以選擇哪個(gè)組件,,很大程度上要看它對(duì)于服務(wù)注冊(cè)與發(fā)現(xiàn)的解決方案,。在這個(gè)領(lǐng)域,開(kāi)源架構(gòu)很多,,最常見(jiàn)的是Zookeeper,,但這并不是一個(gè)最佳選擇。 在分布式系統(tǒng)領(lǐng)域有個(gè)著名的CAP定理:C——數(shù)據(jù)一致性,,A——服務(wù)可用性,,P——服務(wù)對(duì)網(wǎng)絡(luò)分區(qū)故障的容錯(cuò)性。這三個(gè)特性在任何分布式系統(tǒng)中不能同時(shí)滿(mǎn)足,,最多同時(shí)滿(mǎn)足兩個(gè),。 Zookeeper是著名Hadoop的一個(gè)子項(xiàng)目,很多場(chǎng)景下Zookeeper也作為Service發(fā)現(xiàn)服務(wù)解決方案,。Zookeeper保證的是CP,,即任何時(shí)刻對(duì)Zookeeper的訪(fǎng)問(wèn)請(qǐng)求能得到一致的數(shù)據(jù)結(jié)果,同時(shí)系統(tǒng)對(duì)網(wǎng)絡(luò)分割具備容錯(cuò)性,,但是它不能保證每次服務(wù)請(qǐng)求的可用性,。從實(shí)際情況來(lái)分析,在使用Zookeeper獲取服務(wù)列表時(shí),,如果zookeeper正在選主,,或者Zookeeper集群中半數(shù)以上機(jī)器不可用,那么將就無(wú)法獲得數(shù)據(jù)了,。所以說(shuō),,Zookeeper不能保證服務(wù)可用性。 誠(chéng)然,,對(duì)于大多數(shù)分布式環(huán)境,,尤其是涉及到數(shù)據(jù)存儲(chǔ)的場(chǎng)景,數(shù)據(jù)一致性應(yīng)該是首先被保證的,,這也是zookeeper設(shè)計(jì)成CP的原因,。但是對(duì)于服務(wù)發(fā)現(xiàn)場(chǎng)景來(lái)說(shuō),情況就不太一樣了:針對(duì)同一個(gè)服務(wù),,即使注冊(cè)中心的不同節(jié)點(diǎn)保存的服務(wù)提供者信息不盡相同,,也并不會(huì)造成災(zāi)難性的后果。因?yàn)閷?duì)于服務(wù)消費(fèi)者來(lái)說(shuō),,能消費(fèi)才是最重要的——拿到可能不正確的服務(wù)實(shí)例信息后嘗試消費(fèi)一下,,也好過(guò)因?yàn)闊o(wú)法獲取實(shí)例信息而不去消費(fèi)。所以,,對(duì)于服務(wù)發(fā)現(xiàn)而言,,可用性比數(shù)據(jù)一致性更加重要——AP勝過(guò)CP,。而Spring Cloud Netflix在設(shè)計(jì)Eureka時(shí)遵守的就是AP原則。 Eureka本身是Netflix開(kāi)源的一款提供服務(wù)注冊(cè)和發(fā)現(xiàn)的產(chǎn)品,,并且提供了相應(yīng)的Java封裝,。在它的實(shí)現(xiàn)中,節(jié)點(diǎn)之間是相互平等的,,部分注冊(cè)中心的節(jié)點(diǎn)掛掉也不會(huì)對(duì)集群造成影響,,即使集群只剩一個(gè)節(jié)點(diǎn)存活,,也可以正常提供發(fā)現(xiàn)服務(wù),。哪怕是所有的服務(wù)注冊(cè)節(jié)點(diǎn)都掛了,Eureka Clients上也會(huì)緩存服務(wù)調(diào)用的信息,。這就保證了我們微服務(wù)之間的互相調(diào)用是足夠健壯的,。 除此之外,Spring Cloud Netflix背后強(qiáng)大的開(kāi)源力量,,也促使我們選擇了Spring Cloud Netflix: 前文提到過(guò),,Spring Cloud的社區(qū)十分活躍,其在業(yè)界的應(yīng)用也十分廣泛(尤其是國(guó)外),,而且整個(gè)框架也經(jīng)受住了Netflix嚴(yán)酷生產(chǎn)環(huán)境的考驗(yàn),。 除了服務(wù)注冊(cè)和發(fā)現(xiàn),Spring Cloud Netflix的其他功能也十分強(qiáng)大,,包括Ribbon,,hystrix,F(xiàn)eign,,Zuul等組件,,結(jié)合到一起,讓服務(wù)的調(diào)用,、路由也變得異常容易,。 Spring Cloud Netflix作為Spring的重量級(jí)整合框架,使用它也意味著我們能從Spring獲取到巨大的便利,。Spring Cloud的其他子項(xiàng)目,,比如Spring Cloud Stream、Spring Cloud Config等等,,都為微服務(wù)的各種需求提供了一站式的解決方案,。
Spring Cloud Netflix的核心是用于服務(wù)注冊(cè)與發(fā)現(xiàn)的Eureka,接下來(lái)我們將以Eureka為線(xiàn)索,,介紹Eureka,、Ribbon、Hystrix,、Feign這些Spring Cloud Netflix主要組件,。
Eureka由多個(gè)instance(服務(wù)實(shí)例)組成,這些服務(wù)實(shí)例可以分為兩種:Eureka Server和Eureka Client,。為了便于理解,,我們將Eureka client再分為Service Provider和Service Consumer。如下圖所示: Eureka Server:服務(wù)的注冊(cè)中心,,負(fù)責(zé)維護(hù)注冊(cè)的服務(wù)列表,。 Service Provider:服務(wù)提供方,作為一個(gè)Eureka Client,,向Eureka Server做服務(wù)注冊(cè),、續(xù)約和下線(xiàn)等操作,注冊(cè)的主要數(shù)據(jù)包括服務(wù)名,、機(jī)器ip,、端口號(hào)、域名等等,。 Service Consumer:服務(wù)消費(fèi)方,,作為一個(gè)Eureka Client,向Eureka Server獲取Service Provider的注冊(cè)信息,,并通過(guò)遠(yuǎn)程調(diào)用與Service Provider進(jìn)行通信,。
2.1.1 Eureka ServerEureka Server作為一個(gè)獨(dú)立的部署單元,,以REST API的形式為服務(wù)實(shí)例提供了注冊(cè),、管理和查詢(xún)等操作。同時(shí),,Eureka Server也為我們提供了可視化的監(jiān)控頁(yè)面,,可以直觀地看到各個(gè)Eureka Server當(dāng)前的運(yùn)行狀態(tài)和所有已注冊(cè)服務(wù)的情況。 2.1.1.1 Eureka Server的高可用集群Eureka Server可以運(yùn)行多個(gè)實(shí)例來(lái)構(gòu)建集群,,解決單點(diǎn)問(wèn)題,,但不同于ZooKeeper的選舉leader的過(guò)程,Eureka Server采用的是Peer to Peer對(duì)等通信,。這是一種去中心化的架構(gòu),無(wú)master/slave區(qū)分,,每一個(gè)Peer都是對(duì)等的,。在這種架構(gòu)中,節(jié)點(diǎn)通過(guò)彼此互相注冊(cè)來(lái)提高可用性,,每個(gè)節(jié)點(diǎn)需要添加一個(gè)或多個(gè)有效的serviceUrl指向其他節(jié)點(diǎn),。每個(gè)節(jié)點(diǎn)都可被視為其他節(jié)點(diǎn)的副本。 如果某臺(tái)Eureka Server宕機(jī),,Eureka Client的請(qǐng)求會(huì)自動(dòng)切換到新的Eureka Server節(jié)點(diǎn),,當(dāng)宕機(jī)的服務(wù)器重新恢復(fù)后,Eureka會(huì)再次將其納入到服務(wù)器集群管理之中,。當(dāng)節(jié)點(diǎn)開(kāi)始接受客戶(hù)端請(qǐng)求時(shí),,所有的操作都會(huì)進(jìn)行replicateToPeer(節(jié)點(diǎn)間復(fù)制)操作,將請(qǐng)求復(fù)制到其他Eureka Server當(dāng)前所知的所有節(jié)點(diǎn)中,。 一個(gè)新的Eureka Server節(jié)點(diǎn)啟動(dòng)后,,會(huì)首先嘗試從鄰近節(jié)點(diǎn)獲取所有實(shí)例注冊(cè)表信息,完成初始化,。Eureka Server通過(guò)getEurekaServiceUrls()方法獲取所有的節(jié)點(diǎn),,并且會(huì)通過(guò)心跳續(xù)約的方式定期更新。默認(rèn)配置下,,如果Eureka Server在一定時(shí)間內(nèi)沒(méi)有接收到某個(gè)服務(wù)實(shí)例的心跳,,Eureka Server將會(huì)注銷(xiāo)該實(shí)例(默認(rèn)為90秒,通過(guò)eureka.instance.lease-expiration-duration-in-seconds配置)。當(dāng)Eureka Server節(jié)點(diǎn)在短時(shí)間內(nèi)丟失過(guò)多的心跳時(shí)(比如發(fā)生了網(wǎng)絡(luò)分區(qū)故障),,那么這個(gè)節(jié)點(diǎn)就會(huì)進(jìn)入自我保護(hù)模式,。下圖為Eureka官網(wǎng)的架構(gòu)圖
2.1.1.2 Eureka Server的Region,、ZoneEureka的官方文檔對(duì)Regin,、Zone幾乎沒(méi)有提及,由于概念抽象,,新手很難理解,。因此,我們先來(lái)了解一下Region,、Zone,、Eureka集群三者的關(guān)系,如下圖所示: region和zone(或者Availability Zone)均是AWS的概念,。在非AWS環(huán)境下,,我們可以先簡(jiǎn)單地將region理解為Eureka集群,zone理解成機(jī)房,。上圖就可以理解為一個(gè)Eureka集群被部署在了zone1機(jī)房和zone2機(jī)房中,。 2.1.2 Service Provider2.1.2.1 服務(wù)注冊(cè)Service Provider本質(zhì)上是一個(gè)Eureka Client。它啟動(dòng)時(shí),,會(huì)調(diào)用服務(wù)注冊(cè)方法,,向Eureka Server注冊(cè)自己的信息。Eureka Server會(huì)維護(hù)一個(gè)已注冊(cè)服務(wù)的列表,,這個(gè)列表為一個(gè)嵌套的hash map: 第一層,,application name和對(duì)應(yīng)的服務(wù)實(shí)例,。 第二層,服務(wù)實(shí)例及其對(duì)應(yīng)的注冊(cè)信息,,包括IP,,端口號(hào)等。 當(dāng)實(shí)例狀態(tài)發(fā)生變化時(shí)(如自身檢測(cè)認(rèn)為Down的時(shí)候),,也會(huì)向Eureka Server更新自己的服務(wù)狀態(tài),,同時(shí)用replicateToPeers()向其它Eureka Server節(jié)點(diǎn)做狀態(tài)同步。 2.1.2.2 續(xù)約與剔除前面提到過(guò),,服務(wù)實(shí)例啟動(dòng)后,,會(huì)周期性地向Eureka Server發(fā)送心跳以續(xù)約自己的信息,避免自己的注冊(cè)信息被剔除,。續(xù)約的方式與服務(wù)注冊(cè)基本一致:首先更新自身狀態(tài),,再同步到其它Peer。 如果Eureka Server在一段時(shí)間內(nèi)沒(méi)有接收到某個(gè)微服務(wù)節(jié)點(diǎn)的心跳,,Eureka Server將會(huì)注銷(xiāo)該微服務(wù)節(jié)點(diǎn)(自我保護(hù)模式除外),。 2.1.3 Service ConsumerService Consumer本質(zhì)上也是一個(gè)Eureka Client(它也會(huì)向Eureka Server注冊(cè),只是這個(gè)注冊(cè)信息無(wú)關(guān)緊要罷了),。它啟動(dòng)后,,會(huì)從Eureka Server上獲取所有實(shí)例的注冊(cè)信息,包括IP地址,、端口等,,并緩存到本地。這些信息默認(rèn)每30秒更新一次,。前文提到過(guò),如果與Eureka Server通信中斷,,Service Consumer仍然可以通過(guò)本地緩存與Service Provider通信,。 實(shí)際開(kāi)發(fā)Eureka的過(guò)程中,有時(shí)會(huì)遇見(jiàn)Service Consumer獲取到Server Provider的信息有延遲,,在Eureka Wiki中有這么一段話(huà):
最后一句話(huà)提到,,服務(wù)端的更改可能需要2分鐘才能傳播到所有客戶(hù)端,至于原因并沒(méi)有介紹,。這是因?yàn)镋ureka有三處緩存和一處延遲造成的,。 Eureka Server對(duì)注冊(cè)列表進(jìn)行緩存,默認(rèn)時(shí)間為30s,。 Eureka Client對(duì)獲取到的注冊(cè)信息進(jìn)行緩存,,默認(rèn)時(shí)間為30s。 Ribbon會(huì)從上面提到的Eureka Client獲取服務(wù)列表,,將負(fù)載均衡后的結(jié)果緩存30s,。 如果不是在Spring Cloud環(huán)境下使用這些組件(Eureka, Ribbon),服務(wù)啟動(dòng)后并不會(huì)馬上向Eureka注冊(cè),而是需要等到第一次發(fā)送心跳請(qǐng)求時(shí)才會(huì)注冊(cè),。心跳請(qǐng)求的發(fā)送間隔默認(rèn)是30s,。Spring Cloud對(duì)此做了修改,服務(wù)啟動(dòng)后會(huì)馬上注冊(cè),。 基于Service Consumer獲取到的服務(wù)實(shí)例信息,,我們就可以進(jìn)行服務(wù)調(diào)用了。而Spring Cloud也為Service Consumer提供了豐富的服務(wù)調(diào)用工具: Ribbon,,實(shí)現(xiàn)客戶(hù)端的負(fù)載均衡,。 Hystrix,斷路器,。 Feign,,RESTful Web Service客戶(hù)端,整合了Ribbon和Hystrix,。 接下來(lái)我們就一一介紹,。 Ribbon是Netflix發(fā)布的開(kāi)源項(xiàng)目,主要功能是為REST客戶(hù)端實(shí)現(xiàn)負(fù)載均衡,。它主要包括六個(gè)組件: ServerList,,負(fù)載均衡使用的服務(wù)器列表。這個(gè)列表會(huì)緩存在負(fù)載均衡器中,,并定期更新,。當(dāng)Ribbon與Eureka結(jié)合使用時(shí),ServerList的實(shí)現(xiàn)類(lèi)就是DiscoveryEnabledNIWSServerList,,它會(huì)保存Eureka Server中注冊(cè)的服務(wù)實(shí)例表,。 ServerListFilter,服務(wù)器列表過(guò)濾器,。這是一個(gè)接口,,主要用于對(duì)Service Consumer獲取到的服務(wù)器列表進(jìn)行預(yù)過(guò)濾,過(guò)濾的結(jié)果也是ServerList,。Ribbon提供了多種過(guò)濾器的實(shí)現(xiàn),。 IPing,探測(cè)服務(wù)實(shí)例是否存活的策略,。 IRule,,負(fù)載均衡策略,其實(shí)現(xiàn)類(lèi)表述的策略包括:輪詢(xún),、隨機(jī),、根據(jù)響應(yīng)時(shí)間加權(quán)等,其類(lèi)結(jié)構(gòu)如下圖所示,。!
ILoadBalancer,負(fù)載均衡器,。這也是一個(gè)接口,,Ribbon為其提供了多個(gè)實(shí)現(xiàn),比如ZoneAwareLoadBalancer,。而上層代碼通過(guò)調(diào)用其API進(jìn)行服務(wù)調(diào)用的負(fù)載均衡選擇,。一般ILoadBalancer的實(shí)現(xiàn)類(lèi)中會(huì)引用一個(gè)IRule。 RestClient,,服務(wù)調(diào)用器,。顧名思義,這就是負(fù)載均衡后,,Ribbon向Service Provider發(fā)起REST請(qǐng)求的工具,。 Ribbon工作時(shí)會(huì)做四件事情: 1,優(yōu)先選擇在同一個(gè)Zone且負(fù)載較少的Eureka Server,; 2,,定期從Eureka更新并過(guò)濾服務(wù)實(shí)例列表; 3,,根據(jù)用戶(hù)指定的策略,,在從Server取到的服務(wù)注冊(cè)列表中選擇一個(gè)實(shí)例的地址; 4,,通過(guò)RestClient進(jìn)行服務(wù)調(diào)用,。 Netflix創(chuàng)建了一個(gè)名為Hystrix的庫(kù),實(shí)現(xiàn)了斷路器的模式?!皵嗦菲鳌北旧硎且环N開(kāi)關(guān)裝置,,當(dāng)某個(gè)服務(wù)單元發(fā)生故障之后,通過(guò)斷路器的故障監(jiān)控(類(lèi)似熔斷保險(xiǎn)絲),,向調(diào)用方返回一個(gè)符合預(yù)期的、可處理的備選響應(yīng)(FallBack),,而不是長(zhǎng)時(shí)間的等待或者拋出調(diào)用方無(wú)法處理的異常,,這樣就保證了服務(wù)調(diào)用方的線(xiàn)程不會(huì)被長(zhǎng)時(shí)間、不必要地占用,,從而避免了故障在分布式系統(tǒng)中的蔓延,,乃至雪崩。 當(dāng)然,,在請(qǐng)求失敗頻率較低的情況下,,Hystrix還是會(huì)直接把故障返回給客戶(hù)端,。只有當(dāng)失敗次數(shù)達(dá)到閾值(默認(rèn)在20秒內(nèi)失敗5次)時(shí),斷路器打開(kāi)并且不進(jìn)行后續(xù)通信,,而是直接返回備選響應(yīng),。當(dāng)然,Hystrix的備選響應(yīng)也是可以由開(kāi)發(fā)者定制的,。 除了隔離依賴(lài)服務(wù)的調(diào)用以外,,Hystrix還提供了準(zhǔn)實(shí)時(shí)的調(diào)用監(jiān)控(Hystrix Dashboard),Hystrix會(huì)持續(xù)地記錄所有通過(guò)Hystrix發(fā)起的請(qǐng)求的執(zhí)行信息,,并以統(tǒng)計(jì)報(bào)表和圖形的形式展示給用戶(hù),,包括每秒執(zhí)行多少請(qǐng)求多少成功,多少失敗等,。Netflix通過(guò)hystrix-metrics-event-stream項(xiàng)目實(shí)現(xiàn)了對(duì)以上指標(biāo)的監(jiān)控,。Spring Cloud也提供了Hystrix Dashboard的整合,對(duì)監(jiān)控內(nèi)容轉(zhuǎn)化成可視化界面,,Hystrix Dashboard Wiki上詳細(xì)說(shuō)明了圖上每個(gè)指標(biāo)的含義,。 @SpringBootApplication 以上是一個(gè)Feign的簡(jiǎn)單示例。 Feign是一個(gè)聲明式的Web Service客戶(hù)端,,它的目的就是讓W(xué)eb Service調(diào)用更加簡(jiǎn)單,。它整合了Ribbon和Hystrix,從而讓我們不再需要顯式地使用這兩個(gè)組件,。Feign還提供了HTTP請(qǐng)求的模板,,通過(guò)編寫(xiě)簡(jiǎn)單的接口和插入注解,我們就可以定義好HTTP請(qǐng)求的參數(shù),、格式,、地址等信息。接下來(lái),,F(xiàn)eign會(huì)完全代理HTTP的請(qǐng)求,,我們只需要像調(diào)用方法一樣調(diào)用它就可以完成服務(wù)請(qǐng)求。 Feign具有如下特性: 可插拔的注解支持,,包括Feign注解和JAX-RS注解 支持可插拔的HTTP編碼器和解碼器 支持Hystrix和它的Fallback 支持Ribbon的負(fù)載均衡 支持HTTP請(qǐng)求和響應(yīng)的壓縮
|
|
來(lái)自: 快讀書(shū)館 > 《信息技術(shù)》