上篇中解釋到什麼是架構風格和應該以怎樣的視角來理解REST(Web的架構風格)。本篇來介紹一組自洽的術語,用它來描述和解釋軟體架構;以及列舉下對於基於網路的應用來說,哪些點是需要我們重點關註的。 1 軟體架構 軟體架構方面研究的是如何以最佳的方式劃分一個系統、如何標識組件、組件之間如何通信、信息如何 ...
上篇中解釋到什麼是架構風格和應該以怎樣的視角來理解REST(Web的架構風格)。本篇來介紹一組自洽的術語,用它來描述和解釋軟體架構;以及列舉下對於基於網路的應用來說,哪些點是需要我們重點關註的。
1 軟體架構
軟體架構方面研究的是如何以最佳的方式劃分一個系統、如何標識組件、組件之間如何通信、信息如何表達、組成系統的元素如何獨立的進化,以及如何表達上述的內容。一個優秀的架構並非憑空靠想象得來的,每一個架構級的決策,都應該根據被設計的系統功能、行為和社交三方面的需求而作出。這是一個基本的設計原則,即“形式追隨功能”。這條原則源自於建築學領域在數百年中失敗的建築項目中獲得的經驗,但是卻總被軟體行業所忽略。dedign-by-buzzword的行為隨處可見,出現這種行為的原因在於很多設計者不理解哪些東西才是自己所需的;以及在選擇某一個優秀的軟體架構時,這個架構的適用場景是什麼,以及背後是基於什麼考量才得出的這樣的架構。下麵先介紹一組自洽的術語來描述解釋軟體架構。
1.1 運行時抽象
軟體架構是一個軟體系統在其運行過程中某個階段的運行時元素的抽象。一個系統可能會有多層抽象和多個運行階段組成,每一個抽象和運行階段都是自己的軟體架構。
軟體架構的核心是抽象:通過封裝來隱藏系統的一些細節,從而更好的識別其架構屬性。一個複雜的系統會有著多層抽象,每一層都有自己的架構,架構代表了某個層次上系統行為的抽象。除了層次之外,系統還會有多個運行階段,比如啟動、初始化、正常運行、停止、重新初始化等,每個階段也都有自己的架構,比如配置文件在啟動的時候會作為架構的一個數據元素來處理,到了正常運行的時候,這些數據元素已經完成了它的使命。那麼在啟動階段如何處理它的架構也就完成了自己的使命。
很多時候很容易把軟體的源代碼的靜態結構視為軟體架構,其實這是有些不妥的。軟體結構是靜態的源代碼的組織結構方式,而非其真正運行起來時所表現出來的功能、層次和行為等。舉個小例子,比如一個介面和它的一個實現者,它們再源代碼級別是歸屬在一個地方的,但是在運行時我們關註的通常是其介面的行為,而非它的實現者身在何處。
1.2 架構元素
軟體架構是由一些架構元素(組件、連接器和數據)的配置來定義的,這些元素之間的關係受到一組約束,以獲得期望的架構屬性。具體的元素類型如下:
- 組件:組件是軟體指令和內部狀態的抽象單元,通過其介面提供數據的轉換能力。比如執行從硬碟載入數據到記憶體、執行一些計算、轉換為另外一種格式等。每個組件的行為是架構的一部分,能夠被其他組件觀察到或者識別出來。比如瀏覽器,網關,Web伺服器(apache,ngnix.,iis)等。
- 連接器:對於組件之間的通信、配合或者協作進行中間周旋的一種抽象機制。區分連接器和組件的最佳方式是看其對數據的處理方式,連接器是把數據從一個介面移交到另外一個介面而不改變數據,以此來支持組件之間的通信。在連接器的內部,可能是由多個組件來實現的,但是其對外的表現的行為則是未對數據做出改變。比如緩存,SSL/TLS等等這類。
- 數據:數據是組件通過連接器接收或發送的信息元素。比如二進位數據,json,HTML文檔,圖片等。
1.3 配置
配置是系統在運行期間和組件、連接器和數據之間的架構關係的結構。此配置非彼配置,指的不是一個系統的各項配置參數,而是如何組織架構元素之間的關係。
1.4 架構屬性
架構屬性是軟體架構對組件、連接器和數據的選擇以及排列所產生的屬性。其包含了系統的功能性屬性以及非功能性屬性(比如組件的可重用性、效率、擴展能力等)。架構屬性是由一組架構約束產生的,而架構約束則是由在架構元素的某一個方面應用軟體工程原則來驅動的。比如統一管道和過濾器架構風格通過在組件的介面上應用通用性的原則(強迫組件實現統一的介面),從而獲得組件的可重用性和可配置性的架構屬性。因此它的架構約束就是由通用性原則所驅動的“統一組件介面”,目的是獲得上述的可重用性和和配置性這兩個架構屬性。舉個簡單的小實例,比如asp net mvc中的filter。
架構設計的目標是創建包含一組期望的架構屬性的架構。這組架構屬性是系統需求的一個超集,不同架構屬性的重要性則取決於系統本身的需要。後面會介紹對於一個基於網路的應用來說,哪些架構屬性是值得關註的。
1.5 架構風格
架構風格的定義在上一篇中已經簡單的解釋過了,這裡更嚴謹的定義一下:架構風格是一組相互協作的架構約束,這些架構約束限制了架構元素的角色和功能,以及在任何一個遵循該架構風格的架構中允許存在的元素之間的關係。
一個架構中即會包含功能屬性又會包含非功能屬性,直接比較不同類型的架構時是比較困難的。架構風格是一種對架構進行分類並且定義它們的公共特征的機制。通過比較這部分公共部分的架構約束,來識別其能獲得的架構屬性的差異。好比上篇文章中說到的佛教建築和古羅馬建築,比較它們的不同之處的辦法在於用其各自的特征來對比。架構風格是比軟體架構更加抽象的一個層次。比如說面向對象語言如果是架構風格,則Java,C#這些具體的實現了面向對象的語言則是具體的軟體架構,當我們拿C#和C對比的時候,它們的差異歸根到底是面向對象與面向過程的差異,而並不是分別實現了面向對象的C#和麵向過程的C的具體細節差異。
2 基於網路應用的架構
軟體架構可以存在於軟體系統的多個層次之上。而REST則是聚焦於軟體架構的最高層次的抽象,即跨越網路的運行環境,這裡的組件是通過網路通信來實現組件的交互的。
軟體方面的研究通常是關註軟體設計如何分類和設計,但是卻很少能客觀的評估不同的設計對於系統行為有什麼影響。
網路方面的研究則聚焦於系統之間的通信細節以及如何提高通信性能,卻通常忽略一個事實,有時候改變一個應用的交互風格對於性能產生的影響要比改變所使用的通信協議更大。
基於網路 VS 分散式:基於網路的架構和軟體架構的區別在於,組件之間的通信僅限於消息傳遞或者消息傳遞的等價物。基於網路的系統和分散式系統之間有細微的差異,比如一個分散式系統在其消費者看來和普通的集中式系統沒什麼區別(只是它背後是運行在多個獨立的系統之上),也就是說其背後的實現對其消費者而言是透明的。而基於網路的系統則是無需對消費者透明的,比如消費者在執行一個網路請求時,如果本地的緩存可以滿足其需要,則無需執行一個真正的網路請求。可以簡單的認為分散式應用屬於基於網路應用的一個子集。當然也並不是說分散式系統就沒有緩存,這隻是一種很細微的差異。
應用軟體 VS 網路軟體:應用軟體通常來說指的是包含系統中包含業務行為的那部分功能。而網路軟體的目的通常來說是關註與如何把數據跨越網路傳遞到另外一個地方,其關心的書如何傳輸,而不關心為何要傳遞這些數據。應用軟體是對整個系統的一個抽象,比如用戶執行一個動作,這個動作中會包含如何獲取數據,執行網路請求和對請求結果進行呈現,而網路傳輸則是其中的一個環節。
3 基於網路應用的關鍵架構屬性
REST關註的是基於網路的應用軟體的架構設計,這也正是Web的訴求,Web是一個互聯網規模的分散式超媒體系統,互聯網規模意味著無法控制的可伸縮性和組件的獨立部署。那麼如何評估一個軟體架構是否滿足Web的需求,把它實現出來看一下?不現實吧。比較可取的辦法就是利用上面所介紹到的架構屬性來和Web的需求目的進行比較:首先是要滿足功能性的要求,如果一個架構連基本的功能性需求都滿足不了,評估對於它來說就沒什麼意義;其次則是非功能性的屬性,這也是評估的主要關註點。下麵列舉下基於網路的應用的關鍵架構屬性。
3.1 性能
性能這個話題或許是電腦行業永遠也繞不開的話題。基於網路的應用的性能首先取決於應用的需求,然後是所選擇的交互風格,接下來是實現的架構,最後則是每個組件的實現細節。換句話說,應用軟體無法迴避為了實現該軟體的需求而付出的基本成本。比如說軟體需要的數據位於系統A,並由系統B來處理,那麼該軟體就無法避免的要把數據從系統A移動到系統B(好比你要訪問資料庫,這部分網路開銷是無論如何也繞不過去的)。無論架構怎樣優秀,網路的速度再快,也不可能比直接在系統A處理要快。
- 用戶感知的性能:用戶的一個動作從發出,到其得到響應的時間,其主要有兩個衡量指標,延遲和完成時間,比如打開一張圖片,一邊下載一邊顯示和等下載完後再顯示,對於用戶感知的性能是有明顯的區別的。
- 網路性能:通常來講,網路性能指的的網路傳輸的吞吐量以及其支撐這些吞吐量所產生的開銷。
- 網路效率:一個有趣的現象是,最佳的應用性能通常時通過不使用網路而獲得的。這也就是說,對於一個基於網路的應用來說,把對網路的使用降低到最少,才是最高效的架構風格。
3.2 可伸縮性
可伸縮性是可以通過配置來改變一個架構中的大量的組件之間的交互的能力。可以通過簡化組件、去中心化、以及通過監視獲得的信息來對交互進行配置和控制。
3.3 簡單性
乍看之下這個架構屬性有點籠統,其實也不然。比如http的無狀態性特點,就使得伺服器端的實現簡單化,不用去保存或者恢覆上一次的http請求,也使得中間的各個組件和連接器可以獨立的理解單次請求的語義。通過對組件實施分離關註點原則,可以獲得簡單性;通過實施通用性原則,也可以提高簡單性。
3.4 可修改性
可修改性指的是對於應用的架構做出改變的容易度。即使創造出了一個完全滿足用戶需要的系統,用戶需求也總是會變化的,唯一不變的事情就是變化本身。基於網路的應用中的組件跨越了網路。比如系統中的一些組件難免的會升級為新組件,系統需要能面對新舊共存的局面等等。可修改性可以做如下更細節的劃分:
- 可進化性:指一個組件改變了內部實現而不會對其他組件產生負面影響的程度。
- 可擴展性:指可以把一個新功能添加到系統中的能力。動態擴展性則是指將功能添加到一個已部署的系統中,而不會影響到系統中的其他部分。
- 可定製型:指臨時性的規定一個架構元素的行為的能力。如果一個組件的客戶端能夠擴展該組件的服務,而不會對其他客戶端產生影響,則該組件就是可定製的。
- 可重用性:指一個應用軟體中的組件、連接器和數據元素能夠不做修改的在其他應用重用。
3.5 可見性
可見性指的是一個組件對於其他組件之間的交互進行監視或者進行中間周旋的能力。擁有了可見性之後,就可以通過共用緩存來改善性能、通過分層來改善可伸縮性、通過允許中間件(比如防火牆)對交互做出檢查來改善安全性、通過監視來改善可靠性等。
3.6 可移植性
指的是軟體在不同的環境下運行的能力。比如那些將代碼和代碼處理的數據放在一起移動的架構風格可以獲得此架構屬性,比如虛擬機風格、移動代理風格,以及那些限制只能使用標準格式的數據元素的架構風格。
3.7 可靠性
從應用軟體的角度來看,可靠性是在組件、連接器和數據之間出現部分故障時,一個架構受影響的程度。通過避免單點故障、增加冗餘、系統監視等方法來改善可靠性。
4 總結
本篇主要介紹一組如何描述軟體架構的自洽的術語,以及對於基於網路的應用來說,哪些架構屬性是值得我們關註的。本篇均是筆者自己的一些理解,不免有錯誤之處,歡迎指正。
參考資料
理解本真的REST:http://www.infoq.com/cn/articles/understanding-restful-style/
架構風格與基於網路的軟體架構設計-導讀:http://www.infoq.com/cn/articles/doctor-fielding-article-review
架構風格與基於網路的軟體架構設計:http://www.infoq.com/cn/minibooks/web-based-apps-archit-design