今天再重新整理下我對服務組合和服務視覺化編排的一些思考。
從整個服務分層的角度來說,微服務最底層首先提供的是原子服務,再朝上則可以提供更加粗顆粒度的組合服務能力。
為何要進行服務組合和編排?
簡單來說就是進一步將共性的可複用業務能力下沉,這些共性業務能力有些是在前端開發中,開發人員自己進行組合和編排完成的。那麼實際這塊內容應該下沉到一個統一的領域服務能力提供層。
在前後端開發分離的情況下,實際上對於前端人員往往並不熟悉和精通業務,如果是簡單的UI介面互動呼叫多個介面服務,前端來做沒有問題。但是對於本身和業務場景和業務規則相關的服務組合,前端實際上很難在清楚業務情況下進行編排。
比如對於一個訂單提交,前端來說就是準備好資料呼叫介面,但是實際一個訂單提交涉及到訂單保持,庫存扣減,預算檢查,支付請求生成等多個API介面能力。而這些如何組合,按什麼順序呼叫已經和業務規則邏輯相關,而且往往還需要事務控制。
類似上面事情則不適合前端來做,而應該透過服務組合來完成,即使沒有視覺化的服務組合編排工具,那麼這部分工作也應該在微服務架構中,由一個領域服務層來進行提供。
簡單輸入-組合輸出這個是在開發中經常會遇到的一個場景。比如在實現一個訂單檢視功能的時候,在訂單詳細介面裡面往往涉及到訂單資訊,使用者詳細資訊,訂購的酒店資訊,房間詳細資訊,付款資訊多個資訊展示功能。
如果是前端開發來做,那麼往往前端開發需要呼叫多個後臺的API介面服務來完成資料的獲取和填充。而透過服務組合則可以透過一次組合服務呼叫來返回所有資訊。
整個服務組合過程可以簡化如下:
在這個圖裡面實際上有兩個關鍵點。
其一是一個服務的輸出可以選擇某些資料專案資訊作為下游服務的輸入。其二是任何一個服務的輸出資訊都可以作為最終服務的輸出組合。
那麼如何來實現呢?
整體思路我們完全可以借鑑傳統ESB裡面進行服務組合設計的思路,即首先定一個新的組合服務,並確定該API介面服務的契約格式。然後基於該新服務進行服務組合和資料對映。
整體實現的難度實際體現在兩點。
其一是資料對映節點的設計,該資料對映需要是一個獨立的設計節點,在該節點完成上一個介面服務的輸出到下一個介面服務輸入之間資料格式的對映和轉化操作。
比如前面這個例子,訂單查詢介面查詢出來的json資料中,只獲取到userid資訊,即可去觸發呼叫使用者查詢介面。而一個訂單可以預定多個方面,那麼這裡就需要獲取到一個roomidList的json資料作為入口傳遞給房間資訊獲取介面。
因此,在對映裡面不是簡單的資料項對映,還涉及到資料集合的對映等。
其二是資料組合格式的處理,要明白實際最終輸出的是要給多個查詢返回的組合資料集,那麼資料集本身就會有結構,有層次體現。因此在最終返回資料集的資料對映中,需要處理這種組合資料格式,包括每個獨立介面服務返回資訊具體對映到哪層,和主節點的ID依賴關係等。
序列處理中的事務對於API介面服務,本身是無狀態的,因此當呼叫多個服務進行序列編排的時候,不是簡單地輸入和輸出的組合和資料對映。更加重要的是分散式事務處理。
在服務編排中的分散式事務處理實際推薦兩種方式。
其一是事務補償其二是非同步最終一致性對於事務補償,那需要在提供服務編排和接入的時候,基於服務冪等性提供要給逆向操作服務。而對於非同步最終一致性則需要服務組合中提供底層的訊息中介軟體來實現非同步和訊息重試能力。
舉個簡單的例子來進行說明。
對於訂單提交的時候,我們需要呼叫訂單儲存服務,在訂單儲存成功的時候呼叫庫存扣減服務介面扣減庫存。同時給使用者傳送訂單提交成功的郵件通知。
以上是一個常見的三個服務的序列編排操作。在這個過程中對於訂單儲存和庫存扣減我們採用補償機制,先進行庫存扣減,再進行訂單儲存,如果訂單儲存失敗則對庫存扣減回退。
而對於郵件傳送我們採用非同步方式介面,即確保事務最終一致性即可。
因此在進行服務編排設計的時候,上游服務應該提供冪等的逆服務用於編排,方便下游服務調用出現異常的時候對上游服務進行回滾操作。
而對於類似傳送訊息,事件等介面服務,則建議採用訊息中介軟體來實現非同步最終一致性。在這種情況下即使呼叫失敗也不進行上游服務回滾,而是服務編排實現中對服務進行重試處理。如果多次重試仍然失敗再發送異常日誌資訊供人工修復處理。
對傳統BPEL流程編排的簡化在傳統的SOA建設和實施專案中,如果遇到複雜的服務組合和服務編排,一般會採用類似BPEL來完成。比如在Oracle SOA建設專案中,採用Oracle BPEL流程設計器來實現服務編排和組合。
BPEL是Business Process Execution Language的縮寫,意為業務過程執行語言,是一種基於XML的,用來描寫業務過程的程式語言,被描寫的業務過程的每個單一步驟則由Web服務來實現。2002年IBM、BEA和微軟一起開發和引入了BPEL作為描寫協調Web服務的語言。這個描寫的本身也由Web服務提供,並可以當作Web服務來使用。
對於BPEL實際功能相當強大,類似協議轉換,適配,資料對映,資料裁剪和豐富,分支判斷邏輯,外部第三方介面服務呼叫等能力全部具備。因此也經常被認為是比較重量級的服務編排工具。
對於BPEL設計的結果是XML格式檔案,有嚴格的方法步驟說明,對於介面服務本身也需要有類似WSDL和XSD等嚴格的介面契約說明檔案。因此在當前微服務編排中很少再用類似BPEL這種服務編排工具。
BPEL的服務編排基本是面向設計開發人員的,而在這裡需要找尋一種方法可以面向業務建模和系統分析人員使用的服務簡單組裝和編排的方法。對於服務的組裝,和流程建模和設計的方法基本類似,服務組裝的最後成果是一個組合服務或流程服務,在服務組裝的過程中仍然會大量參考流程視覺化建模和設計的方法,只是考慮如何儘量簡化。
相對於傳統的BPEL服務編排來講,實際上微服務編排需要簡化如下內容。
僅僅編排服務,不做服務適配,協議轉換等。僅做資料對映,不做複雜的業務規則邏輯處理。僅做簡單資料裁剪或豐富,不做複雜邏輯分支判斷以上3點是在實現服務組合和服務編排的時候需要考慮的點。否則整個服務編排會越做越複雜,服務編排本身不是萬能的,對於複雜的規則實現,服務組合等寫程式碼仍然是最佳方式。
編排後服務可監控對於透過服務設計器編排完成的服務,本身即是一個新的API介面服務。服務編排設計和流程設計實際上有很多地方類似。即既需要提供服務設計功能,又需要提供服務執行監控功能。
對於組合服務執行,每次請求方對API組合服務的呼叫都應該產生一個介面服務例項,進入到介面服務例項後可以詳細的監控到當前介面服務的執行狀態,具體每個編排節點的輸入輸出資訊,執行日誌和異常資訊等。
如果要實現整個服務編排,可以看到不僅僅是一個簡單的服務設計器問題,而是需要提供要給完整的類似BPEL一樣的服務編排管理系統,既包含了設計態,也包括了服務執行容器和狀態監控。
透過服務編排構建領域服務對於後端是一個個已經拆分的微服務模組中心,那麼如果出現需要整合多個微服務API介面服務的領域服務能力在哪裡做?傳統的做法一般兩種,一種是直接在前端開發中完成,一種是單獨新增一個領域服務模組來實現跨微服務中心的領域服務API能力介面。
如果在前端來實現服務組合存在兩個問題,其一是前端開發往往並不會太關心詳細業務規則和邏輯,讓前端來組合往往導致關鍵業務實現邏輯出現差錯;其次就是在前端組合後這部分內容將很難複用,比如同時存在BS端和APP端的時候,這部分內容往往需要同時實現兩遍。
因此對於服務編排內容更適合在後端開發來做,但是傳統的單體應用以及劃分為了多個獨立的微服務中心,開發人員往往也僅僅是對自己負責的微服務模組業務熟悉。因此即使要後端來做,也需要對整體業務和應用架構熟悉的人員才能夠完成。
在前面談低程式碼開發平臺的時候也談到,最好是透過一個統一的服務層來實現前端開發和後端能力提供之間的解耦,即前端表單設計繫結的是API介面服務能力,而不是和後臺物件和資料庫直接發生關係。這樣對於比較複雜的業務規則實現,我們就可以編碼實現API介面服務,再統一接入。
在整個APP應用開發過程中,透過前後端分離後,後端能力和API提供僅需要做到半自動化即可,而前端表單設計由於是透過呼叫API介面來實現,再增加前端一些JS指令碼進行的簡單規則處理完全可以實現理想的低程式碼開發效果。