前言:本文介紹了微服務(wù)架構(gòu)風(fēng)格的定義以及4個(gè)與微服務(wù)治理相關(guān)的技術(shù)概念,,其實(shí)也是對(duì)于當(dāng)下DevOps理念的一種體現(xiàn)
以上是來自James Lewis 和 Martin Fowler關(guān)于微服務(wù)架構(gòu)的定義,。歸納起來,,有以下幾點(diǎn):
1. 整個(gè)應(yīng)用系統(tǒng)由若干個(gè)獨(dú)立運(yùn)行的服務(wù)組成
2. 服務(wù)之間有輕量級(jí)的通訊機(jī)制,,通常是REST API
3. 每個(gè)服務(wù)都有自己的業(yè)務(wù)邏輯,,并且可以單獨(dú)部署
4. 去中心化的服務(wù)管理機(jī)制
5. 每個(gè)服務(wù)可以用不同的編程語(yǔ)言實(shí)現(xiàn),,使用不同的數(shù)據(jù)存儲(chǔ)技術(shù)
在整個(gè)微服務(wù)架構(gòu)中,主角自然是一個(gè)個(gè)獨(dú)立部署,,獨(dú)立運(yùn)行的服務(wù),,而如果缺少一種管理這些服務(wù)的機(jī)制,就像這個(gè)社會(huì)突然沒有了道德法律的約束了,,整個(gè)微服務(wù)架構(gòu)也就不成體系了,。
筆者所理解的微服務(wù)架構(gòu)大致是這個(gè)樣子的:
從這張圖上可以看出,除了核心的微服務(wù)之外,,還加入了API網(wǎng)關(guān)(Gateway)和注冊(cè)發(fā)現(xiàn)中心(Registry),。但是這張圖還并不是很完美,只能算是把一些核心機(jī)制表現(xiàn)出來了,。
筆者還沒想到用什么樣的姿勢(shì)能把微服務(wù)的各個(gè)機(jī)制較為完整的表現(xiàn)在一張圖上,,還是費(fèi)一些筆墨加以敘述吧!
一,、從Gateway說起
我們可以將Gateway視為整個(gè)系統(tǒng)的Entry Point,,是具有非常重要的戰(zhàn)略意義的,從上圖中的位置可見一斑,。讓我們先考慮一個(gè)問題:
問:為什么需要Gateway,?這部分可以舍棄嗎?
答:從服務(wù)的用戶角度考慮,,沒有Gateway,,就意味著需要了解每個(gè)服務(wù)對(duì)外暴露的接口,這無疑是一個(gè)繁雜而毫無意義的工作,;從服務(wù)的管理者角度考慮,,沒有Gateway,無論是日常的開發(fā)工作,,還是日后的維護(hù)擴(kuò)展工作,都將是一個(gè)嚴(yán)峻的考驗(yàn),。
所以結(jié)論很顯然,,Gateway對(duì)于整個(gè)微服務(wù)架構(gòu)體系來說是不可或缺的。
實(shí)際上,,我們的部署策略通常是一個(gè)服務(wù)部署多個(gè)實(shí)例,,那么客戶端發(fā)送一個(gè)請(qǐng)求過來,Gateway應(yīng)該路由到哪個(gè)實(shí)例上呢,?
是時(shí)候讓Load Balance出場(chǎng)了,。
所以,如果是以上的部署策略的話,,通常是需要在Gateway和Services之間加一層Load Balance,,通過一定的轉(zhuǎn)發(fā)策略,,最終路由到其中的一個(gè)服務(wù)實(shí)例上。
我們不妨再大膽假設(shè)一下:如果有多個(gè)Gateway,,那會(huì)怎么樣,?
通常有這種考慮,是因?yàn)楸澈蟮姆?wù)數(shù)量非常多了,,一個(gè)Gateway承載不了這么大的流量,,所以才考慮多加幾個(gè)幫手,每個(gè)Gateway路由一部分服務(wù),,最后可以形成一個(gè)Gateway的集群,。
這個(gè)時(shí)候,整個(gè)架構(gòu)的復(fù)雜度又上升了一個(gè)層次,,新的問題又產(chǎn)生了,,對(duì)于這群Gateway,必須要有效的管理起來,。
簡(jiǎn)單的解決辦法就是在這群Gateway前面加一個(gè)Load Balance,,大概是這個(gè)樣子:
但是前面有多個(gè)Load Balance又該怎么辦呢?
……
這個(gè)問題還沒完沒了了,。
只能是依實(shí)際情況而定了,,這讓我想起了一句話:
在Gateway層面還有很多好玩的東西,比如做監(jiān)控,,限流什么的,。
Gateway的實(shí)現(xiàn)手段也是多樣的,NodeJs,,Zuul,,Nginx等等。
二,、如何通訊
文章開頭便提到了,,微服務(wù)之間通常以REST API形式進(jìn)行通訊。這里對(duì)REST稍作解釋,。
REST API并不是那么神秘,,REST是建立在HTTP請(qǐng)求之上的,所以REST請(qǐng)求本質(zhì)上是HTTP請(qǐng)求,。
REST是面向資源(resources)的架構(gòu),,API的每種操作都可以認(rèn)為是資源的狀態(tài)轉(zhuǎn)移。
有三個(gè)重要的概念:
l Resource:資源,,即數(shù)據(jù),。比如 goods,orders等,;
l Representational:資源的某種表現(xiàn)形式,,比如用JSON,,XML,JPEG等,;
l State Transfer:狀態(tài)變化,,通過HTTP動(dòng)詞實(shí)現(xiàn)。
當(dāng)你的技術(shù)團(tuán)隊(duì)決定使用REST架構(gòu)時(shí),,有兩個(gè)細(xì)節(jié)需要斟酌一下:
HTTP動(dòng)詞應(yīng)該選哪個(gè),?尤其是PATCH和PUT的選擇,要考慮清楚,。
資源命名規(guī)范,。REST的標(biāo)準(zhǔn)是命名都是名詞,而且是復(fù)數(shù)形式,。
既然是基于HTTP協(xié)議,,我們不得不考慮因?yàn)楦鞣N原因?qū)е乱淮握?qǐng)求失敗了的問題。
通常情況下,,我們會(huì)在系統(tǒng)中引入重試機(jī)制,。請(qǐng)求重試的策略也不盡相同,比如最大重試3次,,5秒內(nèi)重試3次,,如果多實(shí)例,還可以設(shè)置在每個(gè)實(shí)例上允許的最大重試次數(shù),。那么,,即便是把重試次數(shù)都用光了,請(qǐng)求還是無法到達(dá),,該怎么應(yīng)對(duì)呢,?
我們?cè)囍惺芤幌拢?/span>
Service-1因?yàn)槟撤N原因被迫下線了,如果沒有其他副本集的支撐,,那么路由到Service-1的所有鏈路都將會(huì)被迫中斷,。如果這種狀況不能盡快改善的話,可能在數(shù)秒內(nèi)導(dǎo)致所有應(yīng)用資源(線程,,隊(duì)列等)被耗盡,,整條請(qǐng)求鏈路將會(huì)被拖累,甚至導(dǎo)致整個(gè)系統(tǒng)癱瘓,。
這就是經(jīng)典的雪崩效應(yīng)(Cascading
Failure)。
此時(shí),,需要在通向各個(gè)服務(wù)的鏈路上安插一個(gè)開關(guān),,就像家里面的空氣開關(guān),一旦遇到緊急情況,,就會(huì)自動(dòng)斷開鏈路,,不至于影響到其他的鏈路,,進(jìn)而保證整個(gè)系統(tǒng)的正常運(yùn)行。
這就是所謂的熔斷機(jī)制(Circuit Breaker),。這個(gè)機(jī)制并不是IT界獨(dú)有的,,在金融界也是赫赫有名的。這些概念都是來源于生活,,提煉出一個(gè)又一個(gè)人類生存的法則,。
還有一個(gè)與熔斷相近的概念:降級(jí)。
在微服務(wù)領(lǐng)域,,「服務(wù)熔斷」和「服務(wù)降級(jí)」確實(shí)會(huì)對(duì)初學(xué)者造成一定的困惑,。
其實(shí)仔細(xì)推敲一下,也不難理解,。
兩者都是出于對(duì)系統(tǒng)穩(wěn)定性和安全性考慮,,并且達(dá)到了一定的條件才會(huì)觸發(fā)。不同的是觸發(fā)的方式和場(chǎng)景是不一樣的,。
服務(wù)熔斷一般是系統(tǒng)根據(jù)預(yù)設(shè)的條件自動(dòng)觸發(fā)的,,比如連續(xù)請(qǐng)求失敗10次,為了避免造成進(jìn)一步的損失,,系統(tǒng)直接讓對(duì)應(yīng)的服務(wù)下線,。此時(shí),開關(guān)相當(dāng)于出于Closed狀態(tài),,等到服務(wù)重新上線,,建立了心跳連接后,開關(guān)狀態(tài)就轉(zhuǎn)換成Open狀態(tài),。
服務(wù)降級(jí)的觸發(fā)可以是人工干預(yù)的,,也可以是系統(tǒng)自動(dòng)觸發(fā)的。這時(shí)候,,服務(wù)之間是有層次之分的,,被降級(jí)的某些服務(wù)的可用性降低了,用戶在使用的時(shí)候,,有時(shí)候會(huì)得不到預(yù)期的結(jié)果,。
這兩者之間也有一定的關(guān)系,總結(jié)起來就是:
由于長(zhǎng)期的服務(wù)降級(jí),,導(dǎo)致了永久的服務(wù)熔斷,。
如果還不是很清楚,可以看我附上的第4個(gè)參考文獻(xiàn),。
三,、再談Registry
在高度自治的微服務(wù)架構(gòu)中,注冊(cè)與發(fā)現(xiàn)中心(Registry)這個(gè)角色是十分重要的。
Registry的作用就好比是一本書的目錄,,通過目錄可以找到相應(yīng)的內(nèi)容,。Registry裝載的就是微服務(wù)的元數(shù)據(jù)。當(dāng)一個(gè)服務(wù)嘗試去調(diào)用另一個(gè)服務(wù),,就會(huì)去Registry上請(qǐng)求一份元數(shù)據(jù),,找到被調(diào)用的服務(wù)在什么地方。
這樣看來,,每個(gè)服務(wù)都可以看作是一個(gè)Registry
Client,,Gateway也不例外。
Registry如此重要,,通常我會(huì)希望其高可用,,所以至少會(huì)為其多部署一個(gè)副本,每個(gè)Registry都持有一份完整的服務(wù)元數(shù)據(jù),。
此處不得再次提及文章開頭說到的去中心化的服務(wù)管理機(jī)制,。
在SOA架構(gòu)體系中,ESB是整個(gè)系統(tǒng)的中心,,如果ESB癱瘓了,,那么也就意味著整個(gè)系統(tǒng)就不可用了。
微服務(wù)與SOA的一個(gè)重大區(qū)別就是去ESB,,也就是去中心化,。也就意味著,當(dāng)Registry全部下線了,,各個(gè)服務(wù)仍能正常運(yùn)行,。其中,做的一個(gè)主要的工作就是,,每個(gè)Registry Client都緩存一份服務(wù)的元數(shù)據(jù)信息,,以備不時(shí)之需。
在分布式系統(tǒng)領(lǐng)域有個(gè)著名的CAP定理:
l C——數(shù)據(jù)一致性(Consistency)
l A——服務(wù)可用性(Available)
l P——服務(wù)對(duì)網(wǎng)絡(luò)分區(qū)故障的容錯(cuò)性(Partition tolerance)
這三個(gè)特性在任何分布式系統(tǒng)中不能同時(shí)滿足,,最多同時(shí)滿足兩個(gè),。架構(gòu)師不要將精力浪費(fèi)在如何設(shè)計(jì)能滿足三者的完美分布式系統(tǒng),而是應(yīng)該進(jìn)行取舍,。
在SOA架構(gòu)體系中,,ESB優(yōu)先滿足的是一致性,以zookeeper為例,,在使用Zookeeper獲取服務(wù)列表時(shí),,如果zookeeper正在選主,或者zookeeper集群中半數(shù)以上機(jī)器不可用,,那么將就無法獲得數(shù)據(jù)了,,所以說,,zookeeper不能保證服務(wù)可用性,滿足的是CP兩個(gè)條件,。
但是就服務(wù)發(fā)現(xiàn)這個(gè)場(chǎng)景來說,如果數(shù)據(jù)達(dá)不到一致性的要求,,并不會(huì)造成什么災(zāi)難性后果,,我們應(yīng)該更看重的是服務(wù)的可用性,從這個(gè)方面考慮,,AP是勝過CP的,。這也是Spring
Cloud Netflix在設(shè)計(jì)Eureka時(shí)遵守AP原則的原因。
四,、淺談鏈路跟蹤
這是本文的最后一部分內(nèi)容,,也算是微服務(wù)領(lǐng)域的一個(gè)「高級(jí)話題」。
在筆者看來,,調(diào)用鏈的跟蹤算是一種運(yùn)維手段,,要做好這一部分的工作,并不是那么簡(jiǎn)單,。
以往在單體應(yīng)用環(huán)境下,,所有的業(yè)務(wù)都在同一個(gè)服務(wù)器上,如果服務(wù)器出現(xiàn)錯(cuò)誤和異常,,我們只要盯住一個(gè)點(diǎn),,就可以快速定位和處理問題。
而微服務(wù)的架構(gòu)已經(jīng)決定了系統(tǒng)是在分布式環(huán)境下完成一系列的業(yè)務(wù)活動(dòng)的,,此時(shí),,對(duì)于問題的追蹤和定位會(huì)變得比較麻煩。
鏈路跟蹤工具常見于一些中大型的系統(tǒng),,因?yàn)槿巳馀挪閱栴}的效率實(shí)在是太低了,。
即便不是排查問題,若PM想跟蹤一下業(yè)務(wù)流,,也會(huì)逐漸變得不可能了,。