從單體到微服務(wù),這些年架構(gòu)的演變

這兩年業(yè)界最流行的技術(shù)架構(gòu)話題已經(jīng)從前后端分離,變成了分布式、微服務(wù)、DDD了。微服務(wù)架構(gòu)適合所有的公司嗎,業(yè)務(wù)場景演變到了什么地步才需要考慮上微服務(wù)呢?畢竟選擇技術(shù)架構(gòu)之前應該考慮業(yè)務(wù)是否與之匹配,否則分布式、微服務(wù)這類繁重的架構(gòu)設(shè)計對一些公司來說就變成了屠龍之技,反而成為一線開發(fā)團隊的負擔。

在我不長的職業(yè)生涯中,經(jīng)歷過小型創(chuàng)業(yè)公司、國企般的大型項目以及在ThoughtWorks見到的各種項目。架構(gòu)就像一個雜貨鋪,微服務(wù)也只是工具箱,不能有了錘子滿世界找釘子,有可能人家只是一顆螺絲釘在等待改錐。

我想嘗試讓架構(gòu)這個概念變得更為通俗,原諒我文中出現(xiàn)大量不恰當?shù)谋扔?。為了描述常見互?lián)網(wǎng)公司技術(shù)架構(gòu)演變過程,這里設(shè)定了一個虛擬背景:

Neo是一名軟件工程師,畢業(yè)后就留在這個城市加入了一家互聯(lián)網(wǎng)創(chuàng)業(yè)公司,公司的業(yè)務(wù)是從事面向餐廳的食材配送服務(wù),用戶可以從APP或者微信提前訂購食材,公司會在次日早晨送達。使用了Java + MySQL的技術(shù)棧,目前來說還只是使用了一臺服務(wù)器,并且數(shù)據(jù)庫和應用程序都還是部署在同一臺服務(wù)器上。

因為用戶增加和業(yè)務(wù)逐漸變得復雜,Neo的團隊遇到的第一個問題就是需要對系統(tǒng)擴容,提高系統(tǒng)響應速度。擴容對于互聯(lián)網(wǎng)公司來說一般就是“加機器”,那么第一步,怎么加機器呢?

單數(shù)據(jù)庫多應用服務(wù)架構(gòu)

增加機器方案的時候,我第一時間想到的是軟件園餐廳的工作模式了。

軟件系統(tǒng)用戶就像來餐廳吃飯的顧客,而服務(wù)器就像服務(wù)員,本來服務(wù)員既可以收費也可以售賣菜品,就像有時我們在同一臺服務(wù)器上同時部署了應用代碼和數(shù)據(jù)庫。如果在服務(wù)員同時承擔結(jié)賬和售飯職責的模式上增加人手的話,效率不高且最終的賬目很可能無法保持一致,因此餐廳一般會有多個服務(wù)員售飯,然后由專人負責結(jié)賬。

回到我們的架構(gòu)問題上來,如果我們需要多臺服務(wù)器響應更多的用戶,同時也要保證數(shù)據(jù)的一致性。根據(jù)數(shù)據(jù)庫的范式理論,數(shù)據(jù)的冗余性越低數(shù)據(jù)的一致性就越高。因此我們的第一步方案可以剝離為多個應用服務(wù)器處理用戶的請求,一臺數(shù)據(jù)庫服務(wù)器來集中處理數(shù)據(jù)的讀寫,這樣就能夠達到分攤服務(wù)器壓力的同時也能保證數(shù)據(jù)的正確。

不過在應用服務(wù)器的入口,我們需要增加一個負載均衡服務(wù)器,來分配不同的用戶請求到特定的應用服務(wù)器上。這有點類似于餐廳的排隊機,對用戶分流。負載均衡服務(wù)器可以是普通PC服務(wù)器上配置Nginx一類的軟件,也可以是F5這類專用的硬件負載均衡設(shè)備。


image1.png
image1.png

