- 極簡(jiǎn)Spring Cloud實(shí)戰(zhàn)
- 胡勁寒
- 4071字
- 2019-10-10 18:57:57
1.2 Spring Cloud面面觀
為了降低用戶構(gòu)建和維護(hù)分布式系統(tǒng)的難度,推動(dòng)微服務(wù)的落地,Spring Cloud提供了快速構(gòu)建分布式微服務(wù)系統(tǒng)的一些常用功能,如配置管理、服務(wù)發(fā)現(xiàn)、斷路器、智能路由、服務(wù)代理、控制總線等提供的一套開(kāi)發(fā)工具。這些工具就相當(dāng)于分布式系統(tǒng)的樣板,Spring Cloud的使用者可以使用這些樣板工具快速構(gòu)建服務(wù)以及相關(guān)應(yīng)用。這些工具能夠在任何分布式環(huán)境中良好運(yùn)行,如開(kāi)發(fā)者的計(jì)算機(jī)、數(shù)據(jù)中心以及類似Cloud Foundry這樣的管理平臺(tái)。
Spring Cloud適用于以下場(chǎng)景:配置管理、服務(wù)發(fā)現(xiàn)、斷路器、智能路由、微代理、控制總線、一次性令牌、全局鎖、領(lǐng)導(dǎo)選舉、分布式會(huì)話、集群狀態(tài)等。
接下來(lái)從服務(wù)化架構(gòu)演進(jìn)的角度來(lái)講述為什么Spring Cloud更適應(yīng)微服務(wù)架構(gòu)。
1.2.1 Spring Cloud與Dubbo對(duì)比
我們先從Nginx說(shuō)起,了解為什么需要微服務(wù)。最初的服務(wù)化解決方案是給相同服務(wù)提供一個(gè)統(tǒng)一的域名,然后服務(wù)調(diào)用者向這個(gè)域發(fā)送HTTP請(qǐng)求,由Nginx負(fù)責(zé)請(qǐng)求的分發(fā)和跳轉(zhuǎn)。
這種架構(gòu)存在很多問(wèn)題:Nginx作為中間層,在配置文件中耦合了服務(wù)調(diào)用的邏輯,這削弱了微服務(wù)的完整性,也使得Nginx在一定程度上變成了一個(gè)重量級(jí)的ESB。圖1-7標(biāo)識(shí)出了Nginx的轉(zhuǎn)發(fā)信息流走向。

圖1-7 Nginx轉(zhuǎn)發(fā)的信息流
服務(wù)的信息分散在各個(gè)系統(tǒng),無(wú)法統(tǒng)一管理和維護(hù)。每一次的服務(wù)調(diào)用都是一次嘗試,服務(wù)消費(fèi)方并不知道有哪些實(shí)例在給他們提供服務(wù)。這帶來(lái)了一些問(wèn)題:
? 無(wú)法直觀地看到服務(wù)提供方和服務(wù)消費(fèi)方當(dāng)前的運(yùn)行狀況與通信頻率;
? 消費(fèi)方的失敗重發(fā)、負(fù)載均衡等都沒(méi)有統(tǒng)一策略,這加大了開(kāi)發(fā)每個(gè)服務(wù)的難度,不利于快速演化。
為了解決上面的問(wèn)題,我們需要一個(gè)現(xiàn)成的中心組件對(duì)服務(wù)進(jìn)行整合,將每個(gè)服務(wù)的信息匯總,包括服務(wù)的組件名稱、地址、數(shù)量等。服務(wù)的調(diào)用方在請(qǐng)求某項(xiàng)服務(wù)時(shí)首先通過(guò)中心組件獲取提供服務(wù)的實(shí)例信息(IP、端口等),再通過(guò)默認(rèn)或自定義的策略選擇該服務(wù)的某一提供方直接進(jìn)行訪問(wèn),所以考慮引入Dubbo。
Dubbo是阿里開(kāi)源的一個(gè)SOA服務(wù)治理解決方案,文檔豐富,在國(guó)內(nèi)的使用度非常高。圖1-8為Dubbo的基本架構(gòu)圖,使用Dubbo構(gòu)建的微服務(wù)已經(jīng)可以較好地解決上面提到的問(wèn)題。

