架構模式的演變之路 從單體架構到微服務架構

2021-10-20 20:12:39 字數 4286 閱讀 2001

談到軟體系統設計的方**,在**層面,有我們熟悉的23種設計模式(design pattern),對應到架構層面,則有所謂的架構模式(architecture pattern)。它們分別從微觀和巨集觀的角度指導著我們設計出良好的軟體系統,因此,作為乙個軟體工程師,我們不僅要熟悉設計模式,對常見的架構模式也要熟稔於心。正如看到乙個設計模式的名字腦裡就能浮現出大致的結構圖,當我們看到乙個架構模式的名字時,也要馬上想到對應的架構圖及其基本特點。比如,當談到分層架構時,我們就應該想起它的架構圖是怎樣的、有哪些出色的架構特徵(architecture characteristics)、系統是如何部署的、資料儲存的策略是哪種、等等。

一般地,架構模式大致可以分成兩類,單體架構(monolithic architecture)和分布式架構(distributed architecture)。本系列文章將會介紹以下8種常用的架構模式:

分層架構(layered architecture)

管道架構(pipeline architecture)

微核心架構(microkernel architecture)

基於服務的架構(service-based architecture)

事件驅動架構(event-driven architecture)

基於空間的架構(space-based architecture)

面向服務的架構(service-oriented architecture)

微服務架構(microservices architecture)

在介紹架構模式前,我們先談談軟體設計中的謬誤(fallacy)。所謂謬誤,就是在設計軟體系統,特別是分布式系統時,我們先入為主地假設它們是正確,但實際上並非如此的一些觀念。這些觀念都是我們在設計軟體時考慮不周的體現。

網路是不可靠的

很多軟體工程師常常假設網路是可靠的,但實際並非如此。相比20年前,現在的網路會可靠很多,但是仍然具有很大的不確定性。如上圖所述,serivce b可能完全是正常執行的,但是因為網路的問題,service a發出的請求無法到達service b。一種更糟糕的場景是,service b可以收到service a的請求,並處理了相關的資料,但是網路問題導致了service a無法收到service b的響應,從而造成了資料不一致。網路的不可靠也是為什麼系統中常常出現服務通訊超時、服務熔斷等的原因。

總而言之,如果假設網路是可靠的,那麼我們設計出來的軟體系統將會是不可靠的。

時延不為0

如上圖所示,服務內元件間的函式/方法級別的呼叫,耗時是微秒,甚至是納秒級別;但是服務間的遠端呼叫(比如rest、訊息佇列、rpc),耗時會是毫秒級別,甚至在異常場景會達到了秒級!在設計系統,特別是分布式系統時,時延是乙個無法被忽視的因素,我們必須清楚系統的平均時延,否則設計出來的方案可能根本不可行。比如,假設系統中服務間通訊時延為100ms,如果乙個請求的呼叫鏈涉及到10個服務,那麼該請求的時延將會是1000ms!這麼高的平均時延對於一般系統來說是完全無法接受的。

進行系統設計時,考慮平均時延還不夠,更重要的是95th和99th百分點。乙個系統的平均時延可能僅僅只有數十毫秒,但是95th百分點的時延卻達到了數百毫秒,很多時候,這也恰恰成為了拖垮整系統效能的那塊「短板」。

頻寬是有限的

在單體架構中,業務流程都在單服務內閉環,消耗的頻寬很少甚至為0,因此頻寬並不是主要關注點。一旦將系統拆分成分布式架構,乙個業務流程可能涉及多個服務間的通訊,頻寬就成了必須考慮的因素。頻寬的不足,會導致網路變慢,從而影響系統的時延(謬誤2:時延是0)和可靠性(謬誤1:網路是可靠的)。

如上圖所示,假設在乙個web系統中,service a負責處理前端請求,service b負責管理使用者資訊(包括姓名、性別、年齡等45個屬性)。service a每處理乙個請求都需要向service b查詢使用者姓名(200 bytes),而在一次請求中,service b卻返回了使用者的所有資訊(500 kb)。如果系統每秒處理2000次請求,每次請求消耗500 kb頻寬,那麼每秒消耗的總頻寬會是1 gb!如果service b僅僅返回必須的姓名,那麼同等條件下,每秒消耗的總頻寬僅僅是400 kb。

網路是不安全的

vpn、防火牆等的廣泛使用,使得很多任務程師在設計系統時忽略了「網路是不安全的」這一重要原則。特別是從單體架構演進到分布式架構以後,系統被攻擊的概率將會大大增加。因此,在分布式系統中,每個服務都必須是安全的endpoint,這樣才能確保任何未知或惡意的請求都被攔截掉。當然,安全是有代價的,這也是像微服務架構這類細服務粒度的系統,一次業務請求中呼叫鏈過長後效能極速下降的重要原因。