Neo的團隊花了半個月的時間重新部署了這些服務(wù)器,通過剝離數(shù)據(jù)庫和增加應用服務(wù)器的方式提高了系統(tǒng)性能。

讀寫分離的數(shù)據(jù)庫架構(gòu)

時間很快過去了半年,Neo的公司又增加了很多新的業(yè)務(wù),系統(tǒng)也增加了更多的功能。預定蔬菜的商戶也可以通過手機查看歷史訂單和各種統(tǒng)計信息了,這個時候Neo發(fā)現(xiàn)即使怎么增加應用服務(wù)器,也會出現(xiàn)用戶需要等待很長的時間,最終數(shù)據(jù)庫也出現(xiàn)了瓶頸。

數(shù)據(jù)庫是分布式架構(gòu)中最難的問題,因為不像應用服務(wù)器是不保存數(shù)據(jù)的。如果想要增加數(shù)據(jù)庫服務(wù)器的數(shù)量,那么首先需要解決數(shù)據(jù)重復和一致性的問題。現(xiàn)實中對應的方案有很多,例如讀寫分離、數(shù)據(jù)庫物理分區(qū)、邏輯分表、邏輯分庫,但本質(zhì)上講只是拆分數(shù)據(jù)庫操作的方式不同而已,而我們應對數(shù)據(jù)庫性能最常用和性價比最高的方式是讀寫分離。

這里我又忍不住使用一個美食城的例子來說明數(shù)據(jù)庫讀寫分離的思想了。

上文中我們提到數(shù)據(jù)的集中處理,一開始這樣是挺有效的,但是隨著用戶的增多,負責處理數(shù)據(jù)的服務(wù)器還是忙不過來。同樣的例子對于現(xiàn)實生活,很多美食城這類流量更大的場景,出現(xiàn)了另一種運作方式,美食城一般由管理公司和各個商戶構(gòu)成。消費者需要首先到管理公司設(shè)置的充值點充值,然后到各個商戶刷卡消費,結(jié)賬的人員只需要寫入充值數(shù)據(jù),然后每個商戶都能讀取數(shù)據(jù)。

因為數(shù)據(jù)的讀取需要耗費大量的計算資源,而又不需要對數(shù)據(jù)進行修改操作,我們可以考慮把數(shù)據(jù)庫的讀和寫這兩種操作拆開。


image2.png
image2.png

我們可以使用數(shù)據(jù)庫的主從架構(gòu)來增加讀的服務(wù)器,主數(shù)據(jù)庫保證數(shù)據(jù)的一致性,使用從服務(wù)分擔查詢請求,主服務(wù)器會把數(shù)據(jù)同步到從服務(wù)器中實現(xiàn)數(shù)據(jù)的最終一致性。當然這個架構(gòu)可以還是會遇到性能瓶頸,不過可以暫時用上很長一段時間了。

當然如果配上緩存,靜態(tài)文件分離,性能會得到進一步提升。一般的項目到達這一步足以應對大多數(shù)的需求。

image3.png
image3.png

不過隨后的日子里,產(chǎn)品經(jīng)理提出需要給食材訂購的頁面中提供視頻介紹,于是系統(tǒng)中出現(xiàn)了大量耗費計算資源或者耗時的視頻轉(zhuǎn)碼操作。

使用消息隊列的架構(gòu)

電影《讓子彈飛》中有一句經(jīng)典的臺詞,“讓子彈飛一會兒”。程序世界和現(xiàn)實生活總是相似的,如果我們要去郵局寄出一封郵件,或者是到快遞公司寄出一件包裹,我們不必等待郵件或者包裹到達了收件人手上我們才離開,這可得花好幾天。

相應的系統(tǒng)中往往存在這種類似的場景,當我們視頻網(wǎng)站上傳了一條視頻后,視頻網(wǎng)站往往會進行轉(zhuǎn)碼以便適合網(wǎng)絡(luò)播放,這種操作需要耗費大量的服務(wù)器資源,不可能實時的在用戶點擊提交后處理完畢,否則用戶需要等待很久,甚至連接超時。


