對微服務(wù)編排引擎和應(yīng)用場景的再思考
在底層共性技術(shù)服務(wù)和中臺業(yè)務(wù)服務(wù)能力具備后,上層應(yīng)用可以根據(jù)可重用的服務(wù)快速的構(gòu)建的,但是不可能所有場景都簡單的簡單調(diào)用一個API接口服務(wù)就能夠?qū)崿F(xiàn)。當(dāng)存在一定業(yè)務(wù)規(guī)則需要處理的時候,往往都涉及到調(diào)用多個API接口服務(wù),中間還涉及到基礎(chǔ)的邏輯處理,判斷分支往往才能夠完成。
如果讓前端應(yīng)用開發(fā)來處理這種事情,又變成了需要大量編寫腳本代碼,而且存在共性領(lǐng)域服務(wù)邏輯對外泄露的問題。
服務(wù)編排實際上就是對基礎(chǔ)的業(yè)務(wù)處理流程,步驟,規(guī)則邏輯進(jìn)行封裝,然后提供一個封裝后的組合服務(wù)或領(lǐng)域服務(wù)API接口能力給前端應(yīng)用開發(fā)。這個和傳統(tǒng)SOA架構(gòu)里面談到的通過BPEL來進(jìn)行SOA服務(wù)編排思路完全一致。
當(dāng)前微服務(wù)編排引擎來源

對于開源的微服務(wù)編排引擎,最早大家比較熟悉的是Netfix Conductor,我在前面也專門寫過文章分析和說明,但是這個開源版本本身更多的是面向開發(fā)人員使用,很難做到前端的可視化靈活配置,而且也沒有可視化設(shè)計能力,只有編排完成后的可視化監(jiān)控。
從當(dāng)前主流的一些微服務(wù)編排引擎來看,主要包括如下幾類發(fā)展演進(jìn)。
其一是從傳統(tǒng)的工作流引擎或BPM引擎積累開始做微服務(wù)編排引擎,比如當(dāng)前開源的Zeebe,其開發(fā)團(tuán)隊即來源于知名的Activiti工作流和BPM引擎。

其二是傳統(tǒng)的ESB服務(wù)總線上層,對于ESB總線本身就有輕量服務(wù)編排功能,因此從ESB總線來發(fā)展微服務(wù)編排引擎。

