記一份關於HTTP服務的七層架構技術解析及運用

前言

今天簡單記錄一下關於HTTP服務的七層架構技術解析及運用

一般來說,計算機領域的體系結構普遍採用了分層的方式,從整體結構來看:

從最底層的硬件往高層依次有:

操作系統 -> 驅動程序 -> 運行庫 -> 系統程序 -> 應用程序等等。

從網絡分層模型OSI來講,由上至下爲:

應用層 -> 表示層 -> 會話層 -> 傳輸層 -> 網絡層 -> 數據鏈路層 -> 物理層

當然實際應用的TCP/IP協議的分層就沒OSI標準這麼複雜。

從C語言文件編寫到生成可執行文件的過程來看:

預處理(展開後的C語言代碼) -> 編譯成彙編語言(特定CPU體系結構的彙編語言源文件) -> 彙編器生成目標文件(CPU可執行的二進制指令機器碼)

-> 鏈接器連接目標文件生成可執行文件(操作系統可以加載執行的二進制文件)

雖說這不算是軟件的分層結構,但是可以理解爲一種通過分層來簡化複雜問題的思想,那麼,PHP語言可以認爲是建立在C語言之上的層——其解釋器

Zend引擎是用C語言實現,畢竟用PHP這樣的腳本語言編寫動態網頁要比用C語言方便得多。

當然還有我們最熟悉的MVC分層技術了,對於分層的好處,想必大家都已經比較熟悉了,這是一種“分而治之 大而化小”的思想。

說到分層就不得不提模塊了,其實分層和模塊是從兩種維度來進行“分而治之”的方式,模塊是從橫向維度來將一個整體分割成若干個獨立的部分,

每個部分行使獨立自己的職責,當然它們之間也可能有依賴關係,這通過其對外提供的服務來實現。

如果將整個系統比做中國版圖的話,那麼模塊方式將中國分爲省,自治區等。分層則是從縱向緯度將一個整體從高至低劃分爲若干個獨立的層,

一個完整的服務由底層至上層,層層傳遞最終產出。

分層和模塊可以同時運用,例如中國用模塊方式分爲省之後,然後每個省的行政機構利用分層方式來行使職責,

從低到高有戶,村,鄉,區,市,省等等,每一層都向上一層彙報。

分層和模塊會提高系統複雜度並影響效率(戶不能直接向省彙報,而需要一級一級向上彙報),但是這樣有利系統的擴展和維護,

每一層只需要關注自己提供的服務接口以及它下一層所提供的服務接口,試想一下如果省需要接受來自市,區,鄉,村等所有下級層的彙報,那些省幹部會很頭疼的。

一、HTTP服務傳統的三層架構MVC

HTTP服務中最經典的分層架構非MVC莫屬了,幾乎任何一個PHP開發框架都是支持MVC分層模式,此模式歷史也比較悠久,

是在上個世紀八十年代爲編程語言Smalltalk設計的軟件模式,至今已經被廣泛引用,如下圖所示:

本文主要講的是HTTP服務七層架構技術,比MVC多出了四層,這樣複雜的分層是否有必要呢?

關於這個問題仁者見仁智者見智,有些人認爲MVC分層粒度不夠精細,當然你也可以繼續堅持傳統的三層,那麼後文你也沒必要看下去了。

那麼爲什麼MVC分層不夠精細呢,在我曾經使用開源框架的MVC模式的經驗中發現,V和C層功能職責一般都很清晰穩定,但是M層卻常常顯得臃腫笨拙。

C層主要是負責整體流程控制,一般規範的架構中,流程都可以用一張或幾張流程圖畫出,那麼表明流程一般都是固定的。

V層主要是負責頁面呈現,可能使用smarty模板引擎,也可能是自帶的模板引擎,顯示的頁面可能是HTML,XML或則JSON,

這些種類再多也都是可以度量的,所以M層也可以說是固定的。

而M層卻關係到系統的業務邏輯,隨着系統不斷迭代更新,M層中的內容也會不斷演變,而這一層中也有很多複雜的處理,

如文件讀取,數據庫查詢,緩存策略,邏輯運算,數據加工,數據打包等等。

所以MVC三層模型中,M層是還能再做細分的,當M層有一個更精細合理的分層方式之後,我們的業務邏輯演變過程會更加的得心應手。

二、HTTP服務七層架構

由上面的介紹,那麼我們對MVC中的M層再進行分層規劃,這裏給出的是一種對M層分五層的方式,

讀者如果覺得五層太多或則太少那麼可以參考這個再進行規劃。

原來的M層被分爲:

A層:Application 應用層

B層:Business 業務層

C層:Component 組件層

D層:Datadriver 數據驅動層

S層:Systemdriver 系統驅動層

那麼整個七層架構則爲:

1、Controller

2、View

3、Application

4、Business

5、Component

6、Datadriver

7、Systemdriver

結構圖還是參考經典MVC,將其中M層換成新的五層即可。