image4.png
image4.png

對于這種應用場景,我們可以讓此類任務(wù)不必是實時完成的。當用戶提交請求后,系統(tǒng)會把任務(wù)添加到消息隊列中,完成之后改變數(shù)據(jù)的狀態(tài),用戶在刷新或接到通知后知道任務(wù)已經(jīng)處理完畢。

前面說的系統(tǒng)架構(gòu),應用服務(wù)器只是被克隆多個然后分別部署不同的,每一臺應用服務(wù)器上的代碼都是一模一樣。就像原始生物真菌,細胞沒有分化所有的細胞都具有同樣的功能,從這一節(jié)起,不同應用服務(wù)器承擔的職責開始變化,就像植物的出現(xiàn)讓細胞開始分化。

隨著業(yè)務(wù)的發(fā)展,Neo的公司開始向新的領(lǐng)域擴張,開發(fā)了拓展更多商戶的代理平臺和物流平臺,甚至需要和和第三方平臺對接,而且需要保證這些平臺中一些通用的數(shù)據(jù)和邏輯是一致的。

面向服務(wù)的架構(gòu)(SOA)

如果大家看過動漫《工作細胞》,一定會對萌萌噠的血小板妹妹印象深刻,《工作細胞》通過動漫擬人的方式講述了人體中不同細胞的職責和工作方式。每種細胞都有自己獨特的功能,血小板負責止血和修復創(chuàng)傷,而T細胞負責吞噬異物和發(fā)現(xiàn)入侵者。

軟件系統(tǒng)變得越來越復雜,參與的開發(fā)者就越多,應用系統(tǒng)的分離和分化就變得很有意義了。面向前端的API應用服務(wù)器不再真正的處理業(yè)務(wù)邏輯而是調(diào)用專門的服務(wù)器來完成。

單點登錄(SSO)是一個典型的面向服務(wù)的架構(gòu),在互聯(lián)網(wǎng)公司中被廣泛使用。國內(nèi)互聯(lián)網(wǎng)巨頭往往擁有多個系統(tǒng),例如騰訊的QQ音樂、空間都可以使用同一個QQ號登陸。于是用戶服務(wù)和認證服務(wù)被剝離開來,各個系統(tǒng)之間通過統(tǒng)一登錄和管理用戶信息,用戶的體驗得到了極大的提升,這就是面向服務(wù)架構(gòu)的一個例子。

image5.png
image5.png

這些大廠不僅在自己的系統(tǒng)內(nèi)完成了統(tǒng)一的認證和用戶管理,并且把登錄、授權(quán)的服務(wù)開放給第三方系統(tǒng)。例如很多網(wǎng)站支持微信登錄,這樣用戶就可以使用一套用戶名密碼登錄大量接入的系統(tǒng)。并且業(yè)界有一個通用規(guī)范,便于各種系接入,這就是OAuth標準。

image6.png
image6.png

服務(wù)調(diào)用有很多種方式,根據(jù)不同的網(wǎng)絡(luò)協(xié)議使用RPC框架或者直接使用HTTP請求。

Neo的公司通過面向服務(wù)的架構(gòu)改造,系統(tǒng)中分化出了用戶服務(wù)、物流服務(wù)、訂單服務(wù)等服務(wù),通過OAuth的方式提供了收銀機系統(tǒng)認證對接。一些收銀機廠商也對接了這個系統(tǒng),商戶可以通過支持的收銀設(shè)備進行下食材的預定操作了。

微服務(wù)架構(gòu)

