單體架構——一個可部署單元,一個資料庫
在一張互動畫布上呈現單體架構:一個可部署的應用程式,內含 UI、業務邏輯與資料存取模組,一個共用資料庫,以及由此而來的擴展天花板。
單體是一個以單一單元建置並部署的應用程式:UI、業務邏輯與資料存取全部在同一個處理程序中運行,對著一個共用的資料庫,而擴展就意味著複製整件東西。
單體架構——一個可部署單元,一個資料庫
The interactive FlowJam canvas for this explanation — every lane, row and arrow above is a real QueryChart diagram you can open and edit.
How to read this visual
- 跟著請求由用戶端進來,向下穿過三個模組,進入那個共用的資料庫,再走出去——在同一個處理程序裡的一趟來回。
- 各個模組之所以在「單體應用程式」那一帶之內,是因為它們共用一個處理程序與同一次部署;這種包覆關係就是單體的定義。
- 最後那個方框就是結論:擴展的路徑在旁邊,做的是複製整個應用程式。
在同一個處理程序中的請求路徑
「用戶端送出一個請求」進入「請求進入那個單一可部署的應用程式」,然後是「UI 模組負責路由與呈現」、「業務邏輯模組處理它」與「資料存取模組查詢資料庫」——全部都在那唯一一條「單體應用程式」泳道之內。三個模組被畫成疊在一起,是為了顯示它們共用記憶體、共用一個處理程序、共用同一次部署:當中沒有任何一個是可以分開部署的。
共用的資料庫
「一個共用的資料庫儲存全部東西」是單體的第二項界定特徵。所有模組讀寫同一份結構描述,令連接查詢與交易都變得直接了當——這就是單體在早期如此高產的原因。「資料庫」群組坐落在應用程式那一帶之外,因為它是一個獨立的處理程序,但它是共用的:耦合就住在每一個模組都依賴的那份結構描述裡。
擴展的天花板
「回應沿著同一批模組傳回」令這趟來回完成,而「擴展意味著複製整個應用程式」就是判詞。一項繁忙的功能迫使整個代碼庫連同它的連線池被搬到另一部伺服器上,把容量浪費在那些並不繁忙的部分。最終促使團隊拆成微服務的,是這種低效,而不是任何技術上的故障。
Key relationships and takeaways
- 所有模組共用一個處理程序、一個代碼庫與同一次部署——這種包覆關係就是定義。
- 那個共用的資料庫把每一個模組都耦合到同一份結構描述之上。
- 請求在一趟來回中穿過每一個模組——沒有獨立的服務呼叫。
- 擴展是粗顆粒的:整個應用程式都會被複製一份,不論那項功能是否繁忙。
- 單體的開發速度是真實的;它拿去交換的,就是那道擴展天花板。
When to use this visual
- 解釋為甚麼一個團隊的應用程式明明容易開發,卻難以擴展。
- 講解那種令微服務變得可以理解的對照——只有對著單體的天花板來看,拆分才說得通。
- 在規劃如何把一個舊有系統拆開之前,先記錄它的結構。
運作方式
把模組改名成你自己的代碼庫
把 UI、業務邏輯與資料存取換成你真實的分層與模組,並補上這三項通用模組未涵蓋的部分。
標出真實的擴展瓶頸
在最後那個方框上標註真正逼你擴展的那項功能或那條查詢,以及複製整個應用程式所浪費掉的容量。
畫出可抽取的候選模組
在那個最適合變成一項服務的模組外圍加上一道虛線邊界,並附註要切斷哪些耦合。
連到微服務這個替代方案
候選模組標好之後,連到微服務那張圖解,把目標架構並排比較。
常見問題
甚麼是單體架構?
單體是一個把 UI、業務邏輯與資料存取當成一個單元去建置、部署與擴展的應用程式——單一代碼庫產出單一可部署的產物,並對著一個共用的資料庫運行。圖解顯示請求在同一條應用程式泳道之內穿過全部三個模組,因為這種包覆關係就是定義。
團隊為甚麼會由單體開始?
因為對大多數團隊、以及應用程式生命中的大部分時間而言,單體是最快出貨的方式。模組之間沒有網絡,共用的結構描述令連接查詢與交易都變得簡單,部署也只有一份產物。圖解中那個共用資料庫的方框直接點明了這一點——只有當獨立擴展或團隊自主成為關鍵瓶頸時,這場交換才會變得不划算。
單體最主要的問題是甚麼?
擴展天花板與耦合。擴展意味著複製整個應用程式,所以一項繁忙的功能會在其餘一切之上浪費容量;而每一次改動,觸碰的都是所有人都依賴的同一個代碼庫與同一份結構描述。隨著團隊與代碼庫變大,這兩種效應會拖慢部署並逼出協調成本——這正是團隊開始把服務抽出來的條件。
單體怎樣變成微服務?
逐步地,每次抽出一項能力。第一步是找出一個可以獨立存在的模組——它有自己邊界明確的資料——然後給它自己的資料庫、一個 API,最終是獨立部署。圖解中那個抽取候選模組的步驟示範的正是這件事:標出模組、切斷耦合、拆開。錯誤的做法是一次過重寫整個單體,遷移正是這樣失敗的。
用 QueryChart(FlowJam)編輯這張圖解
把上面這張單體畫布開啟為你自己的圖表——把模組改名成你代碼庫裡的模組,並把你的擴展瓶頸畫出來。