作者:人月神話,新浪博客同名
簡介:多年SOA規劃建設,私有云PaaS平台架構設計經驗,長期從事一線項目實踐
今天談下傳統ESB服務總線裏面的可視化服務設計,服務組合編排和微服務裏面的服務編排。對於服務組合編排,實際上我們看到有幾個不同的場景。
- 單服務可視化設計-僅僅針對一個服務實現
- 服務組合編排-實現多個服務的組合形成一個新的服務
- 業務流程編排-通過服務組合編排實現要給完整的業務流程
對於業務流程編排可以看到更多的是通過類似BPEL業務流程設計器來完成,因此今天主要介紹下傳統ESB服務總線裏面的單個服務設計,多服務組合設計編排,同時再介紹下NetflixConductor微服務編排的開源實現。
單個服務的可視化設計單個服務的可視化設計可以理解為實現單個服務的可視化服務設計,其中包括了服務適配,路由,數據映射,協議轉換等常見的編排節點和組件。
對於單服務設計可能用到的組件,我們基於服務集成場景,主要可以分為服務發佈類組件,服務適配類組件,數據映射類組件。具體的組件包括了:
服務發佈類組件(只需要支持SOAP WS服務和Rest WS服務即可)
- SOAP Proxy WS組件:發佈代理服務
- SOAP Business WS組件:發佈業務服務,銜接原始的業務服務地址
- Rest Proxy WS組件:發佈基於Rest風格的代理服務
- Rest Business WS組件:發佈業務服務,銜接原始的Rest業務服務地址
- SOAP WS Request組件和 SOAP WS Response組件
- Rest WS Request組件和 Rest WS Response組件
適配器組件
- DBSqlQuery組件:實現對數據庫的Sql數據查詢能力。
- DBSqlInsertOrUpdate組件:實現對數據庫的Insert或Update操作適配能力。
- DBStoreProc組件:實現對數據庫存儲過程的適配能力。
- FTPInput或FileInput組件:實現對源端的數據獲取能力
- FTPOutput或FileOutput組件:實現對FTP服務器目標端的適配能力
- JMSInput組件:實現對JMS寫入能力
- JMSOutput組件:實現對JMS的消費和訂閲能力
數據映射類組件
- XMLMapping組件:實現兩個XML結構之間的數據映射能力
- tMapping組件:實現ETL時候兩個數據集之間的數據映射能力
基於以上組件我們可以來看,常見的服務集成場景用上面的設計器組件基本就能夠滿足,同時實現最簡單額設計組件之間的組合和連接。而設計器本身是一個設計態的東西,因此只需要將設計完成的內容,即設計元數據存儲為一個獨立的XML文件即可。
後續基於設計文件要做的就是進行實際的服務封裝和部署,而這個時候才需要將設計器的內容進行解析,進行動態的服務封裝和部署工作。以實現服務設計態和服務運行態的自動銜接能力。
多個服務組合編排服務組合編排是服務組合,服務組裝等,希望通過服務編排能夠完成這些事情,而不是簡單的完成單一服務的設計和開發。即將多個原子服務組合或組裝在一起,最終形成一個新的服務並提供的能力。我們舉例來説明下。
比如存在A,B,C三個原子服務,我們通過服務編排形成一個新的D服務。
三個原子服務全部是查詢服務,希望組裝一個新服務,一次返回A,B,C三個服務查詢結果
這個即我們説的服務組合能力,比如我們可以對合同基本信息查詢,合同條款信息查詢,合同執行信息查詢三個基本原子服務進行組合,最終返回一個服務綜合信息查詢的服務,一次返回三個查詢結果。
在這種場景下我們需要考慮查詢結果是並行返回還是按層次返回即可。
二個查詢類的原子服務,最終需要返回兩個數據集關聯查詢的結果集
這個在微服務架構做了底層數據庫拆分後經常會遇到,比如對於物料基本信息查詢,和採購訂單明細查詢是在兩個獨立的數據庫獨立服務提供。而我們希望返回的查詢結果集是物料編碼,名稱,型號,單位,價格,採購數量的複合結果集。
這種場景下往往一般都是在前端功能開發的時候進行組裝,而實際上可以考慮是否可以在服務編排層解決這個問題,該問題寫代碼來解決容易,但是要做為可視化服務編排組態方式來做實際上有一定的難度。
對單個已有服務進行裁剪和豐富並形成一個新服務輸出
這個暫時也將其納入到服務編排的範疇,即仍然是輸入服務,但是輸出是提供了一個新服務。
即對單個已有的服務進行服務裁剪和豐富,比如對於輸出結果過濾掉一些數據項,對於輸入固定輸入一些數據項等。這些簡單的服務裁剪,豐富,或簡單的數據轉換可以在服務編排的時候完成,並提供一個新服務。
對多個原子服務進行流程式的前後串接並形成服務提供
這個是我們經常看到的一種服務編排場景,即A,B,C三個服務直接進行編排,即A服務的輸出直接變為B服務的輸入,B服務的輸出又變為C服務的輸出。如果僅僅是上面假設的這樣,那麼這種流程式的服務編排仍然很簡單,也很容易去實現。
但是實際上的難點在於A服務的輸出本身也需要作為C服務的輸出,同時A,B服務的輸出也可能是整體輸出的一部分,這本身就加大了服務編排可視化設計的難度。
單一業務服務為主體服務,但是編排多個業務規則邏輯處理類服務
這也是經常會遇到的場景,比如我們在進行合同信息導入的時候,首先要調用合同有效性校驗服務,同時還有調用預算信息檢查和扣減服務進行相關的完整性和業務規則校驗。在這些校驗完成後再調用實際的合同信息導入服務,如果校驗失敗則直接返回失敗結果。
這類服務編排往往也正是我們實際在進行前端功能開發時候服務進行組裝的邏輯。
多個導入服務組裝為一個導入服務合併導入並形成一個新服務
這個場景實際上和場景1是對應的,既然多個服務可以組合後形成組合結果返回,那麼自然可以將多個導入服務合併為一個導入服務,一次性的完成數據導入。
比如有項目信息導入和項目WBS信息導入兩個原子服務,那麼我們就可以提供一個新的項目信息導入服務,一次完成項目基本信息和項目WBS信息的導入。
在這些場景裏面可以看到,實際上服務編排就是服務串聯,服務並聯下的輸入和輸出合併,服務內容豐富和裁剪等常見場景。在一個理想的場景下,我們最希望實現的就是一個業務功能點的實現完全能夠通過服務編排可視化設計方式來完成。
下面我們來分析和討論下服務編排的可視化設計。
a. 定義一個新服務,需要提前考慮新服務輸入和輸出結構設計
要進行服務編排,實際上編排完成後是新產生一個新服務,那麼新服務一定有輸入和輸出結構,那麼就需要對新服務的輸入和輸出結構進行設計。一種方法是在服務編排的時候再對輸入和輸出結構進行定義,一種方法是提前對新服務的服務契約進行定義,服務契約定義好後就形成了標準的服務輸入和輸出結構。
對於定義的服務編排產生的新服務,拖拽到設計器後應該產生輸入和輸出兩個獨立節點,這個在我們做單服務的ESB服務設計器的時候思路是一致的。
b. 服務之間的連接,本質是服務輸入和輸出之間的連接和映射
要明白服務之間的連接本質是輸入和輸出之間的連接和映射。以三個原子服務全部是查詢服務,我們希望組裝一個新服務,一次返回A,B,C三個服務查詢結果,這個場景來舉例説明。
我們需要拖拽A,B,C三個原子服務節點到設計器裏面,然後將新服務的輸入連線到A,B,C三個原子服務節點。在連接完成後,我們需要將新服務的輸入和ABC三個服務的輸入之間進行數據映射。
其次我們需要將ABC三個服務的輸出連接到新服務的輸出。對於新服務的輸出,我們同樣需要完成數據項之間的映射。但是這裏的複雜性體現在ABC三個服務輸出的三個結果集之間究竟是並行關係,還是父子層次關係,在進行數據映射和合並返回的時候,我們需要提前進行三個結果集的層次關係定義。這裏面場景包括
- 結果集並行結構返回多個
- 結果集返回層一個層次結構的結果集返回
- 對多個結果集類似Sql一樣進行查詢關聯,返回一個結果集作為結果
以上三種則是我們場景的對服務查詢結果進行處理,合併或關聯的方式。
c. 對服務流程式的串聯和順序處理,重點需要解決跨多節點數據映射問題
這個前面已經講過,即將A,B,C三個服務進行串聯方式編排的時候,實際我們看到B結果的輸入只能夠是A節點的輸出,但是服務C的輸入卻可以同時是A或B的輸出。因此在編排完成後進行數據映射的時候,一定需要支持C節點的輸入可以同時映射到A或B的輸出數據項元素。
d. 對於規則計算節點的兩種可能,簡單規則節點和複雜規則節點
對於規則節點需要考慮兩種可能性,一種是常見的簡單規則節點,即進行簡單的加減乘除運算得出一個規則,基於規則判斷後能夠走不同的分支對結果進行處理。另外一種可能即將輸入送入到規則引擎進行處理,處理完成後返回一個結果,如果在不連接規則引擎的情況下,我們可以設計一個專門的WS服務節點,即該節點可以去調用外部服務並返回輸出結果,並基於輸出結果情況進行判斷,基於判斷走不同的分支。
注意這種規則WS服務節點僅僅是進行規則處理,而非整個服務編排的主體輸入和輸出。實際我們在進行服務編排設計的時候,最好不要將這類節點放在主體服務編排路徑上面。
NetflixConductor微服務編排對於服務編排的可視化設計,其中最核心的還是服務編排本身任務或活動節點對應的是原子服務,連線對應的是服務輸入輸出之間的映射,整個編排完成是形成一個新的接口服務能力,這就是服務編排要做的事情。如果無法滿足上面的核心,那談不上服務編排。
今天談下開源的微服務編排Netflix Conductor,先説下具體的場景,這個是Netflix內容平台工程團隊運行由微服務上執行的任務的異步編排驅動的多個業務流程。其中一些是長期運行的流程,跨越幾天。這些流程在準備好標題流式傳輸給全球的觀眾上發揮關鍵作用。
這些流程的幾個實例是:
- 用於內容提取的Studio合作伙伴集成
- 基於IMF的內容提取我們的合作伙伴
- 在Netflix中設置新標題的過程
- 內容提取、編碼和部署到CDN
傳統上,這些流程中的一些已經以ad-hoc方式使用pub/sub的組合來編排,進行直接REST調用,並使用數據庫來管理狀態。然而,隨着微服務數量的增長和進程的複雜性增加,在沒有中央編排器的情況下,獲得對這些分佈式工作流的可見性變得困難。我們將Conductor構建為一個編排引擎,以滿足以下要求,取出在應用程序中需要的樣板,並提供一個反應流:
基於藍圖。基於JSON DSL的藍圖定義執行流程。
- 跟蹤和管理工作流。
- 能夠暫停、恢復和重新啓動進程。
- 能夠擴展到數百萬個併發運行的進程流。
- 由從客户端抽象的排隊服務支持。
- 能夠通過HTTP或其他傳輸方式進行操作,如 gRPC。
基於上面介紹可以看到Netflix Conductor最重要的還是實現了基本的工作流定義,任務定義,任務的連接,整個工作流的任務調度和監控等基本能力。
官方參考文檔:
實例參考文檔:
對於具體的功能説明和介紹參考上面兩篇文章即可,在此不再重複進行描述,只對看完了整個Netflix Conductor功能實現後做一下簡單總結。
在Netflix Conductor中任務節點的定義雖然可以定義詳細的輸入和輸出,但是任務節點並不是服務引用節點,任務節點具體需要開發實現類來進行實現。那麼我們場景裏面説的任務節點即服務節點,任務的輸入或輸出就是服務的輸入或輸出是無法實現的,如果要實現也需要進行大量的定製開發才能夠支持。
微服務編排完成後可以形成一個新的Http Rest服務接口,這個是我們需要的。同時對於編排完成的workflow本身是可以實現靈活的任務監控和任務調度,滿足基本的流程引擎該有的功能。
沒有看到可以進行可視化服務編排設計的地方,但是對於編排完成的模型文件可以展現為可視化的流程圖展示,這個也是很多編排軟件常用的做法。由於沒有可視化設計,當前的輸入輸出數據項映射也在手工編寫流程模板文件的時候完成數據映射工作。但是可以實現前面多個節點的輸出朝後續節點傳遞的需求。
工作流設計完成後,可以看到仍然需要寫大量的代碼和實現類才能夠完成工作流的運行,因此可以看到該開源軟件並不能實現完全的面向業務或開發人員的可配置零編碼的效果。
基於以上初步分析可以看到,Netflix Conductor開源微服務編排框架並不滿足我們前面描述的微服務編排場景,如果要實現服務和服務之間的編排,實際上對該開源軟件的定製和改造工作量相當大。因此在我們實現微服務編排的時候並不建議選擇該開源軟件。其次,在整個微服務架構體系中,也不建議採用Netflix Conductor,至少在前期的改造過程中使用的場景很小,完全可以用其他方式來替代。
歡迎關注@人月聊IT 分享SOA,微服務,DevOps平台規劃和建設。