其三是基于分布式任務(wù)調(diào)度系統(tǒng),自動化事件事物觸發(fā)編排發(fā)展出來的微服務(wù)編排引擎,要明白微服務(wù)編排最終核心仍然是各個活動或任務(wù)的處理。類似當(dāng)前在物聯(lián)網(wǎng)領(lǐng)域應(yīng)用廣泛的Node-Red編排引擎屬于這種方式。
如何理解微服務(wù)編排場景?
當(dāng)我重新思考這個問題的時候,進(jìn)一步將編排場景進(jìn)行分類理解。
首先第一類就是簡單的服務(wù)組合,服務(wù)拆分,數(shù)據(jù)裁剪,數(shù)據(jù)映射等,這些內(nèi)容可以通過服務(wù)編排來解決,比如輸入一個供應(yīng)商編碼,同時調(diào)用兩個API接口服務(wù),一個是查詢供應(yīng)商基本信息,一個是查詢供應(yīng)商的訂單明細(xì)列表信息。在調(diào)用返回后將結(jié)果整合為一個Json輸出給調(diào)用方。
對于這類場景實際就是對應(yīng)到傳統(tǒng)ESB輕量服務(wù)編排能力,并不涉及到復(fù)雜的業(yè)務(wù)規(guī)則,業(yè)務(wù)邏輯處理,也不涉及到類似BPEL自動化業(yè)務(wù)流的處理等。
其次是基于業(yè)務(wù)處理流程的多個服務(wù)編排處理,這個場景和傳統(tǒng)SOA架構(gòu)里面的BPEL很類似,就是要完成一個業(yè)務(wù)功能,你會發(fā)現(xiàn)本身就需要調(diào)用多個接口才能夠完成,而且這些API接口調(diào)用本身有先后關(guān)系,有調(diào)用邏輯和分支判斷,上游API接口服務(wù)的輸出往往會變成下游API服務(wù)的輸入,形成核心的串行邏輯結(jié)構(gòu)。因此你需要通過一個編排功能將多個服務(wù)編排在一起,最終暴露一個服務(wù)。
對于這類場景一個典型就是一個前端功能實現(xiàn),當(dāng)完成相關(guān)書籍錄入后,點擊一個按鈕觸發(fā)事件,傳統(tǒng)代碼開發(fā)方法一定是在按鈕觸發(fā)事件方法中編寫具體的代碼實現(xiàn)邏輯,這個邏輯本身也涉及到調(diào)用多個API接口服務(wù),當(dāng)然也存在分支判斷邏輯等。
而新的低代碼開發(fā)或Serverless無服務(wù)器化下,我們更加希望點擊代碼只需要調(diào)用一個編排完成的組合服務(wù)能力即可。前端開發(fā)人員并不需要知道內(nèi)部多個API服務(wù)編排組合的規(guī)則邏輯。那么這個場景下就需要先通過微服務(wù)編排引擎形成一個組合服務(wù)API,然后再暴露給前端應(yīng)用使用。
我們最近做了什么事?
最近在實現(xiàn)微服務(wù)編排能力的時候,前期也進(jìn)行了大量的選型,最早的計劃是整體從零開始,基于已有的圖形化設(shè)計器的基礎(chǔ)來做服務(wù)編排引擎。
但是分析完成后整體從零開始做仍然難度不小,不僅僅是API服務(wù)本身的組裝,拆分,規(guī)則邏輯處理,更加重要的是需要底層有一個完整的任務(wù)調(diào)度引擎或事件處理引擎。對于消費方系統(tǒng)來說看到的是一個組合服務(wù)API,但是其內(nèi)部本身是多個服務(wù)組裝,組合完成的,內(nèi)部已經(jīng)變成一個消息或事件驅(qū)動的異步處理系統(tǒng)。
因此在這個過程中你需要去處理任務(wù)調(diào)度,處理異常容錯,處理分布式事務(wù)和回退機(jī)制。所有的這些底層邏輯要從零開始實現(xiàn)本身還是有一定難度的。
Node-RED是一種基于流的編程工具,它有一個可視化編輯器,允許將節(jié)點連接在一起創(chuàng)建流。滿足微服務(wù)編排最基礎(chǔ)的可視化服務(wù)編排需求。Node-RED最初是IBM在2013年末開發(fā)的一個開源項目,以滿足他們快速連接硬件和設(shè)備到Web服務(wù)和其他軟件的需求——作為物聯(lián)網(wǎng)的一種粘合劑,它很快發(fā)展成為一種通用的物聯(lián)網(wǎng)編程工具。
因此通過選型后,最終選擇了Node-Red來實現(xiàn)微服務(wù)編排,當(dāng)時我們規(guī)劃的接口服務(wù)串行,并行,數(shù)據(jù)合并整合,規(guī)則處理,異常捕獲,日志記錄等需要都能夠?qū)崿F(xiàn)。
整體來講Node-Red應(yīng)對簡單的服務(wù)組裝,組合沒有任何問題。但是如果存在類似BPEL一樣的自動化業(yè)務(wù)流處理,仍然不合適。畢竟Node-Red這個開源項目誕生的目的仍然是為了應(yīng)對物聯(lián)網(wǎng)領(lǐng)域常見的任務(wù)和事件處理,重點是多個任務(wù)或事件的編排而非類似業(yè)務(wù)系統(tǒng)功能開發(fā)中的流程編排。
微服務(wù)下Http API接口編排關(guān)鍵點
我們這里談的微服務(wù)編排更多的是指對微服務(wù)暴露的Http API接口的可視化編排和組裝。這個是談?wù)撨@個點的前提。
對于微服務(wù)編排引擎底層前面已經(jīng)談到重點是消息中間件,分布式任務(wù)調(diào)度和執(zhí)行邏輯,狀態(tài)機(jī)等。那么在這個底層邏輯上面進(jìn)行微服務(wù)API編排的時候還需要具備或擴(kuò)展哪些關(guān)鍵能力,初步思考如下。
其一是對于Json格式的處理。
也就是服務(wù)編排中會經(jīng)常遇到Json格式的拆分,合并,數(shù)據(jù)映射等操作,一個編排引擎必須在這個方面相當(dāng)靈活。Json格式的字符串本身也是存在規(guī)則,是可以模板化的,只有模板化后才方便進(jìn)行處理。同時一個Http接口調(diào)用本身存在輸入,輸入的內(nèi)容在后續(xù)多個編排節(jié)點都可能使用到,因此還需要支持輸入信息的參數(shù)化處理。
這些參數(shù)對于整個組合服務(wù)運行實例中的全局參數(shù),在后續(xù)任何節(jié)點都可以引用到。
比如當(dāng)獲取訂單信息的時候,我們希望同時返回訂單對應(yīng)的供應(yīng)商的基本信息。也就是先調(diào)用獲取訂單信息,拿到供應(yīng)商編碼后再去調(diào)用獲取供應(yīng)商信息,最好將供應(yīng)商信息結(jié)果拼裝到整個訂單信息中返回。
- //調(diào)用GetOrderInfo獲取Order信息
- //根據(jù)返回的supplierid發(fā)起對GetSuplier接口調(diào)用
- //將返回的信息作為子對象拼裝到完整Json里面
- orderInfo
- {
- orderid
- ordername
- supplierid
- {
- suppliername:
- suppliertype:
- address:
- contactphone:
- }
- }
可以看到,編排的時候同時調(diào)用多個API接口并不難,難的地方是如何完成結(jié)果的映射,快速,靈活的組裝,這個能力反而更加關(guān)鍵。
在傳統(tǒng)的SOA服務(wù)編排里面,經(jīng)常會采用類似Xslt模板來完成數(shù)據(jù)的映射,組裝等操作,這種參數(shù)化模板映射的思路完全可以借鑒。
其二就是業(yè)務(wù)規(guī)則和邏輯處理
在常規(guī)的SOA服務(wù)組裝中,一般會將BPEL和規(guī)則引擎結(jié)合,來實現(xiàn)復(fù)雜業(yè)務(wù)規(guī)則和邏輯的處理。而對于微服務(wù)編排,本身就是一種偏輕量的編排,不適合處理過于復(fù)雜的業(yè)務(wù)規(guī)則和邏輯。
因此服務(wù)可視化編排中,能夠支撐最簡單額分支判斷邏輯,條件組合邏輯就可以了。而對于更加復(fù)雜的邏輯建議是單獨先實現(xiàn)一個規(guī)則處理的原子服務(wù)API接口,再應(yīng)用到微服務(wù)編排中去。
對于低代碼開發(fā)平臺的應(yīng)用,我在前面也提到過這個觀點。
即首先低代碼開發(fā)平臺應(yīng)該是基于服務(wù)分層的思路,將前端開發(fā)和后端服務(wù)能力區(qū)別開,通過服務(wù)層來徹底解耦。其次就是在服務(wù)層提供可視化服務(wù)編排能力,提供編排后的組合服務(wù)給前端應(yīng)用調(diào)用,減少前端應(yīng)用調(diào)用難度。
但是如果出現(xiàn)了復(fù)雜的業(yè)務(wù)規(guī)則處理邏輯,這個就不要在服務(wù)編排里面去處理,還是單獨實現(xiàn)一個規(guī)則處理API接口服務(wù),再暴露出來給上層應(yīng)用或編排設(shè)計器使用。
其三就是分布式事務(wù)處理機(jī)制
由于將多個微服務(wù)API接口服務(wù)編排在一起,一定會產(chǎn)生分布式事務(wù)問題。
當(dāng)前的編排技術(shù)實際本身又為了完全同步等待的方式和異步類似任務(wù)事件和狀態(tài)機(jī)處理機(jī)制。在前面我們談到兩個場景。
如果是簡單的服務(wù)組合,拆分,可以用同步模式。但是如果是類似業(yè)務(wù)流程處理的多個服務(wù)串行編排,建議是采用異步任務(wù)事件處理機(jī)制。底層也需要消息中間件和中間態(tài)數(shù)據(jù)的存儲機(jī)制來進(jìn)行支撐。
實際在微服務(wù)編排里面的分布式事務(wù)處理,最佳的方式仍然是基于冪等規(guī)則下的事務(wù)補(bǔ)償。
我們一個最簡單的例子。在訂單保存的時候需要扣減庫存。
這個時候涉及到SaveOrderAPI接口和FreezeStockAPI兩個接口,對于扣減庫存有一個對應(yīng)的逆操作接口ReleaseStockAPI。
那么你在進(jìn)行微服務(wù)編排的時候?qū)嶋H需要將這三個接口都編排進(jìn)去,而且還需要增加判斷規(guī)則邏輯,即當(dāng)SaveOrderAPI失敗的時候進(jìn)行ReleaseStockAPI,庫存扣減回退操作。
那么是否有一種方式將這個過程簡化。
即涉及到分布式事務(wù)的場景,我們對任何一個API接口服務(wù)都需要同時配置這個服務(wù)的逆操作回退API接口服務(wù)。那么當(dāng)下游服務(wù)操作在出現(xiàn)異常的時候,由整個微服務(wù)調(diào)度機(jī)制通過調(diào)研逆向API接口,自動發(fā)起多上游服務(wù)的回退操作。
如果回退操作仍然失敗,那么發(fā)送異常處理通知或郵件,通知人工介入操作。
第四點是微服務(wù)鏈路監(jiān)控
在談微服務(wù)的時候經(jīng)常會談到微服務(wù)鏈路監(jiān)控,簡單來說就是前端是調(diào)用一個按鈕處理,但是按鈕方法的實現(xiàn)邏輯里面可能會調(diào)用多個微服務(wù)API,因此需要對整個鏈路進(jìn)行監(jiān)控,以方便進(jìn)行性能問題分析,異常問題排查。
在使用微服務(wù)編排后,按鈕原來的處理邏輯已經(jīng)轉(zhuǎn)換到微服務(wù)編排和設(shè)計里面去完成。一個編排后的微服務(wù)在內(nèi)部可能會調(diào)用多個微服務(wù)API接口,形成微服務(wù)API的接口調(diào)用鏈。而這個內(nèi)容仍然需要提供完整的監(jiān)控,日志查看能力。
這個和工作流引擎里面的流程監(jiān)控類似。
即微服務(wù)編排完成的也是一個流程,是自動化的業(yè)務(wù)流,中間調(diào)用多個API接口服務(wù),因此需要對整個自動化業(yè)務(wù)流做到端到端監(jiān)控。通過微服務(wù)流程實例進(jìn)入后,能夠詳細(xì)看到當(dāng)前執(zhí)行到哪個環(huán)節(jié),如果出現(xiàn)異常也能夠快速地排查到具體的錯誤異常日志。