Serverless單體架構(gòu)的崛起
在過(guò)去的幾十年里,我們見(jiàn)證了應(yīng)用架構(gòu)以快速的速度演變。當(dāng)我還是一個(gè)年輕的程序員時(shí),開(kāi)始編寫(xiě)一個(gè)簡(jiǎn)單的代碼庫(kù),我們可以稱之為單體應(yīng)用。
我記得為前端編寫(xiě)了一些HTML/CSS,后端用了一些Java。但后來(lái),隨著時(shí)代發(fā)展和需求改變,分布式架構(gòu)(我們現(xiàn)在稱之為“微服務(wù)”)應(yīng)運(yùn)而生。
單體應(yīng)用的衰落
這暫且不談單體應(yīng)用如何變得越來(lái)越不受歡迎,但需要開(kāi)發(fā)者開(kāi)始鼓吹微服務(wù)卻是事實(shí)。
通常,微服務(wù)提供了以下好處:
- 微服務(wù)更小,更容易維護(hù)。
- 減少了團(tuán)隊(duì)之間的摩擦。每個(gè)團(tuán)隊(duì)可以獨(dú)立地處理每個(gè)微服務(wù)。
- 編寫(xiě)速度更快(不需要遵循現(xiàn)有且有時(shí)繁瑣的架構(gòu))。
- 團(tuán)隊(duì)使用最適合任務(wù)的工具(例如,處理大量JSON數(shù)據(jù)?也許可以使用Node.js。需要高性能?也許可以考慮Rust。只有Ruby開(kāi)發(fā)者?那么Ruby似乎是解決方案)。
- 減少認(rèn)知負(fù)荷,這意味著每個(gè)開(kāi)發(fā)者只需要了解代碼的一個(gè)子集,而不是整個(gè)代碼庫(kù)。
關(guān)于微服務(wù)的誤解
然而,經(jīng)?;蛘哂袝r(shí),過(guò)度使用微服務(wù)也存在一些缺點(diǎn):
- 代碼重復(fù):一些代碼(數(shù)據(jù)或函數(shù))在多個(gè)倉(cāng)庫(kù)之間重復(fù)出現(xiàn),這會(huì)導(dǎo)致共享庫(kù)與單一倉(cāng)庫(kù)的分歧和爭(zhēng)論。
- 事務(wù)處理復(fù)雜:處理多個(gè)微服務(wù)之間的事務(wù)具有一定的挑戰(zhàn)性,并需要額外的模式(Saga、事件溯源等)。
- 增加認(rèn)知負(fù)荷:取決于上下文的不同,可能會(huì)極大地增加認(rèn)知負(fù)荷。每個(gè)開(kāi)發(fā)人員不僅需要知道微服務(wù)能夠做什么/應(yīng)該做什么,還需要知道它可以/應(yīng)該與哪些其他微服務(wù)進(jìn)行通信。
- 易受故障影響:在幾乎所有的場(chǎng)景中,都更容易受到故障的影響:數(shù)據(jù)庫(kù)連接、網(wǎng)絡(luò)延遲、緩存、異常等。
但是,任何明智的開(kāi)發(fā)者都會(huì)告訴你,對(duì)于任何架構(gòu)選擇,答案總是“看具體情況”。
單體與微服務(wù)的平衡
單體與微服務(wù)之爭(zhēng)中,一個(gè)設(shè)計(jì)良好的、高度解耦的架構(gòu)只需要處理最多四個(gè)不同的部分:
- UI,也稱為前端(front-end)
- BFF,即面向前端的后臺(tái)(Backend For Frontend),或者說(shuō)是單一前端的后端(Backend for a Single Frontend, BSF)
- 傳統(tǒng)后端,充當(dāng)前端和數(shù)據(jù)之間的粘合劑。稱之為 BFD (Backend For Database) 或多BSF的后端。
- 數(shù)據(jù)庫(kù),也稱為數(shù)據(jù)庫(kù)及其查詢機(jī)制。
圖片
完全解耦的微服務(wù)架構(gòu)的表示
從熟悉的模式中,我們已經(jīng)擁有合適的技術(shù)棧:
- 前端框架(Angular、React、Vue、Svelte 等)
- 使用適當(dāng)技術(shù)的 BFF(簡(jiǎn)單的 REST API?node.js 中的 GraphQL 服務(wù)器?)
- 一個(gè)傳統(tǒng)的后端(暫且稱之為BFD),再次使用適當(dāng)?shù)募夹g(shù)(另一個(gè)REST API?一個(gè)高性能的gRPC服務(wù)器?)
- 最后是所需的最小數(shù)據(jù)庫(kù)數(shù)量(關(guān)系數(shù)據(jù)庫(kù)和/或文檔數(shù)據(jù)庫(kù)和/或圖數(shù)據(jù)庫(kù)和/或搜索引擎)
如果我們重視簡(jiǎn)單性,還有改進(jìn)的空間。我們還應(yīng)該商定需要技術(shù)棧的每個(gè)部分的比例:
- 至少一個(gè)前端,但你可以無(wú)限擴(kuò)展這個(gè)數(shù)字,無(wú)論是在編寫(xiě)微型前端、大量的 web 應(yīng)用程序,還是兩者兼而有之
- 一個(gè)前端 = 一個(gè) BFF,如果我們遵循邏輯
- 一個(gè)傳統(tǒng)的后端,你可以根據(jù)需要將其拆分成 N 個(gè)微服務(wù)。但是,如果我們使用單體架構(gòu),那就說(shuō) 1 個(gè)吧。
- 每個(gè)類型的數(shù)據(jù)庫(kù)至少一個(gè)。假設(shè)我們需要 3 種類型的數(shù)據(jù)庫(kù)來(lái)滿足中等規(guī)模的應(yīng)用程序。
圖片
N = (2 * UI) + (1 * BFD) + (3 * DB)
正如俗話所說(shuō),“少即是多”,因此我們的目標(biāo)是嘗試將這個(gè)數(shù)字 (N) 減少到絕對(duì)最低。
進(jìn)入Serverless單體架構(gòu)時(shí)代
前端元框架的興起
過(guò)去我們見(jiàn)證了一個(gè)令人難以置信的演變,那就是誕生了眾多前端元框架。其中最著名的有 Next.js、Remix 和 SvelteKit。
一個(gè)元框架的目標(biāo)是同時(shí)處理前端的前端和后端(是的,當(dāng)你這樣說(shuō)的時(shí)候,這聽(tīng)起來(lái)并不聰明)。換句話說(shuō),這意味著使用單一技術(shù)構(gòu)建 UI + BFF。
而且,由于如今的云和托管解決方案,我們可以輕松以無(wú)服務(wù)器模式部署元框架。
BFD和元框架單體架構(gòu)
N = META-FRAMEWORK + (1 * BFD) + (3 * DB)
從這里開(kāi)始,我們?yōu)槊總€(gè)前端減少了 1 個(gè)技術(shù)!
Serverless數(shù)據(jù)庫(kù)時(shí)代
目前,圍繞數(shù)據(jù)庫(kù)作為服務(wù)(DaaS)的解決方案或者說(shuō)后端作為服務(wù)(BaaS)正在興起。BaaS的目標(biāo)是提供應(yīng)用程序所需的所有功能,以便你無(wú)需在后端編寫(xiě)一行代碼。你只需要在你的BFF中編寫(xiě)查詢,就完成了。
最著名的BaaS無(wú)疑是Firebase,它提供了許多功能,如實(shí)時(shí)文檔數(shù)據(jù)庫(kù)、身份驗(yàn)證服務(wù)、數(shù)據(jù)庫(kù)之上的權(quán)限機(jī)制、文件系統(tǒng)存儲(chǔ)等等。
然而,F(xiàn)irebase也有一些嚴(yán)重的限制:
- Firebase 數(shù)據(jù)庫(kù),無(wú)論是 Realtime 數(shù)據(jù)庫(kù)還是 Firestore,都是單模型數(shù)據(jù)庫(kù)(文檔數(shù)據(jù)庫(kù))。
- 它只能作為一個(gè)單向圖進(jìn)行遍歷(如果我們可以將其視為圖的話)。
還有另一個(gè)叫做Supabase的著名BaaS,試圖與Firebase相媲美。使用類似PostgreSQL的關(guān)系型數(shù)據(jù)庫(kù)消除了Firebase的一些限制,但它仍然是單模型數(shù)據(jù)庫(kù)...
最近引起我注意的一個(gè)項(xiàng)目是SurrealDB。它是一個(gè)帶有內(nèi)置后端的數(shù)據(jù)庫(kù),具有許多許多功能(我覺(jué)得“許多”這個(gè)詞寫(xiě)得還不夠)。作為一個(gè)真正的多模型數(shù)據(jù)庫(kù),并且有一種新的查詢語(yǔ)言,他們能夠提供應(yīng)該讓你寫(xiě)一些代碼的功能。
最近,這種類型的數(shù)據(jù)庫(kù)被越來(lái)越廣泛地稱為元數(shù)據(jù)庫(kù)。
完全單體架構(gòu)
N = META-FRAMEWORK + META-DATABASE
從那里開(kāi)始,我們?cè)诹硪粋€(gè)層面上大大減少了技術(shù)數(shù)量。
附加內(nèi)容:利用單一倉(cāng)庫(kù)架構(gòu)
與微服務(wù)一樣,編寫(xiě)單體應(yīng)用意味著擁有正確的工具箱。這個(gè)工具箱可以解決我們通常遇到的約束,比如:
- 太龐大以至于無(wú)法失敗,一個(gè)簡(jiǎn)單的錯(cuò)誤可能會(huì)導(dǎo)致整個(gè)服務(wù)崩潰。
- 長(zhǎng)時(shí)間部署,編譯大型項(xiàng)目通常需要很長(zhǎng)時(shí)間。
- 無(wú)法跨團(tuán)隊(duì)隔離和共享的單一代碼庫(kù)。
使用這種架構(gòu),對(duì)純凈和全面的單體架構(gòu)(前端 + 后端)的需求就不再存在。然而,元框架是超過(guò) 80% 的代碼將駐留的部分。為此,現(xiàn)在有一些工具可以使用,例如 turborepo。
我們還沒(méi)有提到的一個(gè)不可避免的需求是數(shù)據(jù)庫(kù)腳本遷移。當(dāng)然,這些腳本需要存儲(chǔ)在單獨(dú)的倉(cāng)庫(kù)中,沒(méi)有什么復(fù)雜的。