分層架構 (Layered Architecture)
分層架構是最常見的架構,也被稱為n層架構。多年以來,許多企業和公司都在他們的項目中使用這種架構,它已經幾乎成為事實標准,因此被大多數架構師、開發者和軟件設計者所熟知。比如MVC。
分層架構的一個特性就是 關注分離(separation of concerns) 。在層中的組件只負責本層的邏輯。組件的划分很容易讓它們實現自己的角色和職責,也比較容易地開發,測試管理和維護。
我們需要這樣的冗余,即使業務層沒有處理業務規則,也要通過業務層來調用數據層,這叫 分層隔離 。對於某些功能,如果我們從表現層直接訪問數據層,那么數據層后續的任何變動都將影響到業務層和表現層。
注意分層的 開閉原則 。如果某層是關閉的,那么每個請求都要經過着一層。相反,如果該層是開放的,那么請求可以繞過這一層,直接到下一層。
分層隔離有利於降低整個應用程序的復雜度。某些功能並不需要經過每一層,這時我們需要根據開閉原則來簡化實現。
污水池反模式(architecture sinkhole anti-pattern)
分層架構是 SOLID原則 的通用架構,當我們不確定哪種架構更合適的時候,分層架構將是一個很好的起點。我們需要注意防止架構陷入 污水池反模式(architecture sinkhole anti-pattern) 。
在這個模式中,請求流只是簡單的 穿過層次,不留一點雲彩,或者說只留下一陣⻘青煙。比如說界面層響應了一個獲得數據的請求。響應層把這 個請求傳遞給了業務層,業務層也只是傳遞了這個請求到持久層,持久層對數據庫做簡單的SQL查詢獲得用戶的數據。這個數據按照原理返回,不會有任何的二次處理,返回到界面上。
每個分層架構或多或少都可能遇到這種場景。關鍵在於這樣的請求有多少。80-20原則可以幫助你確定架構是 否處於反污水模式。大概有百分之二十的請求僅僅是做簡單的穿越,百分之八十的請求會做一些業務邏輯操 作。然而,如果這個比例反過來,大部分的請求都是僅僅穿過層,不做邏輯操作。那么開放一些架構層會比較好。不過由於缺少了層次隔離,項目會變得難以控制。
巨石應用(Monolith)
分層架構可以演變為 巨石應用(Monolith) ,導致代碼庫難以維護。
將所有功能都部署在一個web容器中運行的系統就叫做巨石型應用。巨石型應用有很多好處:IDE都是為開發單個應用設計的、容易測試——在本地就可以啟動完整的系統、容易部署——直接打包為一個完整的包,拷貝到web容器的某個目錄下即可運行。
但是,上述的好處是有條件的:應用不那么復雜。對於大規模的復雜應用,巨石型應用會顯得特別笨重:
-
要修改一個地方就要將整個應用全部部署(PS:在不同的場景下優勢也變成了劣勢);
-
編譯時間過長;回歸測試周期過長;
-
開發效率降低等。
-
巨石應用不利於更新技術框架,除非你願意將系統全部重寫(代價太高你願意老板也不願意)。
架構舉例
我們看一下淘寶前幾年的架構的例子:
這是一個標准的分層的架構。每一層中又可以詳細的分成更細的層,比如服務層。
圍着着這個主架構還有一些外圍的產品。比如監控和審計。
Tips:
-
不同的階段,不同的業務場景,不同的業務復雜度,不同的團隊,適合不同的分層。
-
有些分層是兼容低端情況(初創公司用起來也很美,還兼顧以后的發展和迭代),有些不兼容(團隊層次達不到,玩不轉)。
-
分層將導致復雜度的上升。(博弈)
-
注意接口和邊界。(不然白分)
事件驅動架構 (Event-Driven Architecture)
事件驅動架構(Event Driven Architecture)是一種流行的分布式異步架構模式,用於創建可伸縮的應用程序。這種模式是自適應的,可用於小規模或者大規模的應用程序。它由高度解耦的,單一目的的事件處理組件組成,可以異步地接收和處理事件。
它包括兩個主要的拓撲結構: 調停者拓撲(Mediator Topology) 和 代理者拓撲(Broker Topology) 。Mediator拓撲結構需要你在一個事件通過mediator時精心安排好幾個步驟,而broker拓撲結構無需mediator,而是由你串聯起幾個事件。這兩種拓撲架構的特征和實現有很大的不同,所以你需要知道哪一個適合你。
調停者拓撲(Mediator Topology)
Mediator拓撲結構適合有多個步驟的事件,需要安排處理層次。
例如購買一只股票,首先會校驗這個交易,校驗股票交易是否符合各種規定,將它交給一個經紀人,計算佣金,最后確認交易。所有這些都安排好各個步驟的順序,決定它們是否串行還是並行。
通常,架構主要包含4種組件,事件隊列(Event Queue)、調停者(Mediator)、事件通道(Event Channel)和事件處理器(Event Processor)。客戶端創建事件,並將其發送到事件隊列,調停者接收事件並將其傳遞給事件通道。事件通道將事件傳遞給事件處理器,事件最終由事件處理器處理完成。
事件流是這樣開始的: 客戶端發送一個事件到事件隊列(event queues)中,它用來將事件傳送給event mediator。Event mediator收到初始的事件后,會發送額外的一些異步事件給event channels來執行處理的每個步驟。Event processors監聽event channels,接收事件並處理一些業務邏輯。
事件調停者不會處理也不知道任何業務邏輯,它只編排事件。事件調停者知道每種事件類型的必要步驟。業務邏輯或者處理發生在事件處理器中,事件通道、消息隊列或者消息主題用於傳遞事件給事件處理器。事件處理器是自包含和獨立的,解耦於架構。理想情況下,每種事件處理器應只負責處理一種事件類型。
這里有兩種事件:初始事件和處理事件。Mediator會將初始事件編排成處理事件。它沒有具體的業務邏輯,只是一個協調者,負責將初始事件轉化成一個或者多個處理事件。
在事件驅動架構中有十幾個甚至幾百個事件隊列都很正常。模式本身沒有限定事件隊列的實現方式。它可能是一個消息隊列,一個web service或者其它。
event channels 既可以是消息隊列,也可以是消息topic,大部分是消息topic,這樣可以由多個消息處理器(event processor)處理同一個消息。
消息處理器包含實際的業務邏輯。每個消息處理器都是自包含的,獨立的,高度解耦的,執行單一的任務。這種模式可能有一些變種。作為架構師,你應該理解每個實現的細節,確保這種解決方案適合你的需求。有一些開源的框架實現了這種架構,如Spring Integration, Apache Camel, 或者 Mule ESB。
代理者拓撲(Broker Topology)
喜歡 | 作者 韓陸 發布於 2016年3月30日. 估計閱讀時間: 不到一分鍾 | 道AI風控、Serverless架構、EB級存儲引擎,盡在ArchSummit! 4 討論
分享到: 微博 微信 Facebook Twitter 有道雲筆記 郵件分享
稍后閱讀我的閱讀清單
【編者的話】本文來自Firat Atagun的《架構演化中的軟件設計原則》,文中給出了軟件架構演化過程中出現的4種經典架構,就每種架構,分析了其主要特點並在幾個度量維度給出結論。在文章的最后,Firat Atagun給出了4種架構的多維對比。本文的完整演講稿是架構演化中的軟件設計原則。
1 分層架構
分層架構是最常見的架構,也被稱為n層架構。多年以來,許多企業和公司都在他們的項目中使用這種架構,它已經幾乎成為事實標准,因此被大多數架構師、開發者和軟件設計者所熟知。
分層架構中的層次和組件是水平方向的分層,每層扮演應用程序中特定的角色。根據需求和軟件復雜度,我們可以設計N層,但大多數應用程序使用3-4層。有太多層的設計會很糟糕,將導致復雜度的上升,因為我們必須維護每一層。在傳統的分層架構中,分層包括表現層、業務或者服務層,以及數據訪問層。 表現層負責應用程序的用戶交互和用戶體驗(外觀和視覺)。通常我們會使用數據傳輸對象(Data Transfer Object)將數據帶到這一層,然后使用視圖模型(View Model)渲染到客戶端。業務層接收請求並執行業務規則。數據訪問層負責操作各種類型的數據庫,每個訪問數據庫的請求都要經過這一層。
分層無需知道其他層如何去做,比如業務層無需知道數據訪問層是如何查詢數據庫的,相反,業務層在調用數據層的特定方法時,只需關注需要部分數據還是全部數據。這就是我們所說的關注點分離。這是非常強大的功能,每層負責其所負的責任。
分層架構中的核心概念是管理依賴。如果我們使用依賴倒置原則和測試驅動開發(Test Driven Development),我們的架構會有更好的健壯性。因為,我們要保證所有可能的用例都有測試用例。
我們需要這樣的冗余,即使業務層沒有處理業務規則,也要通過業務層來調用數據層,這叫分層隔離。對於某些功能,如果我們從表現層直接訪問數據層,那么數據層后續的任何變動都將影響到業務層和表現層。
相關廠商內容
微信Android模塊化架構重構實踐 蘑菇街分布式消息中間件Corgi的架構演進 Serverless架構:一條SQL到一個服務有多遠? 對抗復雜性,架構設計中可借鑒復用這些手段 阿里:風控場景的模型平台架構設計
相關贊助商
ArchSummit深圳2017,7月7-8日,深圳·華僑城洲際酒店,精彩內容搶先看
分層架構中的一個重要的概念就是分層的開閉原則。如果某層是關閉的,那么每個請求都要經過着一層。相反,如果該層是開放的,那么請求可以繞過這一層,直接到下一層。
分層隔離有利於降低整個應用程序的復雜度。某些功能並不需要經過每一層,這時我們需要根據開閉原則來簡化實現。
分層架構是SOLID原則的通用架構,當我們不確定哪種架構更合適的時候,分層架構將是一個很好的起點。我們需要注意防止架構陷入污水池反模式。這種反模式描述了請求經過分層,但沒做任何事或者只處理了很少的事。如果我們的請求經過所有分層而沒有做任何事,這就是污水池反模式的征兆。如果20%的請求只是經過各層,而80%的請求實際做事,這還好,如果這個比率不是這樣的,那么我們已經患上反模式綜合征。
此外,分層架構可以演變為巨石應用(Monolith),導致代碼庫難以維護。
分層架構分析:
敏捷性:總體敏捷性是指對不斷變化的環境作出反應的能力。由於其整體風格(Monolith)的性質,可能會變得難以應對通過所有層的變化,開發者需要注意依賴性和分層分離。
易於部署:大型應用程序的部署會是個麻煩。一個小要求,可能需要部署整個應用程序。如果能做好持續交付,可能會有所幫助。
可測試性:使用Mocking和Faking,每一層可以獨立測試,因此測試上很容易。
性能:雖然分層應用程序可能表現良好,但是因為請求需要經過多個分層,可能會存在性能問題。
可伸縮性:因為耦合太緊以及整體風格(Monolith)的天生特質,很難對分層應用程序進行伸縮。然而,如果分層能夠被構建為獨立的部署,還是可以具備伸縮能力的。但是,這樣做的代價可能很昂貴。
易於開發:這種模式特別易於開發。許多企業采用這種模式。大多數開發者也都知道、了解,並且可以輕松學習如何使用它。
2 事件驅動架構
事件驅動架構(Event Driven Architecture)是一種流行的分布式異步架構模式,用於創建可伸縮的應用程序。這種模式是自適應的,可用於小規模或者大規模的應用程序。事件驅動架構可以與調停者拓撲(Mediator Topology)或者代理者拓撲(Broker Topology)一起使用。理解拓撲的差異,為應用程序選擇正確的拓撲是必不可少的。
調停者拓撲
調停者拓撲需要編排多種事件。比如在交易系統中,每個請求流程必須經過特定的步驟,如驗證、訂單、配送,以及通知買家等。在這些步驟中,有些可以手動完成,有些可以並行完成。
通常,架構主要包含4種組件,事件隊列(Event Queue)、調停者(Mediator)、事件通道(Event Channel)和事件處理器(Event Processor)。客戶端創建事件,並將其發送到事件隊列,調停者接收事件並將其傳遞給事件通道。事件通道將事件傳遞給事件處理器,事件最終由事件處理器處理完成。
事件調停者不會處理也不知道任何業務邏輯,它只編排事件。事件調停者知道每種事件類型的必要步驟。業務邏輯或者處理發生在事件處理器中,事件通道、消息隊列或者消息主題用於傳遞事件給事件處理器。事件處理器是自包含和獨立的,解耦於架構。理想情況下,每種事件處理器應只負責處理一種事件類型。
通常,企業服務總線、隊列或者集線器可以用作事件調停者。正確選擇技術和實現能夠降低風險。
代理者拓撲
不像調停者拓撲,代理者拓撲不使用任何集中的編排,它沒有中心的Mediator。而是在事件處理器之間使用簡單的隊列或者集線器,事件處理器知道處理事件的下一個事件處理器。所有的事件串聯起來通過一個輕量級的消息broker如RabbitMQ,ActiveMQ,HornetQ等。如果你的消息比較簡單,不需要重新編排,就可以使用這種結構。
如圖所示,它包含兩個組件broker和 event processor。broker中的event channel可以是消息隊列,消息topic或者它們的復合形式。每個event processor負責處理事件,發布新的事件。
舉例
在新浪微博的早期架構中,微博發布使用同步推模式,用戶發表微博后系統會立即將這條微博插入到數據庫所有粉絲的訂閱列表中,當用戶量比較大時,特別是明星用戶發布微博時,會引起大量的數據庫寫操作,超出數據庫負載,系統性能急劇下降,用戶響應延遲加劇。
后來新浪微博改用異步推拉結合的模式,用戶發表微博后系統將微博寫入消息隊列后立即返回,用戶響應迅速,消息隊列消費者任務將微博推送給所有當前在線粉絲的訂閱列表中,非在線用戶登錄后再根據關注列表拉取微博訂閱列表。
Tips
因其分布式和異步的性質,事件驅動架構的實現相對復雜,主要是由於它的異步和分布式特性。我們需要面對很多問題,比如網絡分區、調停者失敗、重新連接邏輯等。由於這是一個分布式且異步的模式,如果你需要事務,那就麻煩了,你得需要一個事務協調器。分布式系統中的事務非常難以管理,很難找到標准的工作單位模式。
一個考慮是這種模式對於單一的邏輯缺乏原子事務。所以你需要將原子事務交給一個事件處理器執行,跨事件處理器的原子事務是很困難的。
最困難的設計之一是事件處理器的創建,維護和管理。事件通常有特殊的約定(數據值和格式)。
微內核架構 (Microkernel Architecture)
微內核架構(Microkernel architecture)模式也被稱為插件架構(plugin architecture)模式。可以用來實現基於產品的應用, 比如Eclipse,在微內核的基礎上添加一些插件,就可以提供不同的產品,如C++, Java等。
微內核包含兩個組件: core system 和 plug-in modules。應用邏輯被分隔成核心系統和插件模塊,可以提供可擴展的,靈活的,特性隔離的功能。
這種模式非常適合桌面應用程序,但是也可以在Web應用程序中使用。事實上,許多不同的架構模式可以作為整個系統的一個插件。對於產品型應用程序來說,如果我們想將新特性和功能及時加入系統,微內核架構是一種不錯的選擇。
微內核的架構模式可以嵌入到其它的架構模式之中。微內核架構通過插件還可以提供逐步演化的功能和增量開發。所以如果你要開發基於產品的應用,微內核是不二選擇。
微服務架構(Microservices architecture)
盡管微服務的概念還相當新,但它確實已經快速地吸引了大量的眼球,以替代整體應用和面向服務架構(SOA)。其中的一個核心概念是具備高可伸縮性、易於部署和交付的獨立部署單元(Separately Deployable Units)。最重要的概念是包含業務邏輯和處理流程的服務組件(Service Component)
不管你使用何種實現風格和拓撲,有幾個通用的核心概念應用在這種架構模式上。首先是分隔發布單元(separately deployed units)。
如圖所示,每一個微內核的組件都被分隔成一個獨立的單元。微服務包含 服務組件(service component )。不要考慮微內核的單個服務,而是最好考慮服務組件,從粒度上講它可以是單一的模塊或者一個一個大的應用程序,代表單一功能(提供天氣預報或者圖片存儲)。
正確設計服務組件的粒度是一個很大的挑戰。
另一個關鍵概念是微內核是分布式的。這意味着服務組件可能是遠程方法(通過JMS, AMQP, REST, SOAP, RMI......等等)。分布式意味着這種模式可以建立大規模的應用。
另一個值得興奮的特性是它可以從其它有問題的架構模式中演化出來,而不是直接創建出來等待問題發生。當你遇到一些無法解決的問題,特別是互聯網企業的規模擴大時,是很好的引入微服務架構的時機。
一般會從兩個模式中演化:
-
一種就是一開始就是整體的應用,所有的模塊都是緊耦合的。
-
另外一種是 面向服務的架構模式(SOA,service-oriented architecture pattern) 。
SOA不是不好,但是太昂貴了,不好理解和實現。
應用拆分
這張圖從三個維度概括了一個系統的擴展過程:
-
x軸,水平復制,即在負載均衡服務器后增加多個web服務器;
-
z軸擴展,是對數據庫的擴展,即分庫分表(分庫是將關系緊密的表放在一台數據庫服務器上,分表是因為一張表的數據太多,需要將一張表的數據通過hash放在不同的數據庫服務器上);
-
y軸擴展,是功能分解,將不同職能的模塊分成不同的服務。
從y軸這個方向擴展,才能將巨型應用分解為一組不同的服務,例如訂單管理中心、客戶信息管理中心、商品管理中心等等。
實現方式
有很多實現微服務的方式。最通用最流行的三個方式是:
-
API REST-based
-
applicaiton REST-based
-
中心化的消息
API REST-based 適合網站提供小規模的,自包含的服務。很多互聯網網站都提供這樣的服務,比如OAuth2服務。
application REST-based不同於上面的架構,客戶端看到的是web界面或者富客戶端程序,而不是調用API。UI層獨立發布,可以訪問服務組件。
中心消息模式,它類似前面的模式,但是使用一個輕量級的消息broker取代RESTful的服務調用。這個輕量級的broker不會執行服務的編排,傳輸和路由,這和SOA不同,不要把它看作SOA的簡化版
內部服務之間的通信
內部服務之間的通信方式有兩種:基於HTTP協議的同步機制(REST、RPC);基於消息隊列的異步消息處理機制(AMQP-based message broker)。
Dubbo 是阿里巴巴開源的分布式服務框架,屬於同步調用,當一個系統的服務太多時,需要一個注冊中心來處理服務發現問題,例如使用ZooKeeper這類配置服務器進行服務的地址管理:服務的發布者要向ZooKeeper發送請求,將自己的服務地址和函數名稱等信息記錄在案;服務的調用者要知道服務的相關信息,具體的機器地址在ZooKeeper查詢得到。這種同步的調用機制足夠直觀簡單,只是沒有“訂閱——推送”機制。
AMQP-based的代表系統是 Kafka 、 RabbitMQ 等。這類分布式消息處理系統將訂閱者和消費者解耦合,消息的生產者不需要消費者一直在線;消息的生產者只需要把消息發送給消息代理,因此也不需要服務發現機制。
兩種通信機制都有各自的優點和缺點,實際中的系統經常包含兩種通信機制。例如,在分布式數據管理中,就需要同時用到同步HTTP機制和異步消息處理機制。
微服務架構解決了無架構的整體編碼的應用的問題以及SOA的問題。同時它還可以提供實時的產品發布。它是一個分布式架構,也會有上面分布式的問題。
基於空間的架構 (Space-Based Architecture)
基於空間的架構有時候也被成為基於雲的架構。
大部分的基於web的應用的業務流都是一樣的。 客戶端的請求發送給web服務器,然后是應用服務器,最后是數據庫服務器。對於用戶很小時不會有問題,但是負載增大時就會遇到瓶頸(想想搶火車票)。首先是web服務器撐不住,web服務器能撐住應用服務器又不行,然后是數據庫服務器。通常解決方案是增加web服務器,便宜,簡單,但很多情況下負載會傳遞給應用服務器,然后傳遞給數據庫服務器。有時候增加數據庫服務器也沒有辦法,因為數據庫也有鎖,有事務的限制。
基於空間的架構用來解決規模和並發的問題。
基於空間的架構最小化限制應用規模的影響。這個模式來自於tuple space, 分布式共享內存想法。要想大規模,就要移除中心數據庫的限制,使用可復制的內存網格。應用數據保存在所有活動的處理單元的內存中,處理單元根據應用規模可以加入和移除。因為沒有中心數據庫,所以數據庫的瓶頸可以解決。
這種模式有兩個組件: 處理單元processing unit 和 虛擬化中間件virtualized middleware 。
處理單元包含應用程序。小的應用程序可以使用一個處理單元,大的應用程序可以被分隔成幾個處理單元。處理單元還包括數據網格。
虛擬化中間件負責管理和通信。處理數據的同步和請求。
基於空間的架構是一個復雜而昂貴的模式。對於小型的負載可變的web應用很適合,但是對於大型的關系型數據庫應用不是太適合。