圖1-8 Dubbo的基本架構(gòu)圖
從圖1-8中,可以看出:
? 調(diào)用中間層變成了可選組件,消費(fèi)方可以直接訪問(wèn)服務(wù)提供方;
? 服務(wù)信息被集中到Registry中,形成了服務(wù)治理的中心組件;
? 通過(guò)Monitor監(jiān)控系統(tǒng),可以直觀地展示服務(wù)調(diào)用的統(tǒng)計(jì)信息;
? 服務(wù)消費(fèi)者可以進(jìn)行負(fù)載均衡、服務(wù)降級(jí)的選擇。
但是對(duì)于微服務(wù)架構(gòu)而言,Dubbo并不是十全十美的,也有一些缺陷。
? Registry嚴(yán)重依賴第三方組件(ZooKeeper或者Redis),當(dāng)這些組件出現(xiàn)問(wèn)題時(shí),服務(wù)調(diào)用很快就會(huì)中斷。
? Dubbo只支持RPC調(diào)用。這使得服務(wù)提供方與調(diào)用方在代碼上產(chǎn)生了強(qiáng)依賴,服務(wù)提供方需要不斷將包含公共代碼的Jar包打包出來(lái)供消費(fèi)方使用。一旦打包出現(xiàn)問(wèn)題,就會(huì)導(dǎo)致服務(wù)調(diào)用出錯(cuò)。
筆者認(rèn)為,Dubbo和Spring Cloud并不是完全的競(jìng)爭(zhēng)關(guān)系,兩者所解決的問(wèn)題域并不一樣:Dubbo的定位始終是一款RPC框架,而Spring Cloud的目標(biāo)是微服務(wù)架構(gòu)下的一站式解決方案。如果非要比較的話,Dubbo可以類比到Netflix OSS技術(shù)棧,而Spring Cloud集成了Netflix OSS作為分布式服務(wù)治理解決方案,但除此之外Spring Cloud還提供了配置、消息、安全、調(diào)用鏈跟蹤等分布式問(wèn)題解決方案。
當(dāng)前由于RPC協(xié)議、注冊(cè)中心元數(shù)據(jù)不匹配等問(wèn)題,在面臨微服務(wù)基礎(chǔ)框架選型時(shí)Dubbo與Spring Cloud只能二選一,這也是大家總是拿Dubbo和Spring Cloud做對(duì)比的原因之一。Dubbo已經(jīng)適配到Spring Cloud生態(tài),比如作為Spring Cloud的二進(jìn)制通信方案來(lái)發(fā)揮Dubbo的性能優(yōu)勢(shì),Dubbo通過(guò)模塊化以及對(duì)HTTP的支持適配到Spring Cloud。
1.2.2 Spring Cloud好在哪里
作為新一代的服務(wù)框架,Spring Cloud提出的口號(hào)是開(kāi)發(fā)“面向云的應(yīng)用程序”,它為微服務(wù)架構(gòu)提供了更加全面的技術(shù)支持。結(jié)合我們一開(kāi)始提到的微服務(wù)的訴求,參見(jiàn)表1-1,把Spring Cloud與Dubbo進(jìn)行一番對(duì)比。
表1-1 Spring Cloud與Dubbo功能對(duì)比

Spring Cloud拋棄了Dubbo的RPC通信,采用的是基于HTTP的REST方式。嚴(yán)格來(lái)說(shuō),這兩種方式各有優(yōu)劣。雖然從一定程度上來(lái)說(shuō),后者犧牲了服務(wù)調(diào)用的性能,但也避免了上面提到的原生RPC帶來(lái)的問(wèn)題。而且REST相比RPC更為靈活,服務(wù)提供方和調(diào)用方,不存在代碼級(jí)別的強(qiáng)依賴,這在強(qiáng)調(diào)快速演化的微服務(wù)環(huán)境下顯得更加合適。
很明顯,Spring Cloud的功能比Dubbo更加強(qiáng)大,涵蓋面更廣,而且作為Spring的拳頭項(xiàng)目,它也能夠與Spring Framework、Spring Boot、Spring Data、Spring Batch等其他Spring項(xiàng)目完美融合,這些對(duì)于微服務(wù)而言是至關(guān)重要的。前面提到,微服務(wù)背后一個(gè)重要的理念就是持續(xù)集成、快速交付,而在服務(wù)內(nèi)部使用一個(gè)統(tǒng)一的技術(shù)框架,顯然比將分散的技術(shù)組合到一起更有效率。更重要的是,相比于Dubbo,它是一個(gè)正在持續(xù)維護(hù)的、社區(qū)更加火熱的開(kāi)源項(xiàng)目,這就可以保證使用它構(gòu)建的系統(tǒng)持續(xù)地得到開(kāi)源力量的支持。
下面列舉Spring Cloud的幾個(gè)優(yōu)勢(shì)。
? Spring Cloud來(lái)源于Spring,質(zhì)量、穩(wěn)定性、持續(xù)性都可以得到保證。
? Spirng Cloud天然支持Spring Boot,更加便于業(yè)務(wù)落地。
? Spring Cloud發(fā)展得非常快,從開(kāi)始接觸時(shí)的相關(guān)組件版本為1.x,到現(xiàn)在將要發(fā)布2.x系列。
? Spring Cloud是Java領(lǐng)域最適合做微服務(wù)的框架。
? 相比于其他框架,Spring Cloud對(duì)微服務(wù)周邊環(huán)境的支持力度最大。對(duì)于中小企業(yè)來(lái)講,使用門檻較低。
1.2.3 Spring Cloud子項(xiàng)目與解決方案
我們從整體上來(lái)看一下Spring Cloud各個(gè)組件如何配套使用,如圖1-9所示。

