從分層架構到微服務架構(二)之分層架構

《從分層架構到微服務架構》是一系列介紹《Fundamentals of Software Architecture》中提到的 8 種架構模式的文章,這裏不會事無鉅細地介紹所有的細節,而是會挑選其中關鍵內容,更多詳情請閱讀原書。

前言

軟件剛出現的時候,還是大型計算機的年代,一個軟件系統一般都只會運行在一臺機器上。隨着軟硬件技術的革新,計算機體積和成本逐漸變小,此時工程師們發現一個軟件系統只運行在單臺機器上會存在各種瓶頸。如果將系統按照功能劃分成前端和後端,分別部署在兩臺服務器上,問題得到了緩解,於是便有了 Client/Server 架構的出現。

隨後,個人電腦的興起帶動了衆多富桌面應用(rich  desktop application)的出現,它們基於操作系統上的 user interface 開發,數據則是存儲在單獨部署的 database server 上,通過標準的網絡協議進行數據通信。這種 Desktop + Database Server 的架構和 C/S 架構一樣,同屬兩層架構(two-tier architecture)。

隨着 90 年代互聯網的迅速崛起,Browser + Web Server + Database Server 的組合也漸漸風靡。Browser 爲表現層,提供用戶交互界面;Web Server 爲業務層,處理具體的業務邏輯;Database Server 爲數據層,存儲系統數據。三個層次各司其職,這也是大家最熟悉的三層架構(three-tier architecture)。

上述的幾種架構模式都屬於分層架構(layered architecture)的範疇,分層架構並沒有限定一定得有多少個層次,層次的數量可以根據應用場景靈活控制,因此也被稱爲 n-tier architecture。它結構簡單,基於此架構進行系統開發成本也很低(很多公司在組織結構上劃分爲前端工程師、後端工程師、DBA,根據康威定律,這天然就具備了分層架構開發的良好條件),因此它在業界備受歡迎。如果你的團隊還不確定選擇什麼樣的架構,又或者爲了踐行敏捷宣言中的 “just starts coding“,那麼分層架構會是一個不錯的選擇

架構視圖

在分層架構中,組件根據功能被劃分在不同的層次上,雖然層次的數量和類型並沒有被限制,但大多數的分層架構都由以下 4 層組成:表現層(presentation)、業務層(business)、持久層(persistence)和數據層(database),如下圖所示。在一些簡單的系統中,持久層的邏輯(如 SQL)被嵌入到業務層中,形成了經典的三層架構;而在一些複雜的系統中,也會根據具體的業務劃分爲五層甚至更多的層次。

分層架構的標準邏輯分層

前文所述的表現層等 4 個層次都是邏輯的劃分方法,在實際部署時,一般會有下圖所示的幾種部署形態。形態 1 中,表現層、業務層和持久層爲一個部署單元,而數據層則單獨部署,具體表現爲一個獨立部署的數據庫或文件系統;形態 2 中,表現層被分離出單獨部署,業務層和持久層組成一個部署單元,數據層依舊是單獨部署的數據庫或文件系統;形態 3 中,包括數據層在內的 4 層全都在同一個部署單元內,常見於業務簡單的系統,它們往往使用的是嵌入式數據庫或內存數據庫。

分層架構的部署形態

分層架構中的每一層都扮演着各自的角色,比如表現層負責處理所有的用戶請求和瀏覽器交互,而業務層則負責執行每次請求下的特定業務邏輯;表現層無需擔心從哪裏獲取用戶數據,它只需要將數據以特定的格式在瀏覽器上顯示即可。同樣地,業務層也無需關心用戶數據從何而來以及如何呈現,它只需從持久層中取出數據,執行特定的業務邏輯(比如聚合數據),然後將結果返回給表現層。

每一層都是特定行爲的抽象,這樣的職責劃分,使得組織能夠快速高效地創建出責任模型,圍繞各層打造開發團隊

層間隔離

分層架構中的每一層可以是封閉的或者開放的,封閉意味着當一個請求自頂向下在層間傳遞時,它不能跳過任意的一層。比如,當表現層接收到請求之後,它必須先後經過業務層和持久層才能到達數據層,如下圖所示。

封閉的分層架構

對於簡單的數據獲取類請求,如果讓表現層能夠直接訪問數據層獲取數據,無疑是最簡單高效的。也即是讓業務層和持久層變成開放狀態,允許請求在層間傳遞時跳過此層。那麼,究竟是封閉好,還是開放好呢?要解答這個問題,就要回到層間隔離的出發點上。

