微服務(wù)在過(guò)去幾年一直是一個(gè)非常熱門(mén)的話題(附錄1)。何為“微服務(wù)的瘋狂”,舉個(gè)例子:
眾所周知,Netflix在DevOps上的表現(xiàn)非常棒。Netfix可以做微服務(wù)。因此:如果我做微服務(wù),我也將非常擅長(zhǎng)DevOps。
很多情況下,我們盲目的投入巨大的努力來(lái)接入微服務(wù)模式,然而往往卻很少去考慮接入的成本和收益能否有效的幫我們解決當(dāng)前我們正面臨的痛點(diǎn)。
下面,我將詳細(xì)描述微服務(wù)是什么,以及為什么這種模式這么吸引人,最后再聊一聊一些微服務(wù)正面臨的一些關(guān)鍵挑戰(zhàn)。
如果你正在考慮微服務(wù)是否適合你,是否能幫你解決當(dāng)前面臨的問(wèn)題?那繼續(xù)往下看,我會(huì)用一系列簡(jiǎn)單的問(wèn)題來(lái)幫你走出你的困惑。這一系列“問(wèn)題”在文章的最后。
什么是微服務(wù),為什么微服務(wù)如此受歡迎?
來(lái)來(lái)來(lái),老司機(jī)帶你從基礎(chǔ)走一波。一個(gè)例子:下面這張圖是一個(gè)假想的視頻共享平臺(tái)的實(shí)現(xiàn)方式,左側(cè)是用一個(gè)“整體服務(wù)”來(lái)實(shí)現(xiàn),右側(cè)是多個(gè)微服務(wù)的形式來(lái)實(shí)現(xiàn):
兩種系統(tǒng)設(shè)計(jì)的區(qū)別在于左側(cè)是一個(gè)整體的大而全的服務(wù)。右側(cè)是一組小而多,但每個(gè)都是一個(gè)具體的服務(wù),每個(gè)服務(wù)都有特定的角色。
當(dāng)從系統(tǒng)細(xì)節(jié)層面來(lái)繪制圖表時(shí),很容易看出微服務(wù)的很多潛在的好處,簡(jiǎn)單從幾個(gè)方面來(lái)說(shuō)一下:
獨(dú)立開(kāi)發(fā):小型獨(dú)立組件可由小型獨(dú)立團(tuán)隊(duì)構(gòu)建。一個(gè)小組可以改變“Upload”服務(wù),而不會(huì)干擾“Transcode”服務(wù),甚至都不需要知道這個(gè)服務(wù)。了解組件的時(shí)間大大減少,開(kāi)發(fā)新功能也更容易。
獨(dú)立部署:每個(gè)單獨(dú)的組件都可以獨(dú)立部署。這樣可以以更快的速度和更少的風(fēng)險(xiǎn)發(fā)布新功能。比如:“Streaming”組件的修復(fù)或功能可以部署,而不需要部署其他組件。
獨(dú)立的可伸縮性:每個(gè)組件可以彼此獨(dú)立地進(jìn)行縮放。在需求多并發(fā)同時(shí)需要發(fā)布新的版本時(shí),可以放大“Download”組件,以處理增加的負(fù)載,而不必?cái)U(kuò)大每個(gè)組件,這使得彈性縮放更加可行并降低了成本。
可重用性:組件實(shí)現(xiàn)一個(gè)小的,特定的功能。這意味著它們可以更容易地適用于其他系統(tǒng)、服務(wù)或產(chǎn)品?!癟ranscode”組件可以被其他業(yè)務(wù)部門(mén)使用,甚至可以變成一個(gè)新的業(yè)務(wù),或者為其他組提供Transcode服務(wù)。
從細(xì)節(jié)層面上來(lái)看,微服務(wù)模型較之于整體模型的好處顯而易見(jiàn)。但是問(wèn)題來(lái)了,如果真的是這樣的話 – 為什么微服務(wù)模式最近幾年才流行?我一生都快走完了(尷尬,貌似暴露年齡了),它才出現(xiàn)?
如果這微服務(wù)這么好,為什么之前大家沒(méi)有這么做呢?
這個(gè)問(wèn)題有兩種答案。其一是,它強(qiáng)依賴(lài)我們最好的技術(shù)能力,另一個(gè)是最近的技術(shù)進(jìn)步,促使我們能夠把它帶到一個(gè)新的高度。
當(dāng)我開(kāi)始寫(xiě)軟文來(lái)回答這個(gè)問(wèn)題的時(shí)候,發(fā)現(xiàn)這將會(huì)是一個(gè)很長(zhǎng)的描述,所以從實(shí)際的角度出發(fā),我將把它拆成兩篇文章,稍后再發(fā)表2。第1篇文章,我將跳過(guò)一些內(nèi)容,比如:從單個(gè)程序到多個(gè)程序的過(guò)程,忽略ESB和面向服務(wù)的體系結(jié)構(gòu),組件設(shè)計(jì)和有限的上下文等等。
感興趣的朋友可以稍后閱讀更多關(guān)于journey的信息。盡管,在很多方面我們已經(jīng)這樣做了一段時(shí)間,但是隨著最近容器技術(shù)(特別是Docker)和編排技術(shù)(如Kubernetes、Mesos、Consul等等)的普及,從技術(shù)的角度來(lái)看,微服務(wù)模式變得更加可行。
因此,如果我們想要實(shí)施微服務(wù)的話,我們最好仔細(xì)慎重考慮是否真的需要。我們已經(jīng)看到了高大上的“理論效益”,但值得一提的是,未知的挑戰(zhàn)又是什么?
微服務(wù)有什么問(wèn)題呢?
微服務(wù)如此強(qiáng)大、完美,哪里還會(huì)有什么挑戰(zhàn)?這是目前我見(jiàn)過(guò)的最大的問(wèn)題。
開(kāi)發(fā)的復(fù)雜性增加
對(duì)于開(kāi)發(fā)者來(lái)說(shuō)事情會(huì)變得更加困難。在開(kāi)發(fā)人員想要在遠(yuǎn)程工作的情況下,或者可能跨越許多服務(wù)的功能的情況下,開(kāi)發(fā)人員必須在他們的機(jī)器上運(yùn)行它們,或者連接到它們。這通常比簡(jiǎn)單地運(yùn)行單個(gè)程序更復(fù)雜。
這個(gè)挑戰(zhàn)可以通過(guò)工具(附錄3)得到部分緩解,但隨著構(gòu)成系統(tǒng)的服務(wù)數(shù)量的增加,開(kāi)發(fā)人員在整個(gè)系統(tǒng)運(yùn)行時(shí)面臨的挑戰(zhàn)也會(huì)越來(lái)越多。
運(yùn)維的復(fù)雜性增加
對(duì)于不開(kāi)發(fā)服務(wù)但維護(hù)服務(wù)的團(tuán)隊(duì)來(lái)說(shuō),潛在的復(fù)雜性是一個(gè)巨大的挑戰(zhàn)。他們不是管理幾個(gè)正在運(yùn)行的服務(wù),而是管理數(shù)十,數(shù)百或數(shù)千個(gè)正在運(yùn)行的服務(wù)。服務(wù)越多,溝通越多,潛在的失敗風(fēng)險(xiǎn)就越多。
DevOps的復(fù)雜性增加
閱讀以上兩點(diǎn),可能會(huì)發(fā)現(xiàn)運(yùn)維和開(kāi)發(fā)是分開(kāi)處理的,尤其是考慮到DevOps作為一種實(shí)踐的普及(我是DevOps的真愛(ài)粉)。DevOps難道不能緩解這一痛點(diǎn)?
目前面臨的挑戰(zhàn)是,許多組織仍然依靠獨(dú)立的開(kāi)發(fā)和運(yùn)營(yíng)團(tuán)隊(duì)來(lái)運(yùn)行 – 而一些組織則更傾向于采用微服務(wù)。
對(duì)于已經(jīng)采用了DevOps的組織來(lái)說(shuō),這仍然很難。既是開(kāi)發(fā)者又是運(yùn)維者,已經(jīng)非常艱難(但是要建立好的軟件卻很關(guān)鍵),但是也必須了解容器編排系統(tǒng)的細(xì)微差別,特別是快速發(fā)展的系統(tǒng)是非常困難的。這使我想到了下一點(diǎn)。
沒(méi)專(zhuān)業(yè)知識(shí)?別玩微服務(wù)
當(dāng)很多事情都由專(zhuān)家完成時(shí),最終的結(jié)果也將是極好的。但想象一下,一個(gè)機(jī)構(gòu)或組織使用單一的整體系統(tǒng)并不總是可以很順利的運(yùn)行。那做些什么能夠來(lái)改善并讓這些事情變得更好呢?通過(guò)增加系統(tǒng)服務(wù)的數(shù)量?但同時(shí)也會(huì)增加運(yùn)行的復(fù)雜性。
不可否認(rèn),通過(guò)有效的自動(dòng)化、監(jiān)控和編排等,這一切都可以改善。但挑戰(zhàn)很少是技術(shù)本身——真正的挑戰(zhàn)其實(shí)是找到能夠有效使用技術(shù)的人。恰恰目前這些技能需求非常高,可能很難找到符合你需求的人。
現(xiàn)實(shí)世界的系統(tǒng)往往界限不清
在我們用來(lái)描述微服務(wù)的好處的所有例子中,我們都談到了獨(dú)立的組件。但是在很多情況下,組件并不是完全獨(dú)立的。正所謂“紙上得來(lái)終覺(jué)淺,絕知此事要躬行”,某些領(lǐng)域可能看起來(lái)有限,但是當(dāng)你陷入冗繁的細(xì)節(jié)時(shí),你會(huì)發(fā)現(xiàn)他們比你預(yù)期的更具挑戰(zhàn)性。
這是事情變得非常復(fù)雜的地方。事實(shí)上,如果你的邊界沒(méi)有明確定義,那么會(huì)發(fā)生什么情況呢?即使理論上的服務(wù)可以單獨(dú)部署,你會(huì)發(fā)現(xiàn),由于服務(wù)之間的相互依賴(lài)關(guān)系,你必須部署一系列微服務(wù)作為一個(gè)組服務(wù)。
這意味著你需要管理協(xié)同工作的版本,這些版本的服務(wù)在聯(lián)調(diào)時(shí)會(huì)經(jīng)過(guò)驗(yàn)證和測(cè)試,你實(shí)際上沒(méi)有可獨(dú)立部署的系統(tǒng),因?yàn)橐渴鹦鹿δ?,你需要仔?xì)編排許多服務(wù)的同時(shí)去部署。
狀態(tài)的復(fù)雜性往往被忽略
在前面的例子中,我提到一個(gè)功能部署可能需要同時(shí)部署多個(gè)版本的許多服務(wù)。假設(shè)合理的部署技術(shù)將緩解這種情況,例如藍(lán)/綠部署(大多數(shù)服務(wù)編排平臺(tái)很少原生支持這種功能),或者并行運(yùn)行多個(gè)版本的服務(wù),以及決定使用哪個(gè)版本的消費(fèi)通道。
如果服務(wù)是無(wú)狀態(tài)的,這些技術(shù)可以緩解大量的挑戰(zhàn)。但是無(wú)國(guó)界的服務(wù)非常坦率,容易處理。事實(shí)上,如果你有無(wú)狀態(tài)的服務(wù),那么我會(huì)傾向于考慮跳過(guò)微服務(wù),并考慮使用無(wú)服務(wù)器模型。
實(shí)際上,許多服務(wù)需要管理。我們的視頻共享平臺(tái)的一個(gè)例子可能是訂閱服務(wù)。訂閱服務(wù)的新版本可以以不同形狀將數(shù)據(jù)存儲(chǔ)在訂閱數(shù)據(jù)庫(kù)中。如果你同時(shí)運(yùn)行這兩個(gè)服務(wù),則一次運(yùn)行兩個(gè)模式的系統(tǒng)。如果您進(jìn)行了藍(lán)/綠部署,而其他服務(wù)依賴(lài)于新形狀中的數(shù)據(jù),則必須同時(shí)更新這些數(shù)據(jù),并且如果訂閱服務(wù)部署失敗并回滾,則可能還需要使用級(jí)聯(lián)回滾。
同樣,可能你會(huì)說(shuō),在NoSQL數(shù)據(jù)庫(kù)中,這些架構(gòu)問(wèn)題會(huì)消失,但事實(shí)并非如此。不強(qiáng)制執(zhí)行模式的數(shù)據(jù)庫(kù)無(wú)法連接無(wú)模式系統(tǒng)——這意味著模式往往是在應(yīng)用程序級(jí)而不是數(shù)據(jù)庫(kù)級(jí)進(jìn)行管理的。理解數(shù)據(jù)結(jié)構(gòu)以及如何流轉(zhuǎn)的根本性問(wèn)題并不能被消除。
溝通的復(fù)雜性往往被忽略
當(dāng)你建立一個(gè)相互依賴(lài)的大型服務(wù)網(wǎng)絡(luò)時(shí),可能會(huì)有很多的服務(wù)間通信。這導(dǎo)致了一些挑戰(zhàn)。首先,有很多事情可能會(huì)失敗。我們必須假設(shè)網(wǎng)絡(luò)call可能會(huì)失敗,這意味著當(dāng)一個(gè)服務(wù)call另一個(gè)服務(wù)時(shí),它應(yīng)該至少需要重試幾次?,F(xiàn)在當(dāng)一個(gè)服務(wù)可能調(diào)用很多服務(wù)時(shí),我們最終會(huì)遇到一個(gè)更加復(fù)雜的情況。
用戶(hù)上傳視頻共享服務(wù)中的視頻。我們可能需要運(yùn)行upload服務(wù),將數(shù)據(jù)傳遞到transcode服務(wù),更新訂閱,更新建議等等。所有這些調(diào)用都需要一定程度的協(xié)調(diào),如果過(guò)程中任何部分失敗,我們都需要重試。
這個(gè)重試邏輯可能難以管理。試圖同步做事往往會(huì)導(dǎo)致站不住腳,失敗點(diǎn)太多。在這種情況下,更可靠的解決方案是使用異步模式來(lái)處理通信。這里面臨的挑戰(zhàn)是異步模式本身往往會(huì)使系統(tǒng)具有狀態(tài)性。如前所述,分布式狀態(tài)系統(tǒng)和有狀態(tài)系統(tǒng)很難處理。
當(dāng)一個(gè)微服務(wù)系統(tǒng)使用消息隊(duì)列進(jìn)行服務(wù)內(nèi)通信時(shí),你基本上需要有一個(gè)大的數(shù)據(jù)庫(kù)(消息隊(duì)列或代理)將這些服務(wù)組合在一起。同樣,雖然起初看起來(lái)似乎不是一個(gè)挑戰(zhàn),但你懂的——出來(lái)混遲早都是要還的。X版本的服務(wù)可能會(huì)寫(xiě)入某種格式的消息,當(dāng)發(fā)送服務(wù)更改發(fā)送的消息的詳細(xì)信息時(shí),依賴(lài)于該消息的服務(wù)也將需要更新。
當(dāng)然,可以有許多不同格式的消息處理服務(wù),但這很難管理。現(xiàn)在,在部署新版本的服務(wù)時(shí),你可能會(huì)有兩個(gè)不同版本的服務(wù)嘗試處理來(lái)自同一隊(duì)列的消息,甚至可能是由不同版本的發(fā)送服務(wù)發(fā)送的消息。這可能會(huì)導(dǎo)致復(fù)雜的邊緣情況。為了避免這些邊緣情況,僅允許特定版本的消息存在可能更容易,這意味著你需要將一組服務(wù)的版本作為一個(gè)整體來(lái)部署,以確保先前版本的消息被正確地屏蔽。
這再次突出表明,獨(dú)立部署的想法可能不會(huì)像預(yù)期的那樣順利。
版本控制可能很難
為了緩解前面提到的挑戰(zhàn),版本控制需要非常謹(jǐn)慎的管理。再說(shuō)一下,看起來(lái)貌似有一種趨勢(shì)——假設(shè)遵循像Semver[4]這樣的標(biāo)準(zhǔn)或許將可以解決這個(gè)問(wèn)題。然而事實(shí)并非完全如此。雖然Semver是一個(gè)合理的使用慣例,但是你仍然需要持續(xù)的跟蹤那些可以一起工作的服務(wù)和API的版本。
這可能會(huì)使事情變得非常具有挑戰(zhàn)性,并且很多時(shí)候可能會(huì)讓你感到困惑——哪些版本的服務(wù)可以一起正常工作。
在軟件系統(tǒng)中管理依賴(lài)關(guān)系是非常困難的,無(wú)論是節(jié)點(diǎn)模塊,Java模塊,C庫(kù)還是其他。當(dāng)一個(gè)實(shí)體消費(fèi)獨(dú)立組件之間的沖突的挑戰(zhàn)是很難處理的。
當(dāng)依賴(lài)關(guān)系是靜態(tài)的時(shí)候,這些挑戰(zhàn)是很難處理的。雖然可以進(jìn)行修補(bǔ)、更新、編輯等,但是如果依賴(lài)關(guān)系本身是實(shí)時(shí)服務(wù),那么你可能根本無(wú)法更新它們——你可能需要運(yùn)行許多版本(上面已經(jīng)描述過(guò)這些挑戰(zhàn)),或者直到整個(gè)系統(tǒng)得到修復(fù)。
分布式事務(wù)
在需要跨操作交易完整性的情況下,微服務(wù)可能會(huì)非常痛苦。分布式狀態(tài)很難處理,很多小的單位可能會(huì)很難進(jìn)行編排交易。
試圖通過(guò)使操作冪等性,提供重試機(jī)制等來(lái)避免這個(gè)問(wèn)題可能聽(tīng)起來(lái)很誘人,而且在很多情況下確實(shí)可能起作用。但可能有一些場(chǎng)景,你只需要一個(gè)事務(wù)失敗或成功,而不想它處于中間狀態(tài)。解決這個(gè)問(wèn)題或者在微服務(wù)模型中實(shí)現(xiàn)它的代價(jià)可能是非常高的。
微服務(wù)可能是變相的龐然大物
顯然,單獨(dú)的服務(wù)和組件可能是孤立部署的,但是在大多數(shù)情況下,你將不得不運(yùn)行某種編排平臺(tái),比如Kubernetes。如果你使用的是托管服務(wù),例如Google的GKE 5或Amazon的EKS 6,則會(huì)為你處理管理群集的大量復(fù)雜性。
但是,如果你要自己管理集群,那么你正在管理一個(gè)龐大而復(fù)雜的關(guān)鍵任務(wù)系統(tǒng)。盡管單個(gè)服務(wù)可能具有前面所述的所有優(yōu)點(diǎn),但你需要非常小心地管理群集。這個(gè)系統(tǒng)的部署可能很難,更新可能很難,故障轉(zhuǎn)移可能也很困難等等。
在許多情況下,總體收益仍然存在,但重要的是不要輕視或低估管理另一個(gè)龐大而復(fù)雜系統(tǒng)的額外復(fù)雜性。托管服務(wù)可能會(huì)有所幫助,但在很多情況下,這些服務(wù)都是新興的不穩(wěn)定的(例如,Amazon EKS直到在2017年底才宣布)——誰(shuí)用誰(shuí)知道。
微服務(wù)瘋狂之死!
只有通過(guò)仔細(xì)考慮才能避免為微服務(wù)而微服務(wù)的瘋狂。為了幫助解決這個(gè)問(wèn)題,我想了一些你可能想問(wèn)自己的問(wèn)題,以及可能的答案:
你可以在這里下載PDF副本:https://github.com/dwmkerr/blog/raw/master/2018/microservice-madness/images/microservice-questions.pdf
最后的想法:不要混淆微服務(wù)和架構(gòu)
我故意避免這篇文章中的“a”字。但是,我的朋友Zoltan在校對(duì)這篇文章的時(shí)候提到了一個(gè)很好的觀點(diǎn)。
沒(méi)有微服務(wù)體系結(jié)構(gòu)。微服務(wù)只是組件的另一種模式或?qū)崿F(xiàn),無(wú)他。無(wú)論是否存在于系統(tǒng)中,都不意味著系統(tǒng)的體系結(jié)構(gòu)得到了解決。
微服務(wù)在許多方面與打包和運(yùn)維的技術(shù)過(guò)程有關(guān),而不是系統(tǒng)的固有設(shè)計(jì)。組件的適當(dāng)邊界仍然是工程系統(tǒng)中最重要的挑戰(zhàn)之一。
無(wú)論你的服務(wù)是否在Docker容器中,你總是需要仔細(xì)考慮如何將系統(tǒng)放在一起。沒(méi)有唯一的答案,只有更多的選擇。
我希望你看完這篇文章覺(jué)得有趣!一如既往,如果你有任何疑問(wèn)或想法,請(qǐng)?jiān)谙旅嬖u(píng)論即可。
附錄:進(jìn)一步閱讀
以下鏈接可能有用:
- Martin Fowler – Bounded Context – 馬丁的文章是很棒的,我極力推薦這一篇。
- Martin Fowler – 微服務(wù) – 這篇著重介紹微服務(wù)的模式。
- 微服務(wù) – 好還是壞? – 閱讀這篇文章,你將了解Bj?rnFrantzén對(duì)微服務(wù)的看法。
- 什么時(shí)候不要做微服務(wù) – 來(lái)自于Christian Posta的話題中的優(yōu)秀帖子
- Dave Kerr -微服務(wù)整體架構(gòu) – 微服務(wù)世界中CI / CD和DevOps的實(shí)用技巧 – 最近一次關(guān)于微服務(wù)的devops會(huì)議演示。
如果你愿意,請(qǐng)分享你認(rèn)為值得閱讀或觀看的話題的任何東東!
參考
- https://trends.google.com/tren … rvice
- 如果你不想錯(cuò)過(guò)這篇文章,你可以訂閱RSS源,或者在LinkedIn或Twitter上關(guān)注我。
- Docker Compose是一個(gè)很好的解決方案,F(xiàn)uge非常聰明,在MiniKube這種情況下,也可以選擇在本地運(yùn)行編排。
- https://semver.org/
- 谷歌Kubernetes引擎,一個(gè)從谷歌云平臺(tái)誕生Kubernetes托管服務(wù):https://cloud.google.com/kubernetes-engine/
- 亞馬遜彈性容器服務(wù)(已支持Kubernetes),一個(gè)從亞馬遜Web服務(wù)誕生的Kubernetes托管服務(wù):https://aws.amazon.com/eks/
本站部分文章源于互聯(lián)網(wǎng),本著傳播知識(shí)、有益學(xué)習(xí)和研究的目的進(jìn)行的轉(zhuǎn)載,為網(wǎng)友免費(fèi)提供。如有著作權(quán)人或出版方提出異議,本站將立即刪除。如果您對(duì)文章轉(zhuǎn)載有任何疑問(wèn)請(qǐng)告之我們,以便我們及時(shí)糾正。PS:推薦一個(gè)微信公眾號(hào): askHarries 或者qq群:474807195,里面會(huì)分享一些資深架構(gòu)師錄制的視頻錄像:有Spring,MyBatis,Netty源碼分析,高并發(fā)、高性能、分布式、微服務(wù)架構(gòu)的原理,JVM性能優(yōu)化這些成為架構(gòu)師必備的知識(shí)體系。還能領(lǐng)取免費(fèi)的學(xué)習(xí)資源,目前受益良多
轉(zhuǎn)載請(qǐng)注明原文出處:Harries Blog? ? 請(qǐng)不要在“微服務(wù)”的狂熱中迷失自我!