圖1-9 Spring Cloud各個(gè)組件協(xié)同示意圖
從圖1-9可以看出,Spring Cloud各個(gè)組件相互配合,合作支持了一套完整的微服務(wù)架構(gòu)。
Spring Cloud從設(shè)計(jì)之初就考慮了絕大多數(shù)互聯(lián)網(wǎng)公司架構(gòu)演化所需的功能,這些功能都是以插拔的形式提供,方便合理選擇需要的組件進(jìn)行集成,從而使用過(guò)程中更加平滑、順利。
Spring Cloud提供了標(biāo)準(zhǔn)化的、一站式的技術(shù)方案。下面按照Spring Cloud子項(xiàng)目和其提供的分布式方案來(lái)分別了解Spring Cloud價(jià)值。
系統(tǒng)一旦走向分布式,其復(fù)雜程度成倍增長(zhǎng),傳統(tǒng)單體應(yīng)用那種只考慮業(yè)務(wù)邏輯的開(kāi)發(fā)方式已經(jīng)不再適用。正因其復(fù)雜性,目前只有業(yè)務(wù)需求大的大型互聯(lián)網(wǎng)公司才會(huì)(被迫)采用,而且需要投入大量的技術(shù)力量來(lái)開(kāi)發(fā)基礎(chǔ)設(shè)施,也造成了小公司“用不起”分布式架構(gòu)的情況。現(xiàn)在這一局面正在逐漸被打破,因?yàn)镹etflix開(kāi)源了經(jīng)過(guò)實(shí)戰(zhàn)考驗(yàn)的一系列基礎(chǔ)設(shè)施構(gòu)件,加上Spring Cloud的大力支持,開(kāi)發(fā)分布式系統(tǒng)已經(jīng)不再像以前那樣可怕了。
(1)服務(wù)的注冊(cè)發(fā)現(xiàn)和軟負(fù)載均衡
Spring Cloud Netflix通過(guò)Eureka Server實(shí)現(xiàn)服務(wù)注冊(cè)中心,通過(guò)Ribbon實(shí)現(xiàn)軟負(fù)載均衡。
(2)分區(qū)治理
Eureka支持Region和Zone的概念。其中一個(gè)Region可以包含多個(gè)Zone。Eureka在啟動(dòng)時(shí)需要指定一個(gè)Zone名,即當(dāng)前Eureka屬于哪個(gè)Zone,如果不指定則屬于defaultZone。Eureka Client也需要指定Zone, Client(當(dāng)與Ribbon配置使用時(shí))在向Server獲取注冊(cè)列表時(shí)會(huì)優(yōu)先向自己所在Zone的Eureka發(fā)請(qǐng)求,只有自己Zone中的Eureka全掛了才會(huì)嘗試向其他Zone發(fā)請(qǐng)求。當(dāng)獲取到遠(yuǎn)程服務(wù)列表后,Client也會(huì)優(yōu)先向同一個(gè)Zone的服務(wù)發(fā)起遠(yuǎn)程調(diào)用。Region和Zone可以對(duì)應(yīng)于現(xiàn)實(shí)中的大區(qū)和機(jī)房,如在華北地區(qū)有10個(gè)機(jī)房,在華南地區(qū)有20個(gè)機(jī)房,那么分別為Eureka指定合理的Region和Zone能有效避免跨機(jī)房調(diào)用,而一個(gè)地區(qū)的Eureka壞掉也不會(huì)導(dǎo)致整個(gè)該地區(qū)的服務(wù)都不可用。
(3)Ribbon軟負(fù)載均衡
Ribbon在工作時(shí)分成兩步:第一步先選擇Eureka Server,優(yōu)先選擇同一個(gè)Zone且負(fù)載較少的Server,第二步再根據(jù)用戶指定的策略,在從Server取到的服務(wù)注冊(cè)列表中選擇一個(gè)地址。其中Ribbon默認(rèn)提供了三種策略:輪詢、斷路器和根據(jù)響應(yīng)時(shí)間加權(quán)。
(4)聲明式HTTP RESTful客戶端Feign
Feign與Apache Http Client這類客戶端最大的不同,是它允許通過(guò)定義接口的形式構(gòu)造HTTP請(qǐng)求,不需要手動(dòng)拼參數(shù),使用起來(lái)與正常的本地調(diào)用沒(méi)有什么區(qū)別:
@FeignClient(name = "ea") public interface AdvertGroupRemoteService { @RequestMapping(value = "/group/{groupId}", method = RequestMethod.GET) AdvertGroupVO findByGroupId(@PathVariable("groupId") Integer adGroupId); }
這里只需要調(diào)用AdvertGroupRemoteService.findByGroupId()方法就能完成向目標(biāo)主機(jī)發(fā)送HTTP請(qǐng)求并封裝返回結(jié)果的效果。
(5)斷路器
斷路器(Cricuit Breaker)是一種能夠在遠(yuǎn)程服務(wù)不可用時(shí)自動(dòng)熔斷(打開(kāi)開(kāi)關(guān)),并在遠(yuǎn)程服務(wù)恢復(fù)時(shí)自動(dòng)恢復(fù)(閉合開(kāi)關(guān))的設(shè)施,Spring Cloud通過(guò)Netflix的Hystrix組件提供斷路器、資源隔離與自我修復(fù)功能。
(6)資源隔離
Hystrix對(duì)每一個(gè)依賴服務(wù)都配置了一個(gè)線程池,對(duì)依賴服務(wù)的調(diào)用會(huì)在線程池中執(zhí)行。例如,我們?cè)O(shè)計(jì)服務(wù)I的線程池大小為20,那么Hystrix會(huì)最多允許有20個(gè)容器線程調(diào)用服務(wù)I,如果超出20, Hystrix會(huì)拒絕并快速失敗。這樣即使服務(wù)I長(zhǎng)時(shí)間未響應(yīng),容器最多也只能堵塞20個(gè)線程,剩余80個(gè)線程仍然可以處理用戶請(qǐng)求。
(7)快速失敗
快速失敗是防止資源耗盡的關(guān)鍵一點(diǎn)。當(dāng)Hystrix發(fā)現(xiàn)在過(guò)去某段時(shí)間內(nèi)對(duì)服務(wù)I的調(diào)用出錯(cuò)率達(dá)到某個(gè)閾值時(shí),Hystrix就會(huì)“熔斷”該服務(wù),后續(xù)任何發(fā)向服務(wù)I的請(qǐng)求都會(huì)快速失敗,而不是白白讓調(diào)用線程去等待。
(8)自我修復(fù)
處于熔斷狀態(tài)的服務(wù),在經(jīng)過(guò)一段時(shí)間后,Hystrix會(huì)讓其進(jìn)入“半關(guān)閉”狀態(tài),即允許少量請(qǐng)求通過(guò),然后統(tǒng)計(jì)調(diào)用的成功率。如果這個(gè)請(qǐng)求能成功,Hystrix會(huì)恢復(fù)該服務(wù),從而達(dá)到自我修復(fù)的效果。其中,在服務(wù)被熔斷到進(jìn)入半關(guān)閉狀態(tài)之間的時(shí)間,就是留給開(kāi)發(fā)人員排查錯(cuò)誤并恢復(fù)故障的時(shí)間,開(kāi)發(fā)人員可以通過(guò)監(jiān)控措施得到提醒并線上排查。
(9)監(jiān)控方案
監(jiān)控是保障分布式系統(tǒng)健康運(yùn)行必不可少的方案。基于Spring Cloud,我們可以從兩個(gè)緯度進(jìn)行監(jiān)控:Hystrix斷路器的監(jiān)控和每個(gè)服務(wù)監(jiān)控狀況的監(jiān)控。
圖1-10是Hystrix提供的Dashboard圖形化監(jiān)控。