所謂的層間隔離,旨在降低一個層次上的變化對其他層次的組件的影響,簡單來說,就是每個層次對其他層次的功能知道的越少越好。爲了達到層間隔離的目的,就需要將每個層次置爲封閉的狀態。假設表現層能夠直接訪問持久層,那麼持久層的變化將會直接影響到業務層和表現層,這加劇了層間的耦合,導致系統變化的代價高昂。

層間隔離可以降低層次變化對系統的影響,凡事沒有絕對,在某些的場景,將特定的層次置爲開放的狀態也不失爲一件好事。考慮以下例子,業務層中存在着一些共享組件承載着業務層公共的功能(比如日誌類、審計類、日期和字符串工具類等)。現在有一項架構決策要求表現層不能直接訪問這些共享組件,但矛盾的是,原則上表現層是可以直接訪問業務層的,這種需要違反原則的決策將會很難落地。

業務層中的共享組件

一種解決方法是,新增一個服務層,該層包含了業務層的這些共享組件。因爲業務層是關閉的狀態,故表現層也就不能訪問到這些共享組件了。然而,新增的服務層必須置爲開放狀態,否則業務層將無法直接訪問持久層。新增一個服務層並置爲開放狀態,這樣既落地了架構決策,也不會影響到原有的功能,一舉兩得。

在分層架構中新增一個層次

一些注意事項

在使用分層架構時,需要注意以下兩點:

1、做好模塊的劃分

爲分層架構做好模塊劃分主要是爲後續的架構演進做好準備,比如在業務複雜到一定程度後演進爲微服務架構時,各個模塊可以很自然地演進爲微服務。爲此,應該避免出現類的繼承層次過深的現象,這會導致代碼嚴重的耦合,不利於後續的架構演進。

2、避免掉進 sinkhole 反模式的陷阱

所謂 sinkhole 反模式指的是請求只是簡單地路過各個層次,並沒有做一些業務處理。

比如,表現層接收到一個獲取基本用戶數據(姓名、地址等)的請求後將它傳遞到業務層;然而,業務層並沒有做任何的業務處理,直接將請求傳遞到持久層;持久層也僅僅是構造了一個簡單的 SQL 語句,向數據層查詢用戶數據;最後,數據按照原路返回到表現層,中途沒有經過任何的數據匯聚、轉換等操作。

sinkhole 反模式會導致很多不必要的對象實例化開銷,從而增大了系統的內存消耗,並且影響了性能

然而,一個系統多多少少都會存在一些 sinkhole 反模式場景,要判斷一個系統是否已經徹底掉進 sinkhole 反模式的陷阱,主要還是看這類業務請求所佔的百分比。根據 20-80 法則,當系統中有超過 80% 的業務請求是 sinkhole 類請求時,表示系統已經掉進 sinkhole 反模式的陷阱,這從側面也說明該系統已經不再適合分層架構,是時候考慮架構演進了。

綜合得分

分層架構的綜合得分

從綜合得分上看,分層架構的 Overall cost 和 Simplicity 得分很高,這很大程度上得益於分層架構本身是單體架構,少了很多分佈式系統纔有的複雜性。但這樣導致 Deployability 得分很低,因爲 3 行代碼的改動就足以造成整個系統的重新部署。Testability 得分不高也是這個原因,整系統的重新上線通常都需要將測試用例全部執行一遍,多了不少額外的工作量。

Elasticity、Fault tolerance、Scalability 這些都是單體架構天然的劣勢,自然地,分層架構在這些方面得分都很低。另外,sinkhole 反模式的存在也拉低了分層架構在 Performance 上的得分。

總結

分層架構簡單而高效,業界已經有很多成熟的應用,對那些項目剛剛起步,架構師們還沒想好要採用哪種架構模式的系統而言,這是非常適合的。在實現分層架構時,我們需要合理地設置各個層次的封閉或開放狀態,做好層間隔離,同時也要避免掉進 sinkhole 反模式陷阱。隨着業務的不斷擴張,分層架構在可維護性、可測試性、可擴展性等上的短板也會逐步被放大,此時就需要考慮往其他架構模式演進了。

每種架構模式都有其合適的應用場景,只有熟悉常用的幾種架構模式,才能設計出更好的軟件系統。下一篇文章,我們將繼續介紹管道架構

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/upSALrwyzE_qhtMZRDRLUg