單體架構(gòu)和微服務(wù)架構(gòu)到底哪個(gè)好?
作者 | jeanwu
單體和微服務(wù)誰是毒瘤?單體、分布式、微服務(wù)、SOA到底是什么關(guān)系?我的系統(tǒng)該用什么架構(gòu)?最近終于下定決心研究這個(gè)問題并且有所收獲,歡迎一起討論。
一、架構(gòu)的發(fā)展歷程
我堅(jiān)定的認(rèn)為要深刻的理解一項(xiàng)技術(shù)光靠網(wǎng)上一兩張按照各項(xiàng)維度對(duì)比的表格是不夠的,而是要了解這些技術(shù)出現(xiàn)的歷史背景:他們的出現(xiàn)到底是解決了什么問題,又帶來了什么新的問題,最后又因何而被淘汰。下面這部分內(nèi)容參考《鳳凰架構(gòu)》以及Martin Fowle等人一些文章進(jìn)行整理,一起來看下歷史的浪潮是如何推動(dòng)架構(gòu)的演進(jìn)。
1.原始分布式時(shí)代
首先介紹的是竟然是“分布式”而不是“單體”這有些反常識(shí),然而事實(shí)上分布式確實(shí)出現(xiàn)的比單體早,“單體”這個(gè)名稱是在微服務(wù)開始流行之后“事后追認(rèn)”所形成的概念,在單體出現(xiàn)之前分布式早已流行,并且成果斐然。
1971年Intel公司設(shè)計(jì)了世界上第一臺(tái)微型計(jì)算機(jī)MCS-4,開創(chuàng)了微型計(jì)算機(jī)的新時(shí)代,計(jì)算機(jī)逐步從專業(yè)的科研設(shè)備轉(zhuǎn)變?yōu)槠髽I(yè)的生產(chǎn)設(shè)備。但是微型計(jì)算機(jī)用于商業(yè)生產(chǎn)面臨一個(gè)非常大的問題:計(jì)算機(jī)硬件有限的運(yùn)算處理能力,直接限制在單臺(tái)計(jì)算機(jī)上信息系統(tǒng)軟件能夠達(dá)到的最大規(guī)模。如果你生在這個(gè)時(shí)代,相信也能自然而然想到這一問題的解決思路:“人多力量大”、”眾人拾柴火焰高“,樸素的真理適用于任何地方,當(dāng)時(shí)高校、研究機(jī)構(gòu)、企等不約而同的開始探索“使用多臺(tái)計(jì)算機(jī)共同協(xié)作來支撐同一套軟件系統(tǒng)”的方案,并取得了一系的成果。談分布式必然繞不開遠(yuǎn)程調(diào)用,所以下面以遠(yuǎn)程調(diào)用為例談一下這一時(shí)期的探索成果有什么局限性,又產(chǎn)生了哪些深淵的影響。
通過多臺(tái)計(jì)算機(jī)分布式協(xié)同支撐提升系統(tǒng)規(guī)模
大家應(yīng)該了解“UNIX系統(tǒng)的版本戰(zhàn)爭(zhēng)”這一故事,為了避免相同的“戰(zhàn)爭(zhēng)”重演,負(fù)責(zé)制定 UNIX 系統(tǒng)技術(shù)標(biāo)準(zhǔn)的開放軟件基金會(huì)與主流計(jì)算機(jī)廠商共同制訂了DCE/RPC這一影響深遠(yuǎn)的遠(yuǎn)程服務(wù)調(diào)用規(guī)范,它也是公認(rèn)的現(xiàn)代 RPC 鼻祖之一。因?yàn)殚_放軟件基金會(huì)本身就負(fù)責(zé)UNIX 系統(tǒng)技術(shù)標(biāo)準(zhǔn)的制定,在這個(gè)背景下,DCE/RPC帶著濃厚的UNIX“簡(jiǎn)單優(yōu)先原則”的設(shè)計(jì)哲學(xué),預(yù)設(shè)分布式環(huán)境中的服務(wù)調(diào)用、資源訪問等操作盡可能透明,使開發(fā)人員不必過于關(guān)注他們?cè)L問的方法或資源是位于本地還是遠(yuǎn)程。
然而這個(gè)過于理想化的目標(biāo)在當(dāng)時(shí)面臨著太多的技術(shù)難題,“遠(yuǎn)程調(diào)用”與“本地調(diào)用”相比復(fù)雜程度完全不可同日而語:服務(wù)發(fā)現(xiàn)、負(fù)載均衡、熔斷、隔離、降級(jí)、認(rèn)證、授權(quán)等一系列的問題亟待解決。令人敬佩的是面對(duì)重重困難,DCE從無到有構(gòu)建了大量的協(xié)議來解決這些問題,真的做到了相對(duì)“透明”,但是分布式還有一個(gè)致命的問題——網(wǎng)絡(luò)所帶來的性能問題。
我們來推演一下:硬件性能不足——>采用分布式服務(wù)——>分布式的遠(yuǎn)程調(diào)用導(dǎo)致性能降低(與解決硬件性能不足的初心相悖)——>通過合并多個(gè)請(qǐng)求等方式刻意(開發(fā)人員需要意識(shí)到自己在寫分布式程序,與DCE透明簡(jiǎn)單相悖)降低網(wǎng)絡(luò)性能損耗——>人的能力成為軟件規(guī)模的約束。這時(shí)候分布式從結(jié)果來看并不成功,設(shè)計(jì)向性能妥協(xié)讓簡(jiǎn)單透明成為一句空話。
當(dāng)我們玩游戲打BOSS時(shí),喊人解決不了問題還有另外個(gè)方法——氪金,20世紀(jì)80年代摩爾定律穩(wěn)定發(fā)揮,微型計(jì)算機(jī)的性能以每?jī)赡昙丛鲩L(zhǎng)一倍的驚人速度提升,既然分布式充滿了矛盾與妥協(xié),那就加錢換更好的機(jī)器,單體時(shí)代到來。
通過提升單臺(tái)計(jì)算機(jī)性能提升系統(tǒng)規(guī)模
2.單體架構(gòu)時(shí)代
在微服務(wù)出現(xiàn)之前“單體”都不認(rèn)為是架構(gòu),因?yàn)樗昂?jiǎn)單”、太“自然”了,以至于我想找到一本關(guān)于單體最佳實(shí)踐的書籍都沒有找到?,F(xiàn)在很多書籍把單體當(dāng)做“毒瘤”,甚至?xí)霈F(xiàn)微服務(wù)比單體先進(jìn)的觀點(diǎn),然而事實(shí)上真的如此嗎?
首先,我們先要明確單體是什么:“單體”只是表明系統(tǒng)中主要的過程調(diào)用都是進(jìn)程內(nèi)通信,不會(huì)發(fā)生進(jìn)程間通信,僅此而已。那么進(jìn)程內(nèi)調(diào)用是罪惡?jiǎn)幔渴嵌玖鰡??那肯定不是的?,F(xiàn)實(shí)中不會(huì)有人對(duì)你說:你這個(gè)"Hello, World!"程序不能用單體,因?yàn)閱误w架構(gòu)是毒瘤。
有個(gè)“單體不便于擴(kuò)展“的論調(diào)非常流行,我們著重討論下這個(gè)觀點(diǎn)是否準(zhǔn)確。我們從性能擴(kuò)展和功能擴(kuò)展兩個(gè)方便說。先說性能擴(kuò)展:這太簡(jiǎn)單了,把一個(gè)服務(wù)部署多個(gè)副本,前面加一個(gè)負(fù)載均衡服務(wù)器來均分流量,這是不是就實(shí)現(xiàn)了擴(kuò)展?再說功能擴(kuò)展:縱向上我從來沒見到哪個(gè)大型系統(tǒng)代碼是不分層的,用過Spring都知道寫一個(gè)服務(wù)基本上默認(rèn)按照MVC模式分層以便于擴(kuò)展;而橫向上我們也可以從功能等維度拆分為不同模塊(模塊之間不進(jìn)行通信或者進(jìn)行少量的通信,注意:拆分模塊不代表不是單體服務(wù),單體服務(wù)也不表示系統(tǒng)只有一個(gè)模塊),各模塊完全可以獨(dú)立迭代。從這個(gè)角度來看單體服務(wù)在“可擴(kuò)展”這一點(diǎn)上也不輸與微服務(wù),甚至在開發(fā)、調(diào)試等方面更優(yōu)。當(dāng)前單體服務(wù)也有其局限性,比如有個(gè)C++實(shí)現(xiàn)的系統(tǒng)要實(shí)現(xiàn)部分AI功能,明顯Python更有優(yōu)勢(shì),C++中執(zhí)行Python雖然可以實(shí)現(xiàn),但是顯然不如微服務(wù)獨(dú)立一個(gè)Python模塊來的優(yōu)雅。現(xiàn)在回來看“單體服務(wù)不便于擴(kuò)展”這個(gè)觀點(diǎn)并不完全正確。
單體也有良好的擴(kuò)展性
“罪惡的單體”是“大型的單體系統(tǒng)”,而“大單體服務(wù)”的主要罪惡在于隔離性。舉一個(gè)例子,不小心寫了一個(gè)BUG會(huì)導(dǎo)致程序崩潰,如果是微服務(wù)只會(huì)導(dǎo)致一個(gè)模塊崩潰,影響的范圍也僅僅是依賴這個(gè)模塊的功能,可是如果是單體服務(wù),所有代碼都共享著同一個(gè)進(jìn)程空間,某一處崩潰直接導(dǎo)致整個(gè)進(jìn)程崩潰,那影響的范圍就大了。到這里我們可以簡(jiǎn)單的說:?jiǎn)误w服務(wù)在同一進(jìn)程更簡(jiǎn)單、高效,其代價(jià)是損失了隔離能力以及技術(shù)擴(kuò)展性。至于這兩點(diǎn)誰輕誰重不可一概而論,要看你的系統(tǒng)到底是一個(gè)小賣店還是一個(gè)大超市了。
既然單體和微服務(wù)各有優(yōu)劣,為什么后來微服務(wù)潮流滾滾而來?互聯(lián)網(wǎng)是不斷發(fā)展的,隨著微型計(jì)算機(jī)的普及,軟件系統(tǒng)的功能越來越多,對(duì)應(yīng)的開發(fā)團(tuán)隊(duì)規(guī)模也越來越大,我們逐步進(jìn)入了“大兵團(tuán)作戰(zhàn)”時(shí)代,這時(shí)候“墨菲定律”+“黑天鵝事件”對(duì)系統(tǒng)可用性影響越來越大。
構(gòu)建一個(gè)大規(guī)模但依然可靠的軟件系統(tǒng)非常難。根據(jù)墨菲定律可能發(fā)生的事(BUG)就一定會(huì)發(fā)生,再疊加不可預(yù)測(cè)的“黑天鵝事件”,隨著研發(fā)團(tuán)隊(duì)的規(guī)模不斷擴(kuò)大,系統(tǒng)不可用的概率會(huì)被無限放大,舉個(gè)極端點(diǎn)的例子:假如一個(gè)公司有10萬人,每個(gè)人寫出系統(tǒng)的可用性都能達(dá)到99.999%,可是當(dāng)他們共同協(xié)作寫一個(gè)單體服務(wù)時(shí),那么系統(tǒng)的可用性就是99.999%的10萬次方,約等于36.8%,這個(gè)系統(tǒng)簡(jiǎn)直不可用,更何況人是不可靠的,這時(shí)候單體服務(wù)隔離性差的缺點(diǎn)凸顯。微服務(wù)把構(gòu)筑可靠系統(tǒng)觀點(diǎn)從“追求盡量不出錯(cuò)”轉(zhuǎn)變?yōu)椤俺鲥e(cuò)是必然”,通過拆分服務(wù)以減少異常的影響范圍,關(guān)于微服務(wù)為什么可以提升系統(tǒng)的可用性可以用一個(gè)例子幫助理解:人體系統(tǒng)由一個(gè)個(gè)的不可靠的細(xì)胞(微服務(wù))組成,大多數(shù)情況下一個(gè)或者一群微服務(wù)(細(xì)胞)的崩潰并不會(huì)影響我們的生命,我們的人體系統(tǒng)就是用不可靠部件構(gòu)造的可靠的系統(tǒng)例子。
隨著系統(tǒng)規(guī)模擴(kuò)大單體拆分勢(shì)不可擋,關(guān)于大單體如何拆分前輩們也進(jìn)行了大量的探索,其中比較有代表性的有三種:
(1) 煙囪式架構(gòu):其實(shí)這里并沒有什么高深的理論,無非就是隨著系統(tǒng)的迭代,把一個(gè)系統(tǒng)拆分多個(gè),拆分后的系統(tǒng)相互獨(dú)立沒有業(yè)務(wù)交互,因此使用這種架構(gòu)系統(tǒng)又稱為孤島式信息系統(tǒng),問題是這種情況真的存在嗎,如果存在大概率一開始就設(shè)計(jì)為兩個(gè)系統(tǒng),既然是兩個(gè)系統(tǒng)也就不會(huì)放在一個(gè)單體里面了,放在一起那必然是因?yàn)檫@兩個(gè)系統(tǒng)共享了某些資源的,例如存儲(chǔ)、權(quán)限、賬號(hào)等等。
(2) 微內(nèi)核架構(gòu):煙囪式架構(gòu)在實(shí)際很少存在,因?yàn)椴鸱趾蟮南到y(tǒng)與系統(tǒng)大概率是有資源共享的,既然如此就大方的把數(shù)據(jù)、資源、公共服務(wù)集中到一塊成為一個(gè)被所有業(yè)務(wù)系統(tǒng)共同依賴的核心,具體的業(yè)務(wù)系統(tǒng)以插件模塊(Plug-in Modules)的形式存在,注意微內(nèi)核架構(gòu)核心在于微,核心只負(fù)責(zé)通用業(yè)務(wù)邏輯,不包括針對(duì)特殊情況、特殊規(guī)則或復(fù)雜條件處理的自定義代碼,不是插件化實(shí)現(xiàn)就一定是微內(nèi)核架構(gòu),比如MySQL只是存儲(chǔ)引擎做成了插件,而MySQL的Server層是核心功能,不能算微內(nèi)核架構(gòu)。
這種架構(gòu)至今仍然存在,Eclipse IDE就是一個(gè)典型代表,下載基本的Eclipse產(chǎn)品只會(huì)提供一個(gè)簡(jiǎn)單的編輯器,一旦添加插件它就能變成一個(gè)高度可定制和實(shí)用的軟件開發(fā)工具。當(dāng)然微內(nèi)核架構(gòu)也有其局限性,由于無法預(yù)先知道有哪些插件,因此實(shí)現(xiàn)一個(gè)插件時(shí)并不能默認(rèn)的可以與另一個(gè)插件交互,插件只能和內(nèi)核交互。
目前保險(xiǎn)行業(yè)也常用微內(nèi)核架構(gòu),由于不同地區(qū)、時(shí)間、事件索賠規(guī)則非常復(fù)雜,理賠規(guī)則會(huì)發(fā)展成一個(gè)復(fù)雜的大泥球,更改一條規(guī)則會(huì)影響其他規(guī)則,開發(fā)測(cè)試極其麻煩。使用微內(nèi)核架構(gòu)模式可以解決其中許多問題:
(3) 事件驅(qū)動(dòng)架構(gòu):事件驅(qū)動(dòng)解決了微內(nèi)核架構(gòu)插件不能相互交互的問題,子系統(tǒng)之間建立一套事件隊(duì)列管道,子系統(tǒng)可以發(fā)布消息到隊(duì)列,也可以訂閱隊(duì)列中的消息。系統(tǒng)之間完全解耦,好的架構(gòu)歷久彌新,迄今為止電商系統(tǒng)依然有事件驅(qū)動(dòng)架構(gòu)的影子:下單、支付、發(fā)貨、結(jié)算,完全是由事件驅(qū)動(dòng)。
圖源Google Cloud
3.SOA架構(gòu)時(shí)代
在原始分布式時(shí)代就提到單體和分布式并行發(fā)展,單體架構(gòu)在探索如何拆分、演化到事件驅(qū)動(dòng)架構(gòu)時(shí),分布式也在曲折發(fā)展,SOA即將登上架構(gòu)的舞臺(tái)。
剛接觸到“SOA治理”時(shí)我并不是很清楚是到底治理什么,SOA看起來似乎和微服務(wù)是一樣的,并沒有感受到明顯區(qū)別。SOA(Service-Oriented Architecture)是面向服務(wù)的架構(gòu)……很遺憾定義實(shí)在太多了,我沒有找到權(quán)威的、明確的解釋,但是通過總結(jié)起碼有兩點(diǎn)我覺得是各方達(dá)成共識(shí)的。
- 面向服務(wù)的架構(gòu)中的“服務(wù)”是指包含執(zhí)行完整的、獨(dú)立業(yè)務(wù)功能所需的代碼和數(shù)據(jù)的,注意是“代碼”和“數(shù)據(jù)”,也就是說服務(wù)是一個(gè)獨(dú)立的功能單元,這里的服務(wù)和事件驅(qū)動(dòng)架構(gòu)中的子系統(tǒng)非常類似,要比今天我們所說的微服務(wù)中的“服務(wù)”粒度要粗的多。
- SOA的目的是復(fù)用,并為此制定了一系列標(biāo)準(zhǔn),服務(wù)之間使用公共接口標(biāo)準(zhǔn)和架構(gòu)模式,因此可以快速整合到新應(yīng)用中。這讓應(yīng)用開發(fā)人員無需像之前那樣重新開發(fā)現(xiàn)有功能,因?yàn)橛泄驳慕涌跇?biāo)準(zhǔn)開發(fā)人員也不必了解如何連接現(xiàn)有功能 。
這么看SOA并不是解決新的問題,依然是在解決分布式服務(wù)剛被提出時(shí)就預(yù)見的困難,但是SOA針對(duì)這些問題的解決方案更具體、操作性更強(qiáng),并形成一攬子規(guī)范標(biāo)準(zhǔn),相比前面的煙囪架構(gòu)、微內(nèi)核架構(gòu)、事件驅(qū)動(dòng)架構(gòu),SOA就顯得具體的多,舉幾個(gè)例子:SOA明確了采用 SOAP 作為遠(yuǎn)程調(diào)用的協(xié)議、明確使用企業(yè)服務(wù)總線(ESB)來實(shí)現(xiàn)各個(gè)子系統(tǒng)之間的通信交互等等,從技術(shù)角度SOA成功地解決了分布式環(huán)境下出現(xiàn)的主要技術(shù)問題,那SOA為什么逐步被微服務(wù)替代呢?
因?yàn)镾OA太重了,過于嚴(yán)格的一攬子規(guī)范定義帶來過度的復(fù)雜性,落地成本非常之高。我們以遠(yuǎn)程服務(wù)調(diào)用(Remote Procedure Call,RPC)為例:RPC 出現(xiàn)的最初目的是為了讓調(diào)用遠(yuǎn)程方法和調(diào)用本地方法一樣簡(jiǎn)單,直到今天還有人這么認(rèn)為,實(shí)際上今天的大多數(shù) RPC 技術(shù)已經(jīng)不再追求這個(gè)目標(biāo),因?yàn)橥ㄐ挪皇菬o成本的。Andrew Tanenbaum 教授曾在1987年發(fā)布一篇論文,核心論點(diǎn)是本地調(diào)用與遠(yuǎn)程調(diào)用當(dāng)做一樣處理,這是犯了方向性的錯(cuò)誤,把系統(tǒng)間的調(diào)用做成透明,反而會(huì)增加程序員工作的復(fù)雜度,這個(gè)觀點(diǎn)在后幾年一直有爭(zhēng)論,直到大名鼎鼎的Sun公司一眾大佬總結(jié)“通過網(wǎng)絡(luò)進(jìn)行分布式運(yùn)算的八宗罪”該觀點(diǎn)才被廣泛認(rèn)可,明確RPC是語言層次的特征,而不是系統(tǒng)層次的特征。
既然是RPC是語言層次的特征,編程語言那么多,最理想的是有一套統(tǒng)一的規(guī)范來解決RPC中如何表示數(shù)據(jù)、傳遞數(shù)據(jù)、確定方法三個(gè)基本問題(事實(shí)上直到現(xiàn)在RPC協(xié)議都是混亂的,數(shù)一數(shù)現(xiàn)在流行的RPC協(xié)議有多少個(gè))。這個(gè)規(guī)范的發(fā)展很曲折,我們重點(diǎn)關(guān)注一個(gè)歷史性的時(shí)刻:W3C在1998年發(fā)布SOAP 1.0來實(shí)現(xiàn)Web Service。SOAP當(dāng)時(shí)風(fēng)頭一時(shí)無兩,雖然現(xiàn)在來看他在性能上和易用性上并不完美,但是這并不是他沒落的原因,而是因?yàn)檫^于“理想主義”的期望解決解決分布式計(jì)算中可能遇到的所有問題,為此定義龐大Web Service 協(xié)議家族,學(xué)習(xí)、使用成本非常高,脫離人民群眾的做法導(dǎo)致SOAP必然逐漸淹沒在歷史的長(zhǎng)河中。SOAP作為SOA登上架構(gòu)舞臺(tái)的重要條件,他的沒落也意味著SOA架構(gòu)的沒落。
回顧“原始分布式時(shí)代”這一講中:Unix DCE提出的分布式服務(wù)的主旨是“讓開發(fā)人員不必關(guān)心服務(wù)是遠(yuǎn)程還是本地,都能夠透明地調(diào)用服務(wù)或者訪問資源”。但是現(xiàn)在SOA已經(jīng)背離了這一初心,于是微服務(wù)時(shí)代到來。
4.微服務(wù)架構(gòu)時(shí)代
微服務(wù)真正崛起實(shí)于2014年,這時(shí)候的微服務(wù)已經(jīng)和9年前剛剛被提出時(shí)有了明顯的區(qū)別。最開始微服務(wù)是SOA的輕量版,既然SOA過于繁重,那么微服務(wù)就盡可能的拋棄SOA 里可以拋棄的所有約束和規(guī)范,回歸透明簡(jiǎn)單的初心;當(dāng)然現(xiàn)在微服務(wù)已經(jīng)脫離SOA成為一整獨(dú)立的架構(gòu)風(fēng)格,Martin Fowler在《Microservices: A Definition of This New Architectural Term》一文中對(duì)微服務(wù)解釋已經(jīng)足夠詳細(xì),這里不再贅述。
那么微服務(wù)和SOA到底有什么不同?討論這個(gè)問題實(shí)在意義不大,因?yàn)樗麄冎g的關(guān)系實(shí)在太微妙了,有人說ESB是SOA的特點(diǎn),這其實(shí)是過于武斷了,微服務(wù)拋棄了SOA中所有可以拋棄的標(biāo)準(zhǔn)并不代表微服務(wù)一定不用,別忘了微服務(wù)是自由的。我們只需要知道:微服務(wù)提倡以“實(shí)踐標(biāo)準(zhǔn)”代替“規(guī)范標(biāo)準(zhǔn)”,針對(duì)SOA解決的那些分布式服務(wù)的問題在微服務(wù)中不再會(huì)有統(tǒng)一的解決方案,開發(fā)者可以結(jié)合實(shí)際情況自由選擇。
微服務(wù)是普通開發(fā)者的狂歡,可以隨心所欲;微服務(wù)是架構(gòu)者的噩夢(mèng),對(duì)架構(gòu)師的能力要求提升到史無前例。微服務(wù)并不是什么銀彈,沒有必要過分的神話他,分布式架構(gòu)中出現(xiàn)的問題如注冊(cè)發(fā)現(xiàn)、跟蹤治理、負(fù)載均衡、傳輸通信等微服務(wù)一個(gè)都沒有避免,該需要解決還是需要解決。但是在云時(shí)代下,微服務(wù)迎來新的契機(jī):云技術(shù)讓微服務(wù)從軟件層面獨(dú)力應(yīng)對(duì)分布式問題發(fā)展到軟、硬協(xié)同應(yīng)對(duì),也稱為“后微服務(wù)時(shí)代”。
當(dāng)問題不局限于采用軟件方式那很多問題都簡(jiǎn)單了。例如軟件可以通過命令伸縮擴(kuò)容服務(wù),硬件難道就不可以通過敲鍵盤就變出相應(yīng)的應(yīng)用服務(wù)器、負(fù)載均衡器等基礎(chǔ)設(shè)施嗎?氪金買云服務(wù)一樣可以解決問題,虛擬化技術(shù)讓軟件、硬件的邊界開始模糊,一旦虛擬化硬件變得足夠靈活,那么和業(yè)務(wù)無關(guān)的技術(shù)性問題都可以解決于基礎(chǔ)設(shè)施內(nèi),讓研發(fā)專注于業(yè)務(wù)開發(fā)。后面也催生出了云原生等許多新的概念,但是從本質(zhì)上講他們所追求的目標(biāo)和微服務(wù)沒有什么區(qū)別。微服務(wù)時(shí)代所取得的成就離不開以虛擬化技術(shù)的巨大貢獻(xiàn)。
微服務(wù)+云讓普通程序員也同樣能寫出可用于生產(chǎn)的軟件產(chǎn)品,但是對(duì)于架構(gòu)師提出更高的技術(shù)要求,這會(huì)導(dǎo)致開發(fā)者的分層,形成大部分普通程序員加上小部分軟件設(shè)計(jì)專家的金字塔結(jié)構(gòu)。
5.無服務(wù)時(shí)代
回想分布式架構(gòu)之所以存在,最開始就是因?yàn)閱闻_(tái)機(jī)器的性能無法滿足復(fù)雜系統(tǒng)的需要。那么如果單臺(tái)機(jī)器如果性能無限所有問題都解決了。以前不敢做這樣的假設(shè),但是現(xiàn)在云計(jì)算技術(shù)的發(fā)展實(shí)際已經(jīng)讓這個(gè)暢想接近現(xiàn)實(shí),而所謂無服務(wù)實(shí)際主要涉及兩點(diǎn):后端基礎(chǔ)設(shè)施和函數(shù)。后端基礎(chǔ)設(shè)施提供了日志、存儲(chǔ)等等這一類用于支撐業(yè)務(wù)邏輯運(yùn)行,而函數(shù)負(fù)責(zé)實(shí)現(xiàn)業(yè)務(wù)邏輯。我們不用考慮容量和算力問題,函數(shù)就是服務(wù)?,F(xiàn)在云計(jì)算提供的能力已經(jīng)讓無服務(wù)初見端倪。
到這里架構(gòu)演變的歷史我們已經(jīng)理清,相信你也理解了每種架構(gòu)出現(xiàn)的意義與淘汰的原因,接下來我們一起討論該如何選擇架構(gòu)來解決今天我們所面臨的現(xiàn)實(shí)問題。
二、單體還是微服務(wù)
我們花了大量的篇幅去講架構(gòu)演進(jìn)是為了在歷史的浪潮中,理解每種架構(gòu)出現(xiàn)的意義和淘汰原因,解決今天我們所面對(duì)的現(xiàn)實(shí)問題。直到現(xiàn)在關(guān)于架構(gòu)好壞之爭(zhēng)依然存在,最激烈的討論就是的單體還是微服務(wù)。先說結(jié)論,假如一個(gè)業(yè)務(wù)發(fā)展良好,當(dāng)系統(tǒng)復(fù)雜度增加到一定程度必然是從單體遷移到微服務(wù)的,但在這之前,我推薦單體。下面我們來看下是什么驅(qū)動(dòng)復(fù)雜系統(tǒng)從單體向微服務(wù)遷移。
1.為什么要使用微服務(wù)
天下熙熙,皆為利來;天下攘攘,皆為利往。有收益才有付出,上文已經(jīng)介紹既然單體是如此簡(jiǎn)單、自然為什么還要遷移到微服務(wù)呢?為了更好的性能?微服務(wù)可以擴(kuò)縮容自如,很好的應(yīng)對(duì)業(yè)務(wù)發(fā)展所帶來的性能壓力,問題是隨著云計(jì)算的發(fā)展,單體服務(wù)同樣可以集群化部署、同樣可以很方便的擴(kuò)縮容,而且硬件的價(jià)格越來越便宜,甚至單體服務(wù)還減少了RPC所帶來的性能損耗,這個(gè)理由看似正確,實(shí)際上是站不住腳的。僅僅為了性能而選擇分布式的話,那應(yīng)該是 40 年前“原始分布式時(shí)代”所追求的目標(biāo)。需求是不這樣不行,而不是這樣也行,同理復(fù)雜系統(tǒng)遷移微服務(wù)必然也有著非遷不可的理由。
(1) 當(dāng)團(tuán)隊(duì)內(nèi)個(gè)人能力因素成為系統(tǒng)發(fā)展的明顯制約
這個(gè)問題很好解釋,前面我已經(jīng)舉了一個(gè)極端例子:有10萬人寫一個(gè)單體服務(wù),假如每個(gè)人寫出系統(tǒng)的可用性都能達(dá)到99.999%,那么這個(gè)單體服務(wù)的可用性只能達(dá)到36.8%。更何況沒有人能保證招到的人全部都專業(yè)、靠譜,即使可以人也具有不穩(wěn)定性,受到情緒、健康狀況、人際關(guān)系影響也可能干出各種不靠譜的事,難以做出整體可靠的大型系統(tǒng)。由于在單體架構(gòu)下系統(tǒng)中“整體”與“部分”的關(guān)系沒有物理的劃分,一旦發(fā)生錯(cuò)誤缺乏有效的阻斷手段,而少量的專家也沒有辦法控制某個(gè)人研發(fā)在某行不起眼的代碼生成一個(gè)BUG并造成全局影響。
這種情況下,團(tuán)隊(duì)人員水平參差不齊,或者團(tuán)隊(duì)已經(jīng)發(fā)展的非常大,微服務(wù)都是一個(gè)更好的選擇。在單體架構(gòu)下,系統(tǒng)質(zhì)量只能靠研發(fā)與項(xiàng)目管理措施來盡可能地保障,而微服務(wù)已經(jīng)假定系統(tǒng)一定會(huì)出錯(cuò),架構(gòu)本身就追求獨(dú)立、自治,讓高水平專家來開發(fā)和維護(hù)關(guān)鍵的基礎(chǔ)設(shè)置和業(yè)務(wù)服務(wù),至于其他非核心功能發(fā)生錯(cuò)誤可以依靠基礎(chǔ)設(shè)置的自愈能力恢復(fù),退一萬步來講即使不能恢復(fù)影響也控制在一個(gè)小的范圍,而系統(tǒng)整體依然是高可用的。
(2) 當(dāng)語言或者技術(shù)框架成為系統(tǒng)發(fā)展的明顯制約
語言沒有好壞,但有適不適合,舉一個(gè)非常簡(jiǎn)單的例子:近幾年人工智能開展的如火如荼,所有的軟件都在考慮怎么結(jié)合人工智能提供能優(yōu)秀的服務(wù),讓業(yè)務(wù)進(jìn)入第二增長(zhǎng)曲線。但是稍微一調(diào)研就會(huì)發(fā)現(xiàn)Python對(duì)于AI訓(xùn)練的支持是其他所有語言所無法比擬的,如果原來的系統(tǒng)使用C++實(shí)現(xiàn),這時(shí)候?qū)Σ煌夹g(shù)棧、不同框架實(shí)現(xiàn)的功能進(jìn)行分布式部署并不是你想或者不想的問題,而是沒有選擇、無可避免的。當(dāng)然非要在C++里執(zhí)行Python也可以,可是使用這些奇技淫巧所帶來的維護(hù)成本是無法估量的。
(3) 當(dāng)組織的人員架構(gòu)成為系統(tǒng)發(fā)展的明顯制約
康威定律大家應(yīng)該都了解,這里不做額外的贅述。變化是永恒的,隨著業(yè)務(wù)規(guī)模的不斷擴(kuò)大,開發(fā)該系統(tǒng)的團(tuán)隊(duì)也必然不斷擴(kuò)大,組織架構(gòu)隨之調(diào)整是自然而然的事。我們對(duì)抗不了康威定律,隨著組織架構(gòu)的調(diào)整系統(tǒng)架構(gòu)必然隨之調(diào)整。舉個(gè)簡(jiǎn)單的例子:我要對(duì)某個(gè)模塊進(jìn)行發(fā)布,該找誰審批,必然是自己的領(lǐng)導(dǎo)?但是如果是單體服務(wù)很可能涉及到多個(gè)團(tuán)隊(duì),讓每個(gè)團(tuán)隊(duì)的領(lǐng)導(dǎo)都來審批會(huì)導(dǎo)致發(fā)布效率低下,這是很難容忍的。
那如何識(shí)別組織架構(gòu)已經(jīng)成為制約了呢:當(dāng)所有的決策都要依賴某個(gè)人或者某個(gè)會(huì)議,對(duì)某個(gè)服務(wù)或者功能沒有人愿意承擔(dān)責(zé)任,或者愿意承擔(dān)責(zé)任的人成為決策單點(diǎn)時(shí),這時(shí)候就該意識(shí)到該拆分服務(wù)了。
(4) 小結(jié)
我們要認(rèn)識(shí)到微服務(wù)是有成本的,這里如果用一張表格來從各個(gè)緯度對(duì)比來說微服務(wù)需要解決哪些哪些問題可能并不會(huì)讓你有直接的感受,下面是網(wǎng)上一張著名的圖:Netflix公司在2014年公開的微服務(wù)調(diào)用關(guān)系圖。我相信Netflix中沒有一個(gè)人可以理清楚該系統(tǒng)的服務(wù)間調(diào)用關(guān)系,這是一個(gè)黑洞,如果某個(gè)微服務(wù)需要修改協(xié)議,很難理清楚到底需要周知哪些依賴方進(jìn)行兼容修改。
Netflix公司在2014年公開的微服務(wù)調(diào)用關(guān)系圖
微服務(wù)核心價(jià)值是拆分之后的系統(tǒng)能夠讓局部的單個(gè)服務(wù)敏捷開發(fā),最主要的目的是對(duì)系統(tǒng)進(jìn)行有效的拆分以進(jìn)行物理隔離,通過一系列的自制手段用不可靠的微服務(wù)構(gòu)造可靠的系統(tǒng),然而微服務(wù)在解決單體問題的同時(shí)又會(huì)帶來額外的很多問題,這里如果權(quán)衡不好反而會(huì)導(dǎo)致生產(chǎn)力下降,而系統(tǒng)進(jìn)行任何改造的根本動(dòng)力都是“這樣做收益大于成本”,因此“對(duì)于中小型系統(tǒng)單體架構(gòu)就是最好的架構(gòu)”,只有在業(yè)務(wù)已經(jīng)發(fā)展到一定的程度,單體架構(gòu)與微服務(wù)架構(gòu)的生產(chǎn)力曲線已經(jīng)到達(dá)交叉點(diǎn),此時(shí)開始進(jìn)行微服務(wù)化才是有收益的。至于這個(gè)是否出現(xiàn)了這個(gè)交叉點(diǎn)如何判斷,可以審查一下是否出現(xiàn)了以上三點(diǎn)。
圖源《鳳凰架構(gòu)》
2.使用微服務(wù)的必備條件
即使我們有了充分的理由要遷移微服務(wù)也不能立刻遷移,還要看當(dāng)前團(tuán)隊(duì)是否具備遷移微服務(wù)的條件,貿(mào)然遷移很可能會(huì)適得其反。
(1) 組織中具備對(duì)微服務(wù)有充分理解的專家
講微服務(wù)時(shí)代時(shí)候就提到,微服務(wù)給予編碼人員充分的自由,但對(duì)于架構(gòu)師卻提出了史無前例的高要求。在實(shí)際研發(fā)團(tuán)隊(duì)中并不是每個(gè)人都是架構(gòu)師,也不是每個(gè)人都會(huì)去探究擴(kuò)展、認(rèn)證、隔離等和具體業(yè)務(wù)無關(guān)的問題,大多人普通程序員還是更聚焦于業(yè)務(wù)代碼的編寫??墒鞘褂梦⒎?wù)卻不關(guān)注這些問題那帶來的災(zāi)難將是巨大的。
舉幾個(gè)例子:微服務(wù)之間如何路由?微服務(wù)之間如何進(jìn)行權(quán)限認(rèn)證?微服務(wù)超時(shí)間如何配置才能規(guī)避重試帶來的雪崩?流量變化以怎樣的策略進(jìn)行擴(kuò)縮容?而這些問題不解決很可能影響整個(gè)系統(tǒng)的可用性。使用微服務(wù)架構(gòu)的團(tuán)隊(duì)經(jīng)常會(huì)遇到這中情況:微服務(wù)劃分不合理導(dǎo)致高扇入、高扇出,加一個(gè)字段要修改N個(gè)模塊、測(cè)試N個(gè)接口,極其低效。因此要想享受微服務(wù)帶來的好處,首先就需要有專家認(rèn)識(shí)到其中的風(fēng)險(xiǎn),設(shè)計(jì)靠譜的架構(gòu)。如果整個(gè)團(tuán)隊(duì)中缺乏能夠在微服務(wù)架構(gòu)中撐起系統(tǒng)主干的專家,強(qiáng)行遷移微服務(wù)帶來的收益不足以抵消復(fù)雜性增加而導(dǎo)致的成本。
(2) 系統(tǒng)應(yīng)具有以自治為目標(biāo)的自動(dòng)化與監(jiān)控度量能力
我們期望團(tuán)隊(duì)具備這樣一個(gè)資產(chǎn)管理系統(tǒng),可以清晰的看到所有的資產(chǎn)、服務(wù)運(yùn)行情況以及系統(tǒng)還有多少風(fēng)險(xiǎn)項(xiàng)沒有消除。微服務(wù)是由大量松耦合服務(wù)互相協(xié)作構(gòu)成的系統(tǒng),一旦切換為微服務(wù)意味著資產(chǎn)成倍增長(zhǎng)。我們?cè)賮砘仡櫹拢何⒎?wù)是正視問題,認(rèn)為“錯(cuò)誤一定會(huì)發(fā)生”,因此要有一系列的手段來用不可靠的微服務(wù)構(gòu)造可靠的系統(tǒng)。這個(gè)前提系統(tǒng)能夠監(jiān)控自身的健康狀態(tài)以實(shí)現(xiàn)自動(dòng)恢復(fù),也就是我們需要奔著自動(dòng)化運(yùn)維目標(biāo)前進(jìn)。
在團(tuán)隊(duì)缺少基礎(chǔ)設(shè)施的情況下使用微服務(wù)是冒著極大風(fēng)險(xiǎn)的,想象一下系統(tǒng)故障,原來使用單體服務(wù)只需要查看少數(shù)模塊就可以定位問題發(fā)生點(diǎn),假如拆分為數(shù)百個(gè)模塊,如果沒有有效的監(jiān)控系統(tǒng),該需要多少時(shí)間才能定位到異常原因。
3.如何實(shí)踐微服務(wù)
如何實(shí)踐微服務(wù)這個(gè)話題太大了,遠(yuǎn)遠(yuǎn)不是一篇文章所能夠承載的,光介紹微服務(wù)的書就有《微服務(wù)設(shè)計(jì)》、《微服務(wù)架構(gòu)設(shè)計(jì)模式》、《微服務(wù)分布式構(gòu)架開發(fā)實(shí)戰(zhàn)》 等等很多,這里我只是簡(jiǎn)單提幾個(gè)點(diǎn)與大家一起討論:
如果團(tuán)隊(duì)規(guī)模較小,在開始一個(gè)新的系統(tǒng)的時(shí)我認(rèn)為應(yīng)該堅(jiān)定不移的選擇單體服務(wù)。這時(shí)候希望團(tuán)隊(duì)對(duì)于做出使用的單體的架構(gòu)師有充分的信任。現(xiàn)實(shí)中往往在立項(xiàng)之初就會(huì)給業(yè)務(wù)定下長(zhǎng)遠(yuǎn)的目標(biāo),但是從技術(shù)角度還是應(yīng)該立足當(dāng)下,然后隨著業(yè)務(wù)不斷發(fā)展對(duì)架構(gòu)進(jìn)行及時(shí)調(diào)整。切不可當(dāng)業(yè)務(wù)發(fā)展到一定規(guī)模時(shí)需要拆分微服務(wù)時(shí)再來指責(zé)架構(gòu)師:“當(dāng)初我就說應(yīng)該使用微服務(wù),而不應(yīng)該使用單體這種落后的架構(gòu)”。客觀的想一下,與一開始就用微服務(wù)比,前期使用單體所節(jié)約的工作量,比起遷移所帶來工作是劃算的。我們也應(yīng)該有這樣的意識(shí):我們沒有辦法設(shè)計(jì)出一個(gè)永遠(yuǎn)不變的完美的架構(gòu),架構(gòu)一定是隨著業(yè)務(wù)發(fā)展而不斷變化的。
如果團(tuán)隊(duì)規(guī)模較大,我相信沒有哪個(gè)系統(tǒng)一開始就由一個(gè)“大團(tuán)隊(duì)”開發(fā),而是隨著業(yè)務(wù)發(fā)展系統(tǒng)規(guī)模越來越大,團(tuán)隊(duì)所需的人員也不斷增長(zhǎng)最終變成“大團(tuán)隊(duì)”。這種情況下應(yīng)該通過領(lǐng)域建模后基于內(nèi)部視角將系統(tǒng)劃分為多個(gè)子系統(tǒng),結(jié)合康威定律將這些子系統(tǒng)分配給不同的小團(tuán)隊(duì)負(fù)責(zé)。通常情況下此階段系統(tǒng)已經(jīng)變的較為復(fù)雜,達(dá)到了2.1.4小節(jié)圖中效率和成本的平衡點(diǎn),各個(gè)小團(tuán)隊(duì)經(jīng)過評(píng)估后可以將所負(fù)責(zé)的子系統(tǒng)部署為相對(duì)獨(dú)立的服務(wù),這些服務(wù)之間的交互使用統(tǒng)一的規(guī)范。而且推薦數(shù)據(jù)去中心化,每個(gè)服務(wù)管理自己的數(shù)據(jù)庫,即使這些數(shù)據(jù)在不同的子系統(tǒng)都可能出現(xiàn),但是每個(gè)子系統(tǒng)所需要的屬性多少有差異,還是推薦自己維護(hù)以便于團(tuán)隊(duì)獨(dú)立迭代。實(shí)際上就是每個(gè)小團(tuán)隊(duì)維護(hù)了一個(gè)小的子系統(tǒng),那么參考第一點(diǎn)“如果團(tuán)隊(duì)規(guī)模較小”時(shí)的結(jié)論,各個(gè)小的團(tuán)隊(duì)構(gòu)建服務(wù)也從單體服務(wù)架構(gòu)開始,沒有必要從一開始就再拆分多個(gè)更小的服務(wù)。我所在團(tuán)隊(duì)也一直在探索和實(shí)踐單體服務(wù),某業(yè)務(wù)的核心功能到現(xiàn)在依然是單體,該業(yè)務(wù)已經(jīng)發(fā)展三年,到現(xiàn)在為止尚沒有因?yàn)槭褂脝误w而在某一點(diǎn)上明顯拖慢效率。
三、尾巴
回到導(dǎo)語中的問題,單體和微服務(wù)誰是毒瘤,都不是,他們只是在某個(gè)歷史階段下適應(yīng)潮流而生的一種普通的架構(gòu),并沒有高低貴賤、先進(jìn)落后之分;而現(xiàn)在,也只是我們結(jié)合業(yè)務(wù)和團(tuán)隊(duì)實(shí)際情況進(jìn)行利益取舍后,供我們選擇的方案之一罷了。