下面就依次給大家介紹一下這幾個新的層:

1、Application

應用層在最上面,其針對實際中的單個頁面或則單個接口,Controller通過HTTP請求地址中的參數找到對應的Application,

然後執行中指定的公共方法,比如main(),然後應用就開始啓動。

應用層的職責包括接受HTTP參數(一般是間接接受,比如從request對象中獲取),調用Business層的特定業務,

保存業務執行結果,這些結果最終會由View顯示出來,當然是通過Controller協調。應用層是M層分解成五層之後最高的層,Controller會與此層直接通信。

2、Business

業務層在應用層之下,通常一個應用實例對應一個業務實例,而一個業務有可能爲多個應用服務,業務是一個執行流,它通過執行一系列的操作來完成應用的需求。

這些操作來自下層的組件層Component,可能一個業務需要一個或則多個組件來完成一個完整的需求。因爲一個業務實例通常只對應一個功能,

所以只有一個固定的方法會被上層的應用調用,比如flow()。業務層的職責是幫應用層執行業務流並且有必要的時候返回數據給應用層,它會調用下層Component的方法。

3、Component

從組件層開始和上面兩層有一個本質的區別,組件層開始有了類庫的概念。前面兩層的實例通常只暴露一個特殊約定的公共的方法讓上層調用,

從這一層開始一個實例會提供多個方法給上層。

組件層通常和系統中一個角色對應,例如在博客系統中,博文是一個角色,用戶是一個角色,那麼就會有博文組件BlogComponent,

用戶組件UserComponent,每個角色都有對應的操作,例如博文和用戶都可以添加刪除修改。

需要注意組件層中不應該有任何數據讀取的操作,數據讀取是下層數據驅動層來做的。如果組件層從下層獲取了數據,

那麼它的一個職責就是對數據進行加工。

例如BlogComponent有一個方法是獲取一個博文getBlog($id),那麼getBlog()方法中,從數據驅動層中取得了對應id的博文數據之後,

需要對博文數據進行一定的處理,比如將博文中的HTML特殊標籤過濾等等。

組件層不關心數據的讀取方式,但是會關心數據的結果,比如數據不存在或則數據已經過期。

4、Datadriver

數據驅動層的職責是爲組件層提供源數據,此層關心數據的存取介質,存取方式等等,數據可能被存儲在DB,MC,Filesystem或則遠程的HTTP服務器上。

數據驅動層不關心數據的內容,只關心數據讀取的操作結果,例如假設數據存在DB中,但是數據驅動層在執行數據庫查詢的時候出錯了,那麼需要在此層處理。

假設數據存儲在遠程的HTTP服務器上,那麼數據驅動層需要關心HTTP返回碼是否爲正確的200系列或則錯誤的400,500系列,

哪怕HTTP請求返回了錯誤的數據實體,但是返回碼爲200,那麼數據驅動層也不關心,這種情況需要上層組件層來處理。

5、Systemdriver

系統驅動層是系統環境提供的數據訪問實例,例如數據庫服務的Systemdriver可能是一個db handler,

HTTP服務的Systemdriver可能是一個http handler,文件存儲系統驅動層可能是一個file handler, 系統驅動層相對簡單,

這層可以和數據驅動層進行合併,其職責也較少。僅僅只是執行數據驅動層的數據訪問指令。

通常情況下這五個層中,上層的實例數量比下層的實例數量要多,整體類似一個倒置的梯形,如下圖所示:

在上圖中一共有6個Application,5個Business,4個Component,3個Datadriver,2個Systemdriver。

每個Application都由一個Business爲其服務。

每個Business都服務一個或則多個Application(B5同時服務A5 A6),都有一個或則多個Componet爲其服務。

每個Component爲一個或則多個Business服務,都有一個或則多個Datadriver爲其服務。

每個Datadriver爲一個或則多個Component服務,都有一個或則多個Systemdriver爲其服務。

每個Systemdriver爲一個或則多個Datadriver服務。

三、HTTP服務的七層架構運用

現在運用這樣的架構來設計一個簡單的博客系統,服務端用PHP語言實現,當然,架構是思想,不區分語言。

整個系統包含以下功能:

1、發佈博文

2、修改博文

3、刪除博文

4、評論博文

5、修改用戶信息

要求每個功能都記錄操作日誌。

設計的數據存儲包括:

1、博文數據表

2、用戶數據表

3、評論數據表

4、日誌(存文件系統)

在表結構設計的時候我們加入了一些冗餘字段信息,例如在博文表中有評論數量字段comment_nums, 博文每被評論一次其值加1,每刪除一個評論其值減1。

用戶數據表中我們添加了用戶發佈的博文數量字段blog_nums,用戶每發佈一篇博文其值加1,每刪除一篇博文其值減1。

下面設計分層:

應用層,一共有5個應用:

1、PostBlogApplication 發佈博文

2、UpdateBlogApplication 修改博文