隨著Neo的公司急速發(fā)展,越來越多的業(yè)務(wù)需求被加入到系統(tǒng)中,系統(tǒng)已經(jīng)變得極為龐大。 不同應用和數(shù)據(jù)之間互相依賴,邏輯糾纏不清,項目的部署進入了混沌狀態(tài),對于大型、依賴關(guān)系復雜的系統(tǒng)需要一個更為有力的架構(gòu)。為了解決系統(tǒng)復雜性和服務(wù)解耦的問題,這時候該微服務(wù)和領(lǐng)域驅(qū)動建模(DDD)出場了。

微服務(wù)大家都知道來自于Martin Fowler所創(chuàng)造并隨之流行起來的概念。上面說的各種架構(gòu),應用之間依然強關(guān)聯(lián)到一起,即使被拆分出來也是作為系統(tǒng)組件看待的,很難獨立運行。

微服務(wù)的設(shè)計目的是為了讓大型軟件系統(tǒng)解耦。將不同職責的服務(wù)獨立部署,從而實現(xiàn)服務(wù)內(nèi)部高內(nèi)聚,服務(wù)之間低耦合的效果,讓開發(fā)變得更為靈活。當然“分開是為了更好的在一起”,為了重新組合和穩(wěn)定運行這些服務(wù),人們發(fā)明了服務(wù)發(fā)現(xiàn)、熔斷機制、服務(wù)部署監(jiān)控等一籃子工具。

曾經(jīng)和同事開玩笑,微服務(wù)做的最好的是一個國家的政府。相信所有人都去過政務(wù)中心,當你需要辦理一個戶口或者其他市政業(yè)務(wù)時,政務(wù)大廳運轉(zhuǎn)的像極了一個軟件系統(tǒng)。

大廳的簽到處就像一個API gateway,幫你排號的同時需要你的身份證(認證),如果發(fā)現(xiàn)你不符合這個地區(qū)的辦理條件(授權(quán)或scope),會直接拒絕你。在給多個人排號的時候會分配到不同的窗口,這時候你感覺面對的不是前臺的小姐姐而是一臺輪詢策略的負載均衡服務(wù)器。有些業(yè)務(wù),受理業(yè)務(wù)的窗口并不會真的處理,而是提交到專門處理的部門,窗口對你來說就是BFF(Backend for Frontend)。真正受理業(yè)務(wù)的部門處理完成后會把資料遞交到檔案室,如同數(shù)據(jù)庫的讀寫一般。系統(tǒng)中某個部門因故暫停了工作,會帖出告示(熔斷)。當然這樣的例子太多太多,不再贅述。

image7.png
image7.png

微服務(wù)甚至不是一個架構(gòu),而是像一個生態(tài),應用與應用之間互相獨立,卻又彼此依賴。通過DDD的模型來設(shè)計一個地圖,把合適的代碼放到合適的地方去。實現(xiàn)微服務(wù)涉及的工具太多,其中我省略了部分,以求讓架構(gòu)看起來更加清晰。

架構(gòu)的迷思

原支付寶架構(gòu)師周愛民老師曾說,“真正的架構(gòu)師沒有title”。然而更甚一步,其實IT系統(tǒng)的架構(gòu)也沒有title,每個公司的架構(gòu)都是唯一的、混合的、適合業(yè)務(wù)需要的,很難說我們目前的架構(gòu)就是標準的“微服務(wù)”,一個“標準的微服務(wù)”有時候可能對一線開發(fā)的小伙伴會很難受。

架構(gòu)也很難一開始就設(shè)計的完美,架構(gòu)不是設(shè)計出來的,甚至不能被設(shè)計,只能在需求的變化中不斷演進。架構(gòu)師的工作不太像建筑師那樣構(gòu)建大的藍圖,更像藥劑師那樣對癥治病、照方抓藥。就像《大教堂與集市》說的那樣,“軟件很大程度上是一個服務(wù)行業(yè),雖然長期以來都毫無根據(jù)地被錯認為是制造行業(yè)?!?/p>

就像生命在自然環(huán)境中不斷適應,才得以演化;我們的架構(gòu)需要根據(jù)需求中不斷改進,才得以敏捷。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容