圖1-10 Hystrix的Dashboard圖形化監(jiān)控界面
可見(jiàn)圖1-10中監(jiān)控信息應(yīng)有盡有(調(diào)用成功率、平時(shí)響應(yīng)時(shí)間、調(diào)用頻次、斷路器狀態(tài)等)。可以通過(guò)編程的方式定時(shí)獲取該信息,并在斷路器熔斷時(shí)通過(guò)短信、郵件等方式通知開(kāi)發(fā)者。
Hystrix的監(jiān)控?cái)?shù)據(jù)默認(rèn)保存在每個(gè)實(shí)例的內(nèi)存中,Spring Boot提供了多種方式,可以導(dǎo)入到Redis、TSDB以供日后分析使用。
除此之外,Spring Cloud還提供了對(duì)單個(gè)實(shí)例的監(jiān)控,如圖1-11所示。其中包含了接口調(diào)用頻次、響應(yīng)時(shí)間、JVM狀態(tài)、動(dòng)態(tài)日志等各種開(kāi)發(fā)者關(guān)心的信息。

圖1-11 監(jiān)控界面
Spring Cloud的版本介紹
(1)版本命名
之前提到過(guò),Spring Cloud是一個(gè)擁有諸多子項(xiàng)目的大型綜合項(xiàng)目,原則上其子項(xiàng)目也都維護(hù)著自己的發(fā)布版本號(hào)。每一個(gè)Spring Cloud的版本都會(huì)包含不同的子項(xiàng)目版本,為了管理每個(gè)版本的子項(xiàng)目清單,避免版本名與子項(xiàng)目的發(fā)布號(hào)混淆,沒(méi)有采用版本號(hào)的方式,而是通過(guò)命名的方式。這些版本采用了倫敦地鐵站的名字,根據(jù)字母表的順序來(lái)對(duì)應(yīng)版本時(shí)間順序,比如:最早的Release版本為Angel,第二個(gè)Release版本為Brixton,依此類推。
(2)版本號(hào)
經(jīng)過(guò)上面的解釋,不難猜出,Angel.SR6和Brixton.SR5中的SR6、SR5就是版本號(hào)了。
當(dāng)一個(gè)版本的Spring Cloud項(xiàng)目的發(fā)布內(nèi)容積累到臨界點(diǎn)或者一個(gè)嚴(yán)重bug解決后,就會(huì)發(fā)布一個(gè)“service releases”版本,簡(jiǎn)稱SRX版本,其中X是一個(gè)遞增數(shù)字。
(3)當(dāng)前版本
我們?cè)谶x擇Spring Boot與Spring Cloud版本的時(shí)候,還是需要盡可能按照Spring Cloud官方版本依賴關(guān)系來(lái)選擇:
? Brixton版本對(duì)應(yīng)Spring Boot 1.3.x;
? Camden版本對(duì)應(yīng)Spring Boot 1.4.x;
? Dalston版本對(duì)應(yīng)Spring Boot 1.5.x。
在開(kāi)始正式介紹每個(gè)項(xiàng)目之前,需要準(zhǔn)備如表1-2所示的環(huán)境。
表1-2 必備工具

- Intel FPGA/CPLD設(shè)計(jì)(基礎(chǔ)篇)
- 觸摸屏實(shí)用技術(shù)與工程應(yīng)用
- 龍芯應(yīng)用開(kāi)發(fā)標(biāo)準(zhǔn)教程
- 電腦軟硬件維修大全(實(shí)例精華版)
- INSTANT Wijmo Widgets How-to
- 硬件產(chǎn)品經(jīng)理成長(zhǎng)手記(全彩)
- 單片機(jī)原理及應(yīng)用系統(tǒng)設(shè)計(jì)
- 平衡掌控者:游戲數(shù)值經(jīng)濟(jì)設(shè)計(jì)
- 計(jì)算機(jī)維修與維護(hù)技術(shù)速成
- 電腦軟硬件維修從入門到精通
- Large Scale Machine Learning with Python
- Rapid BeagleBoard Prototyping with MATLAB and Simulink
- 單片機(jī)系統(tǒng)設(shè)計(jì)與開(kāi)發(fā)教程
- 面向?qū)ο蠓治雠c設(shè)計(jì)(第3版)(修訂版)
- Blender Game Engine:Beginner's Guide