轉(zhuǎn)載
一:首先看一張springCloud的圖片:
二:簡單介紹下什么是springCloud?
"Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智能路由拓哺,微代理揣苏,控制總線)荧恍。分布式系統(tǒng)的協(xié)調(diào)導(dǎo)致了樣板模式, 使用Spring Cloud開發(fā)人員可以快速地支持實(shí)現(xiàn)這些模式的服務(wù)和應(yīng)用程序菲语。他們將在任何分布式環(huán)境中運(yùn)行良好拴驮,包括開發(fā)人員自己的筆記本電腦唤反,裸機(jī)數(shù)據(jù)中心凳寺,以及Cloud Foundry等托管平臺鸭津。" -----來自官網(wǎng)
三:為了方便理解假設(shè)一個(gè)業(yè)務(wù)場景(場景來源于石杉的架構(gòu)筆記(id:shishan100))
假設(shè)現(xiàn)在開發(fā)一個(gè)電商網(wǎng)站,要實(shí)現(xiàn)支付訂單功能:流程如下--
?? ?1.創(chuàng)建一個(gè)訂單后,如果用戶立刻支付了這個(gè)訂單,我們需要將這個(gè)訂單狀態(tài)更新為(已經(jīng)支付)
?? ?2.扣減相對應(yīng)的商品庫存
?? ?3.通知倉儲中心,進(jìn)行發(fā)貨
?? ?4.給用戶這次購物怎加相對應(yīng)的積分
針對上述流程,我們需要有訂單服務(wù)肠缨、庫存服務(wù)逆趋、倉儲服務(wù)、積分服務(wù)晒奕。整個(gè)流程的大體思路如下:
?? ?1.用戶針對一個(gè)訂單完成支付后,就回去找訂單服務(wù),跟新訂單狀態(tài)
?? ?2.訂單服務(wù)調(diào)用庫存服務(wù),完成相應(yīng)的功能
?? ?3.訂單服務(wù)調(diào)用倉儲服務(wù),完成相應(yīng)的功能
?? ?4.訂單服務(wù)調(diào)用積分服務(wù),完成相應(yīng)的功能
整個(gè)支付流程結(jié)束
整個(gè)過程可以如下圖所示:
四:SpringCloud核心組件:Eureka
4.1首先考慮第一個(gè)問題,訂單服務(wù)要調(diào)用庫存服務(wù),倉儲服務(wù),或積分服務(wù),怎么調(diào)用?
1.訂單服務(wù)根本不知道庫存服務(wù)在哪臺機(jī)器上,就算想起來,都不知道發(fā)送給誰?
?? ?隨意springCloud就有一個(gè)springCloud的Eureka,Eureka是服務(wù)架構(gòu)的注冊中心
?? ?專門負(fù)責(zé)服務(wù)的注冊和發(fā)現(xiàn);
看下這個(gè)圖:
如上圖所示:庫存服務(wù),倉儲服務(wù),積分服務(wù),都有一個(gè)Eureka Client組件組件,這個(gè)專門這個(gè)服務(wù)的信息注冊到Eureka Server中,說白了就是告訴Eureka Server,自己在哪臺機(jī)器上,監(jiān)聽那個(gè)端口,而Eureka?是一個(gè)注冊中心,里面有一個(gè)注冊表,保存了各個(gè)服務(wù)器的機(jī)器和端口,
訂單服務(wù)里面有一個(gè)Eureka Client組件組件,Eureka Client組件會問一下:庫存在那臺服務(wù)器上,監(jiān)聽的端口號是哪個(gè),倉儲服務(wù)呢闻书?積分服務(wù)呢?然后就可以把這些相關(guān)信息從Eureka Server的注冊表中拉取到自己本地緩存起來脑慧。
這時(shí)候如果訂單服務(wù)想要調(diào)用庫存服務(wù),不就可以找自己本地Eureka Client問題下庫存服務(wù)在那臺機(jī)器上,監(jiān)聽哪個(gè)端口嗎魄眉?收到響應(yīng)后,緊接著就可以發(fā)送一個(gè)請求過去闷袒,調(diào)用庫存服務(wù)扣減庫存的那個(gè)接口坑律!同理,如果訂單服務(wù)要調(diào)用倉儲服務(wù)囊骤、積分服務(wù)脾歇,也是如法炮制。
所以總結(jié)下:
? Eureka?service:注冊中心,里面有一個(gè)注冊表,保存了各個(gè)服務(wù)所在的機(jī)器和端口號
? Eurake Client:負(fù)責(zé)將這個(gè)服務(wù)的信息注冊到Eureka Server中
五springCloud核心組件;Feign
現(xiàn)在訂單服務(wù)確實(shí)知道庫存服務(wù),積分服務(wù),倉儲服務(wù)在哪里了,同事有監(jiān)聽著這些端口號,
但是新問題又來了,難道訂單服務(wù)要寫一大堆代碼,跟其他服務(wù)建立網(wǎng)絡(luò)連接,然后構(gòu)造一個(gè)復(fù)雜的
請求,接著發(fā)送請求過去,結(jié)果寫一大堆代碼來相應(yīng)處理
比如這樣:
如果每次手寫代碼,代碼量比上面的還要多,隨意SpringCloud提供了一個(gè)優(yōu)雅的解決方案,看看Feign的話訂單服務(wù)調(diào)用庫存的代碼會變成啥樣?
沒有底層的建立連接淘捡、構(gòu)造請求、解析響應(yīng)的代碼池摧,直接就是用注解定義一個(gè) FeignClient接口焦除,然后調(diào)用那個(gè)接口就可以了。人家Feign Client會在底層根據(jù)你的注解作彤,跟你指定的服務(wù)建立連接膘魄、構(gòu)造請求、發(fā)起靕求竭讳、獲取響應(yīng)创葡、解析響應(yīng),等等绢慢。這一系列臟活累活灿渴,人家Feign全給你干了。
問題來了,Feign是如何做到的呢?其實(shí)Feign的一個(gè)機(jī)制就是使用了動態(tài)代理,
首先胰舆,如果你對某個(gè)接口定義了@FeignClient注解骚露,F(xiàn)eign就會針對這個(gè)接口創(chuàng)建一個(gè)動態(tài)代理
接著你要是調(diào)用那個(gè)接口,本質(zhì)就是會調(diào)用 Feign創(chuàng)建的動態(tài)代理缚窿,這是核心中的核心
Feign的動態(tài)代理會根據(jù)你在接口上的@RequestMapping等注解棘幸,來動態(tài)構(gòu)造出你要請求的服務(wù)的地址
最后針對這個(gè)地址,發(fā)起請求倦零、解析響應(yīng)
六:springCloud核心組件:Ribbon
說完了,那么問題來了,如果庫存服務(wù)上面部署了臺機(jī)器,
192.168.169:9000
192.168.170:9000
192.168.171:9000
192.168.172:9000
192.168.173:9000
那Feign怎么知道請求那臺服務(wù)器呢,這是SpringCloud就派上用場了,Ribbon?務(wù)就是解決這個(gè)問題的,他的作用是負(fù)載均衡,會幫你在每一次請求的時(shí)候選擇一臺機(jī)器,均勻的把請求發(fā)送到各個(gè)機(jī)器上 ,Ribbon的負(fù)載均衡默認(rèn)的使用RoundRobin輪詢算法,什么是輪詢算法?如果訂單服務(wù)對庫存發(fā)起十次請求,那就先讓你請求第一臺機(jī)器,然后是第二臺機(jī)器,第三臺機(jī)器,.......接著循環(huán)到第十臺機(jī)器
此外误续,Ribbon是和Feign以及Eureka緊密協(xié)作吨悍,完成工作的,具體如下:
首先Ribbon會從?Eureka Client里面獲取到對應(yīng)的服務(wù)注冊表,也就知道了所有的服務(wù)都部署在了那臺機(jī)器上,在監(jiān)聽哪些端口,
然后Ribbon就可以使用默認(rèn)的Round Robin算法,從中選擇一臺機(jī)器,
Feigin就會針對這些機(jī)器構(gòu)造并發(fā)送請求.可以參考如下這圖:
七:SpringCloud的核心組件:Hystrix
在微服務(wù)架構(gòu)里,一個(gè)系統(tǒng)會有多個(gè)服務(wù),?以本文的業(yè)務(wù)場景為例:訂單服務(wù)在一個(gè)業(yè)務(wù)流程里需要調(diào)用三個(gè)服務(wù),現(xiàn)在假設(shè)訂單服務(wù)自己最多只有100個(gè)線程可以處理請求然后呢蹋嵌,積分服務(wù)不幸的掛了育瓜,每次訂單服務(wù)調(diào)用積分服務(wù)的時(shí)候,都會卡住幾秒鐘欣尼,然后拋出—個(gè)超時(shí)異常爆雹。
分析下這樣會導(dǎo)致什么問題:如果系統(tǒng)在高并發(fā)的情況下,大量請求涌過來的時(shí)候,訂單服務(wù)的100個(gè)線程會卡在積分服務(wù)這塊,導(dǎo)致訂單服務(wù)沒有一個(gè)線程可以處理請求,然后會導(dǎo)致別的請求訂單服務(wù)的時(shí)候,發(fā)現(xiàn)訂單服務(wù)掛掉,不響應(yīng)任何請求了,這種問題就是微服務(wù)架構(gòu)中恐怖的服務(wù)器雪崩問題:如下圖,這么多的服務(wù)互相調(diào)用要是不做任何保護(hù)的話,某一個(gè)服務(wù)掛掉會引起連鎖反應(yīng),導(dǎo)致別的服務(wù)掛掉,比如積分服務(wù)掛了會導(dǎo)致訂單服務(wù)的線程全部卡在請求積分服務(wù)這里沒有一個(gè)線程可以工作,瞬間導(dǎo)致訂單服務(wù)也掛了別人請求訂單服務(wù)全部會卡住愕鼓,無法響應(yīng)钙态。
但是我們思考一下,就算積分服務(wù)掛了菇晃,訂單服務(wù)也可以不用掛安岬埂!為什么磺送?
我們結(jié)合業(yè)務(wù)來看:支付訂單的時(shí)候驻子,只要把庫存扣減了,然后通知倉庫發(fā)貨就OK了
如果積分服務(wù)掛了估灿,大不了等他恢復(fù)之后崇呵,慢慢人肉手工恢復(fù)數(shù)據(jù)!為啥一定要因?yàn)橐粋€(gè)積分服務(wù)掛了馅袁,就直接導(dǎo)致訂單服務(wù)也掛了呢域慷?不可以接受!
現(xiàn)在問題分析完了汗销,如何解決犹褒?
這時(shí)就輪到Hystrix閃亮登場了。Hystrix是隔離弛针、熔斷以及降級的一個(gè)框架叠骑。啥意思說白了就是Hystrix會搞很多小線程池,每個(gè)小線程池里的線程僅用去請求的服務(wù),
打個(gè)比方:現(xiàn)在很不幸,積分服務(wù)掛了削茁,會咋樣宙枷?
當(dāng)然會導(dǎo)致訂單服務(wù)里那個(gè)用來調(diào)用積分服務(wù)的線程都卡死不能工作了啊茧跋!但由于訂單服務(wù)調(diào)用庫存服務(wù)朦拖、倉儲服務(wù)的這兩個(gè)線程池都是正常工作的,所以這兩個(gè)服務(wù)不會受到任何影響厌衔。這個(gè)時(shí)候如果別人請求訂單服務(wù),訂單服務(wù)還是可以正常調(diào)用訂單服務(wù)還是可以正常調(diào)用庫存服務(wù)扣減庫存調(diào)用倉儲服務(wù)通知發(fā)貨璧帝。只不過調(diào)用積分服務(wù)的時(shí)候,每次都會報(bào)錯富寿。但是如果積分服務(wù)都掛了睬隶,每次調(diào)用都要去卡住幾秒鐘干啥呢锣夹?有意義嗎?當(dāng)然沒有苏潜!所以我們直接對積分服務(wù)熔斷不就得了银萍,比如在5分鐘內(nèi)請求積分服務(wù)直接就返回了,不要去走網(wǎng)絡(luò)請求卡住幾秒鐘恤左,這個(gè)過程贴唇,就是所謂的熔斷!
那人家又說飞袋,兄弟戳气,積分服務(wù)掛了你就熔斷,好歹你干點(diǎn)兒什么扒裳肌瓶您!別啥都不干就直接返回啊纲仍?沒問題呀袱,咱們就來個(gè)降級:每次調(diào)用積分服務(wù),你就在數(shù)據(jù)庫里記錄一條消息郑叠,說給某某用戶增加了多少積分夜赵,因?yàn)榉e分服務(wù)掛了,導(dǎo)致沒增加成功乡革!這樣等積分服務(wù)恢復(fù)了油吭,你可以根據(jù)這些記錄手工加一下積分。這個(gè)過程署拟,就是所謂的降級。為幫助大家更直觀的理解歌豺,接下來用一張圖推穷,梳理一下Hystrix隔離、熔斷和降級的全流程:
七:SpringCloud核心組件:zull
Zuul:微服務(wù)網(wǎng)關(guān),這個(gè)組件是負(fù)責(zé)網(wǎng)絡(luò)路由的!
什么事網(wǎng)絡(luò)路由?
假設(shè)你后臺部署了幾百個(gè)服務(wù)类咧,現(xiàn)在有個(gè)前端兄弟馒铃,人家請求是直接從瀏覽器那兒發(fā)過來的。打個(gè)比方:人家要請求一下庫存服務(wù)痕惋,你難道還讓人家記著這服務(wù)的名字叫做inventory-service区宇?部署在5臺機(jī)器上?就算人家肯記住這一個(gè)值戳,你后臺可有幾百個(gè)服務(wù)的名稱和地址呢议谷?難不成人家請求一個(gè),就得記住一個(gè)堕虹?你要這樣玩兒卧晓,那就是中美合拍,文體開花了!
上面這種情況芬首,壓根兒是不現(xiàn)實(shí)的。所以一般微服務(wù)架構(gòu)中都必然會設(shè)計(jì)一個(gè)網(wǎng)關(guān)在里面逼裆,像android郁稍、ios、pc前端胜宇、微信小程序耀怜、H5等等,不用去關(guān)心后端有幾百個(gè)服務(wù)桐愉,就知道有一個(gè)網(wǎng)關(guān)财破,所有請求都往網(wǎng)關(guān)走,網(wǎng)關(guān)會根據(jù)請求中的一些特征仅财,將請求轉(zhuǎn)發(fā)給后端的各個(gè)服務(wù)狈究。
而且有一個(gè)網(wǎng)關(guān)之后,還有很多好處盏求,比如可以做統(tǒng)一的降級抖锥、限流、認(rèn)證授權(quán)碎罚、安全磅废,等等。
總結(jié)一下SpringCloud結(jié)果核心組件:
Eureka:個(gè)服務(wù)啟動時(shí),Eureka會將服務(wù)注冊到EurekaService,并且EurakeClient還可以返回過來從EurekaService拉去注冊表,從而知道服務(wù)在哪里
Ribbon:服務(wù)間發(fā)起請求的時(shí)候,基于Ribbon服務(wù)做到負(fù)載均衡,從一個(gè)服務(wù)的對臺機(jī)器中選擇一臺
Feign:基于fegin的動態(tài)代理機(jī)制,根據(jù)注解和選擇機(jī)器,拼接Url地址,發(fā)起請求
Hystrix:發(fā)起的請求是通過Hystrix的線程池來走,不同的服走不同的線程池,實(shí)現(xiàn)了不同的服務(wù)調(diào)度隔離,避免服務(wù)雪崩的問題?
Zuul:如果前端后端移動端調(diào)用后臺系統(tǒng),統(tǒng)一走zull網(wǎng)關(guān)進(jìn)入,有zull網(wǎng)關(guān)轉(zhuǎn)發(fā)請求給對應(yīng)的服務(wù)
Spring Cloud的5個(gè)核心組件通過一張圖串聯(lián)起來