1. 程式人生 > >淺談管道模型(Pipeline)

淺談管道模型(Pipeline)

本篇和大家談談一種通用的設計與處理模型——Pipeline(管道)。

Pipeline簡介

Pipeline模型最早被使用在Unix作業系統中。據稱,如果說Unix是計算機文明中最偉大的發明,那麼,Unix下的Pipe管道就是跟隨Unix所帶來的另一個偉大的發明【1】。我認為管道的出現,所要解決的問題,還是軟體設計中老生常談的設計目標——高內聚,低耦合。它以一種“鏈式模型”來串接不同的程式或者不同的元件,讓它們組成一條直線的工作流。這樣給定一個完整的輸入,經過各個元件的先後協同處理,得到唯一的最終輸出。

Pipeline模型的應用

以下列舉了,我熟悉或者有所瞭解的典型pipeline模型的應用。

公司.net web程式設計師很多,那麼首先就談談asp.net。一個http請求到達http伺服器IIS之後,就是經過pipeline模型被處理的。參見下圖:


說明一下,這幅圖,並沒有下面的圖形來得直觀。它的側重點在於展示管道中各個元件處理事件觸發的時序圖,而不是pipeline模型。但如果你思考以下,也能體會到其中“管道”的概念(注意右面迴圈圖示,如果需要比劃一下的話,就是一個U逆時針旋轉90度的形狀)。

最後,我還是決定上個清晰點的圖:


上圖可以請求到達IIS,經過HttpApplication工廠得到一個HttpApplication,建立一個HttpContext上下文,然後就會進入Http Pipeline。好了,這篇的目標並不是談論http處理行為以及asp.net底層架構,所以到此為止。

又一個大家熟悉的web container,特別是java web人員——Tomcat

Tomcat接受請求之後,請求從被接受,被分發,被處理,到最後轉變成http響應,會走如下的管道【2】:


在《Tomcat系統架構與設計模式,第2部分: 設計模式分析》【3】中,你可以清晰地發現一個最為顯而易見的設計模式——責任鏈模式(這是實現管道模型比較常用的一種設計模式)


可見,pipeline模型幾乎是大部分主流http server處理請求的通用模型。這種設計並不意外,因為pipeline模型特定的理念會讓你感覺到它似乎就是為了處理請求而生的。事實上,它的應用原不止這些web 伺服器架構。

下面,給大家帶來的另一個典型示例也是在web架構裡廣為人知的MVC模型的良好實踐——Struts:


我認為用這幅圖來闡述Pipeline最為清晰,簡潔。從上面這幅圖中你能夠看到對於pipeline模型的多處使用(單向、雙向都有)。它也很好地展示了高內聚,低耦合的設計目標,展示了各個元件以類似“搭建積木”的形式來組合功能(見圖中Interceptor),我最近有空也在讀struts2的原始碼,如果你也有興趣,可以看看這個

專題

最後一個示例了,公司Java伺服器的開發人員,相信都會對Mina框架有所瞭解。下面是Mina的處理模型圖:


不再廢話了,同樣是pipeline的優秀實踐。

上面介紹了很多pipeline的優秀實踐,他們並非來自同一個領域,有web端,有處理socket的等。但對於他們的一個歸納,可以是——優秀的服務端資料處理模型,我覺得公司在資料處理上比較頻繁,這也是選擇介紹pipeline模型的原因。

Pipeline模型帶來的啟示

其實,關於它的好處已經在上面各種優秀的實踐中得以體現。但你還是應該能夠從中去發現一些能夠為我們所用的設計思想。我總結了我得一些觀點,歡迎各位拍磚:

(1)    工作流的參考模型

上面的各個模型圖很難讓我不把pipeline模型與工作流模型聯想到一塊兒去。他們都是鏈式的(或者說流程式的),就像一條生產線一樣。各個元件的前後協同,會讓你聯想到生產流水線上得工人處理流過自己的產品環節。事實上,我在去年年末的時候在雲方圓徐工基礎任務流程裡面曾經嘗試使用了該模型,作為工作流模型

(2)    服務framework的參考構建模型

Pipeline模型的一個特點是,在其內部是以組建的模式來實現組合的(雖然這些組建有先後順序之分),它假如你把側重點放在它的鏈式組合上,而不是將側重點放在上面的工作流上(工作流的關注點是流程的先後順序),那麼完全可以用這種方式來搭建一個複雜的服務,當然這樣做的前提是,單個元件的粒度必須儘可能小並且耦合性極低。

在這裡我冒昧吐槽幾句:

在我的印象中,公司很多服務都喜歡採用WebService,即使不是Web Service也是Http GET請求。當然,這其中的很多情況是不得不採用它來和別的系統或者業務平臺互動。但我一直堅持認為,只有在理論上你根本沒有可能拿到那些資料時,你才會採用別人提供的服務,比如:股票行情、天氣預報、各大開放平臺(新浪、支付寶)的API的等。本公司之內的,原則上其實可以訪問的某些資料,有時我們反而退而求其次選擇採用Web Service這種模式。批量資料走http或者之上的協議(SOAP)在網路上傳輸,有時web系統還有可能釋出在遠端。想要效能從哪兒來?我瞭解你擔心安全性,希望保持本業務平臺數據庫的獨立性。告訴我,其實你也明白有些擔心是沒有意義的。我直接連你的庫,只做一些查詢會有什麼問題?如果你真的比較謹慎的話,你也應該擔心一下你的系統有被攻擊的可能性,為什麼你沒有呢。甚至有人希望,某些相似的業務邏輯也把他抽象出來在dll外面包裝成web service。如果真得是這樣的話,我覺得“可複用的元件”這個詞就沒有必要存在了。

Pipeline模型應用

剛才談到,我認為Pipeline模型帶來的啟示,我個人更看好第二點。我認為在NGP構建API的時候,這種模型也能夠派上大用場。

就拿Redis舉個例子(在一些場景下):

讀取資料流程

(1)    客戶程式從Redis讀取資料,如果讀取到則返回

(2)    如果沒有讀取到,則從資料庫抓取資料

(3)    從資料庫抓取到的資料儲存到Redis

寫入資料流程

(1)    客戶程式將資料寫入Redis

(2)    將資料寫入資料庫

假如有一天,你不打算採用Redis,或者Redis服務全部不可用。你怎麼讓客戶端自己能夠“智慧感知”,讓這些巨大的後端變動對於客戶端透明,並且不會產生呼叫異常?那麼Pipeline模型,就可以派上用場。因為上面這些流程都是可配置的,而開放的API是唯一的。

你是否會覺得普通的封裝也能夠實現上面的讀取資料流程?沒錯,也可以。但我認為Pipeline模型帶來的:流程式(有序)+可拆卸(配置),比普通的封裝機動性更好。

當然,這裡只是選擇了一個簡單的場景來舉個例子。

Pipeline模型實現

其實在上面那個Tomcat的設計模式截圖中已經看到,實現該模型最通常的設計模式就是責任鏈模式,在上面工作流那篇文章中,也是採用責任鏈模式來實現,但我當時忽略了一個非常重要的東西——Context,這是串聯整個Pipeline的重要前提。

你找到一篇任何介紹責任鏈模式的文章,然後搭配淘寶的《基於管道模式的容器設計》【4】就基本能夠完全瞭解Pipeline。

Pipeline模式的缺點

沒有那種模式是完美的。Pipeline模式的缺點是,每次它對於一個輸入(或者一次請求)都必須從鏈頭開始遍歷(參考Http Server處理請求就能明白),這確實存在一定的效能損耗。

引用