網路拓撲是時常變化的

這裡的網路拓撲指的是系統執行時所涉及到的網路裝置,包括所有的路由器、防火牆、集線器、交換機等。很多任務程師會假設網路拓撲是固定的,然而並非如此。

假設如下場景,為架構師的你在周一早上回到公司後,發現組內同事都在為系統中所有的服務間通訊都在不斷出現響應超時現象而抓狂,但奇怪的是週末並沒有做服務變更。經過幾個小時的攻關後,你發現周一凌晨2點時有過一次網路公升級,而恰恰是這次「次要」的網路公升級,推翻之前設計系統時的時延假設,從而觸發了本次事故。

因此,軟體工程師也需要與網路管理員時常聯絡,確保在每次網路公升級前都明確網路拓撲的變更點,從而做出相應的調整。

不只有乙個網路管理員

網路管理員往往不止有乙個,特別是在「雲」時代,資料中心分散在多個地域,理所當然也存在著多個區域網。執行在「雲」上的系統很有可能跨越多個資料中心,因此工程師們應當感知各個資料中心的網路管理員對網路的相關操作,提前做出應對措施,避免出現因網路拓撲變更(謬誤5:網路拓撲一成不變)而導致的服務通訊超時,甚至觸發服務熔斷。

通訊成本不為0

這裡的通訊成本並非指網路時延,而是指每增加一次服務間呼叫所導致的錢的花銷。很多任務程師在設計系統時常常忽視掉通訊成本,大家都在鼓吹分布式架構相對了單體架構的優越性,卻忘記了它帶來的伺服器、防火牆、閘道器等硬體的數量增加,這些都是白花花的銀子。

因此,在進行系統設計時,我們也應該將硬體資源和網路拓撲納入考慮因素。

網路並非同質的

很多任務程師都會假設網路是同質的,也就是所有的網路裝置都來自同一硬體廠商,這當然也是乙個謬誤。實際上,乙個大的通訊網路中,硬體裝置往往來自於不同的廠商,這得益於網路協議標準的統一。廠商間裝置的協作測試畢竟不會太充分,在一些特殊場景下極有可能存在網路丟包,從而影響了網路的可靠性(謬誤1:網路是可靠的)、時延(謬誤2:時延是0)以及頻寬(謬誤3:頻寬是無限的)。

「大泥球」架構是著名的反模式架構,最初在2023年由brian foote 和 joseph yoder提出。在「大泥球」架構裡,系統沒有進行內部的模組劃分,**耦合嚴重,呼叫關係混亂,就像乙個大的泥球。如上圖所示,每乙個點代表乙個類,紅線則表示類之間的耦合關係。這樣的架構對需求變更極不友好,往往牽一髮而動全身,而且在部署、可測試性、效能等方面也存在著很多問題。所有的架構師都在極力避免「大泥球」的出現,但很不幸的是,它仍然在實際專案中很常見,特別是專案伊始,**質量和結構還沒被嚴格管控起來前。

跟設計模式類似,架構模式是軟體工程師們多年來在架構設計方面的經驗總結。每種架構模式並沒有絕對的優劣之分,我們不能說微服務架構就一定比單體分層架構優越,它們都有著各自的應用場景。分布式架構比單體架構有著更好的可擴充套件性、容錯性,但也帶來了更高的複雜性,比如分布式事務。因此,我們應該熟知各個架構模式的特點,這樣才能在特定的業務場景使用合適的架構模式。

架構之路 MVVM架構模式

model層就是職責資料的儲存 讀取網路資料 運算元據庫資料以及i o,一般會有乙個viewmodel物件來呼叫獲取這一部分的資料。view層做的僅僅和ui相關的工作,我們只在xml activity fragment寫view層的 view層不做和業務相關的事,也就是我們的activity 不寫和...

從0開始學架構 高效能架構模式

目錄 儲存高效能 關係型資料庫 nosql 快取 計算高效能 單伺服器高效能 集群高效能 讀寫分離 一主多從,一主一從 主從複製延遲解決方案 1.寫操作後的讀操作指定發給資料庫主伺服器 2.讀從機失敗後再讀一次主機 3.關鍵業務讀寫操作全部指向主機,非關鍵業務採用讀寫分離 分庫分表 業務分庫 joi...

《從0開始學架構》 02 高效能架構模式

目錄 讀寫分離 資料庫主從集群 一主一從或一主多從 主負責讀寫 從僅負責讀 適用場景 分散了資料庫讀寫操作的壓力,適用於讀多寫少的情況。兩個設計細節點 主從複製延遲問題和實現方式 1 主從複製延遲 2 實現方式 使用場景 分散了資料庫的儲存壓力。分庫 按業務模組將資料分散到不同資料庫上。帶來的問題 ...