解決與平衡分布式系統(tǒng)中微服務(wù)的復(fù)雜度
點(diǎn)擊上方“服務(wù)端思維”,選擇“設(shè)為星標(biāo)”
回復(fù)”669“獲取獨(dú)家整理的精選資料集
回復(fù)”加群“加入全國服務(wù)端高端社群「后端圈」
原文標(biāo)題: Untangling Microservices, or Balancing Complexity in Distributed Systems
原文地址[1]
翻譯:祝坤榮
微服務(wù)的蜜月期已經(jīng)結(jié)束了。Uber正在將成千記的微服務(wù)重構(gòu)成一個更加可管理的方案[1];Kelsey Hightower正在預(yù)測單體架構(gòu)將是未來[2];Sam Newman甚至聲明微服務(wù)不應(yīng)該是第一選擇,而應(yīng)該是最后一個選擇[3]。
這是怎么回事?盡管微服務(wù)承諾了簡單和靈活,為什么這么多的項目變得難以維護(hù)?或者難道最終單體架構(gòu)更好?
在這篇文章中,我想要討論這些問題。你會看到一些將微服務(wù)編程一團(tuán)分布式大泥球的常見設(shè)計問題 - 當(dāng)然,也會看到如何避免他們。
但最開始,讓我們先了解下什么是單體架構(gòu)。
單體架構(gòu)
微服務(wù)一直是被認(rèn)為是單體應(yīng)用代碼的解決方案。但是單體應(yīng)用是不是一個問題呢?根據(jù)維基百科的定義[4],一個單體應(yīng)用是自包含且與其他計算應(yīng)用獨(dú)立的。與哪些其他應(yīng)用獨(dú)立呢?這不是我們在設(shè)計微服務(wù)時追求的嗎?David Heinemeier Hansson[5]指出了單體應(yīng)用的缺陷。他
因此,微服務(wù)不是“修復(fù)”單體應(yīng)用。微服務(wù)需要解決的真正問題是交付業(yè)務(wù)目標(biāo)的無力。一般,團(tuán)隊是由于指數(shù)級增長的 - 或更糟的不可預(yù)測性 - 進(jìn)行變更的成本才交付不了業(yè)務(wù)目標(biāo)的。換一句話說,系統(tǒng)不能滿足業(yè)務(wù)的需要。不可控的變更成本不是單體應(yīng)用的特性,而是大泥球的特性[6]:
大泥球是雜亂的結(jié)構(gòu),無序,泥濘,纏在一起的電線和膠帶,面條代碼的叢林。系統(tǒng)顯示出無節(jié)制增長,重復(fù),臨時修復(fù)的明顯跡象。系統(tǒng)中混亂的將信息在很多極長鏈路的系統(tǒng)部分中共享,這表示大部分重要信息都變成了全局的或被重復(fù)復(fù)制的。
對大泥球的復(fù)雜性的修改和進(jìn)化可以由于多個原因引起:協(xié)調(diào)眾多團(tuán)隊的工作,非功能性需求的沖突,或一個復(fù)雜的業(yè)務(wù)域。無論怎樣,我們經(jīng)常試圖將這種復(fù)雜問題分解成微服務(wù)來解決。
微什么?
文字“微服務(wù)”指明了服務(wù)的一部分可以被度量并且它的價值應(yīng)該是最小化的。但微服務(wù)到底意味著什么?我們看下一些常見的用法。
微團(tuán)隊
第一個工作在服務(wù)上的團(tuán)隊大小。而這個尺度可以按披薩來度量。你沒聽錯。他們說如果工作在服務(wù)上的團(tuán)隊可以被2個披薩喂飽, 那么這就是微服務(wù)。我發(fā)現(xiàn)這很有啟發(fā),我曾經(jīng)做一個項目而團(tuán)隊可以被一個披薩喂飽... 而我敢對任何人說這團(tuán)大泥球是微服務(wù)。
微代碼庫
另一種廣泛使用的方法時基于它的代碼庫來設(shè)計微服務(wù)。有些人將這個概念發(fā)揮到了極致,將服務(wù)的大小限制到了某些確定的代碼行數(shù)。就是說,可以構(gòu)成一個微服務(wù)的確切代碼行數(shù)還沒被找到。當(dāng)這個軟件架構(gòu)的圣杯被發(fā)現(xiàn),我們會進(jìn)入下一個問題 - 構(gòu)建微服務(wù)團(tuán)建的編輯器寬度是多少?
有個更嚴(yán)重的問題,這個方法一個沒那么極端的版本更流行。代碼庫的大小常被用來決定它是否是一個微服務(wù)。
某些時候,這個方法管用。更小的代碼庫,更小的業(yè)務(wù)域。因此,這容易理解,實(shí)現(xiàn),發(fā)展。而且,更小的代碼庫不太可能變成一個大泥球 - 如果發(fā)生了,也比較容易重構(gòu)。
不幸的是,前面提到的簡單只是一個錯覺。當(dāng)我們開始基于服務(wù)本身來評估服務(wù)的設(shè)計時,我們忽略了系統(tǒng)設(shè)計的核心部分。我們忘記了系統(tǒng)自己,服務(wù)作為系統(tǒng)的組成。
“有很多有用和有啟發(fā)性的方法來定義一個服務(wù)的邊界。大小是最不重要的部分。” - Nick Tune
我們開發(fā)系統(tǒng)!
我們開發(fā)系統(tǒng),而不是服務(wù)的集合。我們使用基于微服務(wù)的架構(gòu)來優(yōu)化系統(tǒng)的設(shè)計,而不是設(shè)計獨(dú)立的服務(wù)。無論別人怎么說,微服務(wù)不能,也永遠(yuǎn)不會完全解耦,和獨(dú)立。 你不能用完全獨(dú)立的組件來打造系統(tǒng)! 現(xiàn)在我們看下“系統(tǒng)”的定義[7]:
1.一組連接在一起并可一起操作的物件或設(shè)備2.一組為了一個特定目的一起使用的計算機(jī)設(shè)備或程序
服務(wù)會與其他服務(wù)進(jìn)行不斷交互來形成系統(tǒng)。如果你通過優(yōu)化服務(wù)來設(shè)計一個系統(tǒng),卻忽略了他們之間的交互,最終你可能是這樣的結(jié)局:

這些“微服務(wù)”可能自身很簡單,但系統(tǒng)卻變成了復(fù)雜性的地獄!
所以我們?nèi)绾尾恢皇翘幚砹朔?wù)的復(fù)雜性,而是也考慮了整個系統(tǒng)的復(fù)雜性來進(jìn)行微服務(wù)設(shè)計呢?
這是個困難的問題,但幸運(yùn)的是,在很早以前就有答案。
系統(tǒng)視角的復(fù)雜性
四十年前,還沒有云計算,沒有全球規(guī)模的需求,不需要每11.7秒部署一次系統(tǒng)。但工程師仍然需要控制系統(tǒng)復(fù)雜度。盡管這些工具與現(xiàn)在不一樣,但挑戰(zhàn) - 更重要的是, 解決方案 - 都是類似的,也可以被用于基于微服務(wù)設(shè)計的系統(tǒng)。
在他的書里,“組合/結(jié)構(gòu)設(shè)計”[8],Glenford J. Myers討論了如何用結(jié)構(gòu)化的過程代碼來降低復(fù)雜度。在書的第一頁,他寫到:
關(guān)于復(fù)雜性的主題中有比簡單的嘗試最小化程序中一部分的本地復(fù)雜度更重要的事。一個更重要的復(fù)雜度類型是全局復(fù)雜度:程序或系統(tǒng)的全局結(jié)構(gòu)的復(fù)雜度(比如,程序主要部分的關(guān)聯(lián)或獨(dú)立程度)。
在我們的語境里,本地復(fù)雜度就是每個獨(dú)立微服務(wù)的復(fù)雜度,而全局復(fù)雜度是整個系統(tǒng)的復(fù)雜度。本地復(fù)雜度依賴于一個服務(wù)的實(shí)現(xiàn)部分;全局復(fù)雜度是被服務(wù)間的交互和依賴所定義的。
所以哪一個復(fù)雜度更重要 - 本地還是全局?讓我們看看當(dāng)只有一種復(fù)雜度被關(guān)心時的情況。
要將全局復(fù)雜度降到最小實(shí)際非常簡單。我們只要評估下任何系統(tǒng)組件間的交互 - 即,將所有功能在一個單體服務(wù)中實(shí)現(xiàn)。就像我們早前看到的,這個策略在某些特定場景是有用的。而在其他場景,它會導(dǎo)致恐怖的大泥球 - 可能是最高級別的本地復(fù)雜度。
從另一方面,我們很清楚當(dāng)你只優(yōu)化本地復(fù)雜度而忽視系統(tǒng)全局復(fù)雜度時會發(fā)生什么 - 更大的分布式大泥團(tuán)。

因此,當(dāng)我們只關(guān)注復(fù)雜度的某一種,選哪一個并不重要。在一個復(fù)雜分布式系統(tǒng),對向的復(fù)雜度都會暴漲。所以,我們不能只優(yōu)化一個。相反,我們要平衡本地和全局復(fù)雜度。
有意思的是,在“組合/結(jié)構(gòu)設(shè)計”一書中描述的復(fù)雜度平衡不僅與分布式系統(tǒng)有關(guān),其也提供了如何設(shè)計微服務(wù)的見解。
翻譯待續(xù) ...
本文來自祝坤榮(時序)的微信公眾號「麥芽面包,id「darkjune_think」 開發(fā)者/科幻愛好者/硬核主機(jī)玩家/業(yè)余翻譯。
— 本文結(jié)束 —

● 漫談設(shè)計模式在 Spring 框架中的良好實(shí)踐
關(guān)注我,回復(fù) 「加群」 加入各種主題討論群。
對「服務(wù)端思維」有期待,請在文末點(diǎn)個在看
喜歡這篇文章,歡迎轉(zhuǎn)發(fā)、分享朋友圈


