本文是我在閱讀O'Reilly免費的電子書 Software Architecture Patterns過程中做的筆記。
首先這本書非常新,2015年3月30號訂正後發佈。其次將目前流行的幾種架構詳細進行了剖析和比較,除了傳統的N層架構外,其它架構相當的前沿。並且,這篇小書連帶封面才55頁,短小精悍,值得一讀。這本書的作者是 Mark Richards,有30多年行業經驗,19年軟件集成,企業級架構的經驗,大部分是Java平臺,也出版了多本書和論文。
如果你沒有時間去閱讀這本書,那麼不妨看一下本篇文章。 我在筆記中將書中的主要知識點都記錄下來。
不先進行正式的架構設計就直接開發對於程序員來說再普通不過了。沒有清晰和很好的架構設計,大部分程序員和架構師實際上會採用傳統的分層的架構模式, 自然地將代碼模塊分隔成幾個包(package)。不幸地是,這種做法經常導致未能好好組織代碼模塊,這些模塊缺乏清晰的角色,責任以及相互關係。這經常被成爲大泥球反模式。
沒有進行架構設計的應用程序通常是緊耦合的,玻璃心,難以改變,沒有頭緒。如果不理解應用的各個組件的內部工作方式的話很難看清它的架構特徵。關於部署和維護的問題都很難回答:架構的規模如何?程序的性能如何?程序容易修改嗎?程序的部署模型是怎麼樣?程序的響應如何?
架構模式可以幫助你定義程序的基本特徵和行爲。例如一些架構模式很自然讓程序成爲大規模(scalable)的程序。有些模式讓程序變得靈巧敏捷(agile)。知道這些架構的特徵,優點和缺點,你就可以根據你特定的業務需求和目標從容的選擇一種架構模式。
作爲一位架構師,你總會爲自己架構選擇做解釋,尤其你選擇一個特別的架構模式的時候。O'Reilly的這本書提供了充足的信息來爲你的架構選擇提供證明。
分層架構 (Layered Architecture)
它是最通用的架構,也被叫做N層架構模式(n-tier architecture pattern)。這也是Java EE應用經常採用的標準模式。基本上是個程序員都知道它。這種架構模式非常適合傳統的IT通信和組織結構,很自然地成爲大部分應用的第一架構選擇。
模式描述
在分層架構中的組件被劃分成幾個層,每個層代表應用的一個功能。分層架構本身沒有規定要分成多少層,大部分的應用會分成表現層,業務層,持久層和數據庫層。小的應用有時候會將業務層和持久層合在一起,更大規模的應用可能會劃分更多的層,比如調用外部服務的層。
每一層都有特定的角色和職能。
分層架構的一個特性就是關注分離(separation of concerns)。在層中的組件只負責本層的邏輯。組件的劃分很容易讓它們實現自己的角色和職責,也比較容易地開發,測試管理和維護。
關鍵概念
注意每一層都是封閉的。這意味着Request必須經過每一層才能到達最底下一層。
爲什麼不允許展示層直接訪問數據庫層呢,這樣不是更快嗎?這就是分層架構的另一個特徵:層隔離(layers of isolation)。
層隔離的概念意味着你對任何一層的改變都不會影響其它層。這很好理解。
層隔離也意味着一個層的組件並不會瞭解其它層的實現,或者知道很少。 比如業務層不需知道你持久層是由hibernate還是mybatis實現的。
分層架構也很容易增加新的層。 比如你想將一些通用的服務重構成一個服務層,比如通用圖片處理,遠程賬戶審計等,可以在業務層下增加一個服務層。它不會對展示層造成影響,也不會改變持久層的代碼。
上面的這個例子帶來一個問題,因爲每一層丟失封閉的,業務層不得不通過服務層訪問持久層,這沒有天理啊。 所以有時候你會創建一個開放的層。這意味着上一層可以繞過這一層直接訪問下一層。
架構例子
我們看一下淘寶前幾年的架構的例子。
這是一個標準的分層的架構。每一層中又可以詳細的分成更細的層,比如服務層。
圍着着這個主架構還有一些外圍的產品。比如監控和審計。
架構考量
分層架構是一個可靠的通用的架構,對很多應用來說,如果你不確定哪種架構適合你的應用,可以用它作爲一個初始架構。
第一個要注意的是污水池反模式(architecture sinkhole anti-pattern).這個反模式是這樣的,請求流簡單的穿過幾個層,每層裏面基本沒有做任何業務邏輯,或者做了很少的業務邏輯。比如一些JavaEE例子,業務邏輯層只是簡單的調用了持久層的接口,本身沒有什麼業務邏輯。
每一層或多或少都有可能遇到這樣的場景。關鍵是分析這樣的請求的百分比是多少。80-20原則可以幫助你決定是否正在遇到污水池反模式。如果你的請求超過20%,你應該考慮讓一些層變成開放的。
另一個需要考慮的是分層架構可能會讓你的應用變得龐大,即使你的展示層和業務層可以獨立發佈(比如展示層使用單頁技術框架AngularJS, EmberJS)。
它的確會帶來一些潛在的問題,比如分佈模式複雜,健壯性下降,可靠性,性能和規模等。
模式分析
總體靈活性: 低
發佈易用性: 低
可測試性: 高
性能: 低
規模擴展性: 低
開發容易度: 高
事件驅動架構 (Event-Driven Architecture)
事件驅動架構是一個流行的分佈式異步架構模式,可以用來設計規模很大的應用程序。基於這種架構模式應用可大可小。它由高度解耦的,單一目的的事件處理組件組成,可以異步地接收和處理事件。
它包括兩個主要的拓撲結構:mediator 和 broker。Mediator拓撲結構需要你在一個事件通過mediator時精心安排好幾個步驟,而broker拓撲結構無需mediator,而是由你串聯起幾個事件。這兩種拓撲架構的特徵和實現有很大的不同,所以你需要知道哪一個適合你。
Mediator拓撲結構
Mediator拓撲結構適合有多個步驟的事件,需要安排處理層次。
例如購買一隻股票,首先會校驗這個交易,校驗股票交易是否符合各種規定,將它交給一個經紀人,計算佣金,最後確認交易。所有這些都安排好各個步驟的順序,決定它們是否串行還是並行。
它包括四個組件:event queues, an event mediator, event channels 和 event processors。
事件流是這樣開始的: 客戶端發送一個事件到事件隊列(event queues)中,它用來將事件傳送給event mediator。Event mediator收到初始的事件後,會發送額外的一些異步事件給event channels來執行處理的每個步驟。Event processors監聽event channels,接收事件並處理一些業務邏輯。
在事件驅動架構中有十幾個甚至幾百個事件隊列都很正常。模式本身沒有限定事件隊列的實現方式。它可能是一個消息隊列,一個web service或者其它。
這裏有兩種事件:初始事件和處理事件。Mediator會將初始事件編排成處理事件。它沒有具體的業務邏輯,只是一個協調者,負責將初始事件轉化成一個或者多個處理事件。
event channels 既可以是消息隊列,也可以是消息topic,大部分是消息topic,這樣可以由多個消息處理器(event processor)處理同一個消息。
消息處理器包含實際的業務邏輯。每個消息處理器都是自包含的,獨立的,高度解耦的,執行單一的任務。
這種模式可能有一些變種。作爲架構師,你應該理解每個實現的細節,確保這種解決方案適合你的需求。
有一些開源的框架實現了這種架構,如Spring Integration, Apache Camel, 或者 Mule ESB。
Broker拓撲架構
Broker不同於上面的結構,它沒有中心的Mediator。所有的事件串聯起來通過一個輕量級的消息broker如RabbitMQ,ActiveMQ,HornetQ等。如果你的消息比較簡單,不需要重新編排,就可以使用這種結構。
如圖所示,它包含兩個組件broker和 event processor。
broker中的event channel可以是消息隊列,消息topic或者它們的複合形式。
每個event processor負責處理事件,發佈新的事件。
架構例子
在新浪微博的早期架構中,微博發佈使用同步推模式,用戶發表微博後系統會立即將這條微博插入到數據庫所有粉絲的訂閱列表中,當用戶量比較大時,特別是明星用戶發佈微博時,會引起大量的數據庫寫操作,超出數據庫負載,系統性能急劇下降,用戶響應延遲加劇。後來新浪微博改用異步推拉結合的模式,用戶發表微博後系統將微博寫入消息隊列後立即返回,用戶響應迅速,消息隊列消費者任務將微博推送給所有當前在線粉絲的訂閱列表中,非在線用戶登錄後再根據關注列表拉取微博訂閱列表。
架構考量
事件驅動架構模式實現起來相對複雜,主要是由於它的異步和分佈式特性。這可能會帶來一些分佈式的問題,比如遠程處理的可用性,缺乏響應,broker重連等問題。
一個考慮是這種模式對於單一的邏輯缺乏原子事務。所以你需要將原子事務交給一個事件處理器執行,跨事件處理器的原子事務是很困難的。
最困難的設計之一是事件處理器的創建,維護和管理。事件通常有特殊的約定(數據值和格式)。
模式分析
總體靈活性: 高
發佈易用性: 高
可測試性: 低
性能: 高
規模擴展性: 高
開發容易度: 低
微內核架構 (Microkernel Architecture)
微內核架構模式通常又被成爲插件架構模式,可以用來實現基於產品的應用, 比如Eclipse,在微內核的基礎上添加一些插件,就可以提供不同的產品,如C++, Java等。
模式描述
微內核包含兩個組件: core system 和 plug-in modules。應用邏輯被分隔成核心繫統和插件模塊,可以提供可擴展的,靈活的,特性隔離的功能。
模式例子
Eclipse IDE是當之無愧的微內核的絕佳例子之一。
架構考量
微內核的架構模式可以嵌入到其它的架構模式之中。微內核架構通過插件還可以提供逐步演化的功能和增量開發。所以如果你要開發基於產品的應用,微內核是不二選擇。
模式分析
總體靈活性: 高
發佈易用性: 高
可測試性: 高
性能: 高
規模擴展性: 低
開發容易度: 低
微服務架構
作爲單一整體的程序和麪向服務架構的替代者, 微服務架構模式在工業界很快贏得了地位。這種模式還在進化之中,在業界對於它的特性和實現還有些困惑。Oreilly的小書提供了這種模式關鍵的概念和基礎知識,用來判斷這種架構是否適合你的應用。
模式描述
不管你使用何種實現風格和拓撲,有幾個通用的核心概念應用在這種架構模式上。首先是分隔發佈單元(separately deployed units)。
如圖所示,每一個微內核的組件都被分隔成一個獨立的單元。
微服務包含服務組件(service component)。不要考慮微內核的單個服務,而是最好考慮服務組件,從粒度上講它可以是單一的模塊或者一個一個大的應用程序,代表單一功能(提供天氣預報或者圖片存儲)。
正確設計服務組件的粒度是一個很大的挑戰。
另一個關鍵概念是微內核是分佈式的。這意味着服務組件可能是遠程方法(通過JMS, AMQP, REST, SOAP, RMI......等等)。分佈式意味着這種模式可以建立大規模的應用。
另一個值得興奮的特性是它可以從其它有問題的架構模式中演化出來,而不是直接創建出來等待問題發生。當你遇到一些無法解決的問題,特別是互聯網企業的規模擴大時,是很好的引入微服務架構的時機。
一般會從兩個模式中演化。
一種就是一開始就是整體的應用,所有的模塊都是緊耦合的。另外一種是面向服務的架構模式(SOA,service-oriented architecture pattern)。SOA不是不好,但是太昂貴了,不好理解和實現。
模式拓撲
有很多實現微服務的方式。最通用最流行的三個方式是: API REST-based, applicaiton REST-based 和 中心化的消息。
API REST-based 適合網站提供小規模的,自包含的服務。很多互聯網網站都提供這樣的服務,比如OAuth2服務。
application REST-based不同於上面的架構,客戶端看到的是web界面或者富客戶端程序,而不是調用API。UI層獨立發佈,可以訪問服務組件。
中心消息模式,它類似前面的模式,但是使用一個輕量級的消息broker取代RESTful的服務調用。這個輕量級的broker不會執行服務的編排,傳輸和路由,這和SOA不同,不要把它看作SOA的簡化版。
架構考量
微服務架構解決了無架構的整體編碼的應用的問題以及SOA的問題。同時它還可以提供實時的產品發佈。
它是一個分佈式架構,也會有上面分佈式的問題。
模式分析
總體靈活性: 高
發佈易用性: 高
可測試性: 高
性能: 低
規模擴展性: 高
開發容易度: 高
基於空間的架構 (Space-Based Architecture)
基於空間的架構有時候也被成爲基於雲的架構。
大部分的基於web的應用的業務流都是一樣的。 客戶端的請求發送給web服務器,然後是應用服務器,最後是數據庫服務器。對於用戶很小時不會有問題,但是負載增大時就會遇到瓶頸(想想搶火車票)。首先是web服務器撐不住,web服務器能撐住應用服務器又不行,然後是數據庫服務器。通常解決方案是增加web服務器,便宜,簡單,但很多情況下負載會傳遞給應用服務器,然後傳遞給數據庫服務器。有時候增加數據庫服務器也沒有辦法,因爲數據庫也有鎖,有事務的限制。
基於空間的架構用來解決規模和併發的問題。
模式描述
基於空間的架構最小化限制應用規模的影響。這個模式來自於tuple space, 分佈式共享內存想法。要想大規模,就要移除中心數據庫的限制,使用可複製的內存網格。應用數據保存在所有活動的處理單元的內存中,處理單元根據應用規模可以加入和移除。因爲沒有中心數據庫,所以數據庫的瓶頸可以解決。
這種模式有兩個組件:處理單元processing unit 和 虛擬化中間件virtualized middleware。
處理單元包含應用程序。小的應用程序可以使用一個處理單元,大的應用程序可以被分隔成幾個處理單元。處理單元還包括數據網格。
虛擬化中間件負責管理和通信。處理數據的同步和請求。
模式考量
基於空間的架構是一個複雜而昂貴的模式。對於小型的負載可變的web應用很適合,但是對於大型的關係型數據庫應用不是太適合。
模式分析
總體靈活性: 高
發佈易用性: 高
可測試性: 低
性能: 高
規模擴展性: 高
開發容易度: 低