3、DeleteBlogApplication 刪除博文

4、CommentBlogApplication 評論博文

5、UpdateUserApplication 修改用戶信息

業務層,這5個應用分別有5個業務對其服務:

1、PostBlogBusiness 博文發佈業務

2、UpdateBlogBusiness 博文修改業務

3、DeleteBlogBusiness 博文刪除業務

4、CommentBlogBusiness 博文評論業務

5、UpdateUserBusiness 用戶修改業務

組件層,系統一共有4個角色對應4個組件:

1、BlogComponent 博文組件

提供方法包括:

(1)、postBlog() 發佈博文

(2)、deleteBlog()刪除博文

(3)、updateBlog()修改博文

(4)、getBlog()獲取博文內容

2、CommentComponent 評論組件

提供方法包括:

(1)、postComment() 發佈評論

(2)、deleteComment() 刪除評論

3、UserComponent 用戶組件

提供方法包括:

updateUser() 修改用戶信息

4、LogComponent 日誌組件

提供方法包括:

logMsg() 記錄日誌信息

數據驅動層和4個組件對應

1、BlogDatadriver DB類型 提供blog的select insert delete update

2、CommentDatadriver DB類型 提供comment的select insert delete update

3、UserDatadriver DB類型 提供user的select insert delete update

4、LogDatadriver FS類型 提供file的read write

系統驅動層: DB類型和FS類型

1、MySqlSystemdriver DB的handler

2、FileSystemdriver FS的handler

1、Controller通過重寫規則發現其對應的Application爲PostBlogApplication,於是PostBlogApplication被實例化,

並且其中的特殊方法main()會被自動調用。

2、postBlogApplication需要PostBlogBusiness業務來完成博文發佈操作,PostBlogBusiness被實例化,

並且其中的特殊方法flow()會被調用。

3、根據需求,發佈博文的時候需要在博文表中插入一條博文,然後修改用戶信息中的博文數量字段。

那麼postBlogBusiness業務流就包括兩個操作,這兩個操作分別由BlogComponent中的postBlog()方法

和UserComponent中的updateUser()方法來實現,其中前者往博文表中插入博文信息,後者將用戶信息中的博文數量字段加1。

由於系統要求任何操作都需要記錄日誌,因此還有第三個操作就是記錄日誌,通過BlogComponent的logMsg()方法實現,

那麼PostBlogBusiness業務流一共包括了三個操作,分別由三個組件來完成。

4、下面就需要分別考慮上面三個組件的下層調用了

其中BlogComponet的postBlog()調用BlogDatadriver的insert相關方法來插入博文數據,BlogDatadriver是DB類型,

因此通過MySqlSystemdriver 來實現。

UserComponent的updateUser()調用UserDatadriver的update相關方法來實現博文數量更新,UserDatadriver也是DB類型,因此也通過MySqlSystemdriver 來實現。

LogComponent的logMsg()調用LogDatadriver的write相關方法,LogDatadriver是FS類型,因此通過FileSystemdriver 來實現。

5、三個組件的操作都執行成功後,PostBlogBusiness告訴postBlogApplication博文發佈成功,然後postBlogApplication通過Controller來調用View相關的方法顯示執行結果。

對於其他幾個操作流程,大家可以舉一反三,這裏就不再多介紹了。

分層帶來的益處:

現在我們通過幾個系統功能的演變用例來看看這個分層帶來的益處:

用例1:爲了方便對日誌的管理,現在希望能夠將日誌存儲在DB中而不是FS中。

解決方法:這是對數據存儲的改造,我們知道應該從數據驅動層入手。日誌功能是由日誌組件LogComponent實現的,

其中LogComponet的了logMsg()方法調用LogDatadriver來存日誌。我們將LogDatadriver由FS類型改造成DB類型,接口方法保持不變,這樣很快就完成了改造。

用例2:新增需求-用戶A可以將一篇博文轉移給另外一個用戶B。

解決方法:

步驟1:首先這個新需求對應了一個新的應用,於是我們新增了一個SendBlogApplication。

步驟2:需要有一個業務完成操作,新增業務爲SendBlogBusiness。

步驟3:考慮轉移一篇博文涉及到的操作:①、將博文表中對應的用戶ID字段由A的ID切換到B的ID;②、A用戶的博文數量減1;③、B用戶的博文數量加1。

這三個操作需要兩個組件來完成,這兩個組件我們系統中已經有了,BlogComponent的updateBlog ()完成操作1,UserComponent的updateUser()完成操作2,3。

從用例2可以看出,當新增了這麼一個需求的時候,我們在應用層和業務層添加了實例,組件層以下都不變,

這是因爲現在的組件層已經能夠滿足新的業務的需求,當我們現有組件無法滿足新的一業務需求的時候,我們則需要對組件層做修改。

通過這兩個簡單的用例我們發現我們對系統的修改要麼可以很明確的確定在哪些層,要麼就是從上層組件往下層進行,操作起來很方便。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章