郜啟凱,李 瑩,鄧水光
(浙江大學(xué) 計(jì)算機(jī)科學(xué)與技術(shù)學(xué)院,浙江 杭州 310013)
隨著云計(jì)算、移動(dòng)互聯(lián)網(wǎng)等技術(shù)的迅猛發(fā)展,網(wǎng)絡(luò)空間中發(fā)布的在線服務(wù)數(shù)量正在成倍地增長,開發(fā)人員能夠快速獲取到滿足自身需求的第三方服務(wù)。但第三方服務(wù)的質(zhì)量往往不受控制,而跨組織服務(wù)間的適配[1]也更為復(fù)雜,這使得針對(duì)跨組織間服務(wù)合作場景的高可靠性服務(wù)編排技術(shù)[2]成為研究熱點(diǎn)。
現(xiàn)有的較為流行的服務(wù)編排框架(如Netflix的conductor[注]https://github.com/Netflix/conductor。和Uber的cadence[注]https://github.com/uber/candence。)盡管在異步和分布式場景中表現(xiàn)出優(yōu)秀的性能,但大部分都是基于服務(wù)編制(service orchestration)[3]的單核心框架,這種框架往往缺乏靈活性,不適合在跨組織項(xiàng)目中部署。與此同時(shí),服務(wù)網(wǎng)格[4-5]概念的興起激起了人們對(duì)于服務(wù)代理的興趣,使用額外的統(tǒng)一化代理[6-7]在應(yīng)用層完成類似TCP協(xié)議在網(wǎng)絡(luò)層所作的工作,屏蔽不同服務(wù)間的差異,以此來簡化服務(wù)編排設(shè)計(jì)和業(yè)務(wù)流程實(shí)現(xiàn)的技術(shù)成為了服務(wù)計(jì)算領(lǐng)域的熱點(diǎn)之一。
根據(jù)以上背景,如何快速、低成本地實(shí)現(xiàn)服務(wù)編排,對(duì)一個(gè)跨組織服務(wù)編排項(xiàng)目的上線速度和成本構(gòu)成了重要影響,而傳統(tǒng)的中心控制組件方式的編排框架顯然很難適應(yīng)這一需求。因此,本文研究了一種基于業(yè)務(wù)流程管理和標(biāo)記法(Business Process Managemen Notation, BPMN)[8]標(biāo)準(zhǔn)的服務(wù)編排(service choreography)框架,其核心為一個(gè)服務(wù)代理引擎。框架向服務(wù)提供一個(gè)服務(wù)代理功能,將服務(wù)編排的實(shí)現(xiàn)和業(yè)務(wù)邏輯剝離,使得開發(fā)者能夠?qū)W⒂跇I(yè)務(wù)本身,而將服務(wù)間通信的任務(wù)交給代理完成。
應(yīng)用服務(wù)編排技術(shù),需具備以下兩個(gè)條件:
(1)服務(wù)的數(shù)據(jù)交換格式需要受到統(tǒng)一標(biāo)準(zhǔn)的約束,因此服務(wù)使用者在進(jìn)行編排設(shè)計(jì)時(shí)不用花費(fèi)過多的精力來考慮參數(shù)適配問題。
(2)網(wǎng)絡(luò)中應(yīng)當(dāng)有支持動(dòng)態(tài)“服務(wù)-實(shí)例”轉(zhuǎn)換查詢[9]的控制服務(wù),這一服務(wù)讓使用者能夠以服務(wù)名稱或類型為基本元素來設(shè)計(jì)工作流。
以上兩個(gè)條件的目的是使框架下的工作流易于設(shè)計(jì)、維護(hù)和擴(kuò)展。希望本文框架能夠像TCP/IP系列協(xié)議所做的那樣,以一定的性能損失為代價(jià)來屏蔽異構(gòu)服務(wù)之間的差異,在整個(gè)服務(wù)網(wǎng)絡(luò)中建立可靠的交互途徑,從而提高整個(gè)系統(tǒng)的可用性。
在一個(gè)現(xiàn)代服務(wù)應(yīng)用場景中,服務(wù)被認(rèn)為是數(shù)量眾多但質(zhì)量不可控的。這就意味著,一方面,針對(duì)功能需求的服務(wù)發(fā)現(xiàn)[10]是可行的,另一方面,對(duì)于某個(gè)具體的服務(wù)實(shí)例,本文總是認(rèn)為它是不可靠的。
如果在服務(wù)編排時(shí),文中將活動(dòng)對(duì)應(yīng)到具體的服務(wù)實(shí)例,則工作流在執(zhí)行時(shí)將會(huì)經(jīng)常性地因?yàn)槟硞€(gè)實(shí)例不可用而進(jìn)入阻塞。因此,工作流中的活動(dòng)應(yīng)當(dāng)是面向服務(wù)功能而不是面向服務(wù)實(shí)例的,只有在工作流執(zhí)行到活動(dòng)的時(shí)候,應(yīng)用才進(jìn)行“活動(dòng)-服務(wù)實(shí)例”的轉(zhuǎn)換,來獲取當(dāng)前可用/最優(yōu)的服務(wù)實(shí)例。
本文的服務(wù)代理引擎采用遞歸調(diào)用模式(如圖1),對(duì)于主持者來說,在發(fā)起服務(wù)時(shí)只需要發(fā)送一份交互消息便可執(zhí)行完整個(gè)工作流,這有利于開發(fā)者專注于業(yè)務(wù)邏輯代碼。
(1)服務(wù)編排腳本 服務(wù)編排腳本用來描述一個(gè)遵循BPMN 2.0規(guī)范的子集的工作流,帶有完整的工作流和參數(shù)適配信息。本文設(shè)計(jì)了相應(yīng)的工具來從一份符合要求的工作流 XML描述中自動(dòng)產(chǎn)生對(duì)應(yīng)的腳本。
(2)主持者 一次工作流執(zhí)行任務(wù)的發(fā)起者,提供一份服務(wù)編排腳本,主持者即可發(fā)起工作流任務(wù)。除發(fā)起任務(wù)和接受結(jié)果外,主持者還需要在本地維護(hù)一個(gè)狀態(tài)信息棧用于過程控制,并在任務(wù)異常時(shí)進(jìn)行終止、補(bǔ)償和重定向操作。
(3)參與者 工作流執(zhí)行中被調(diào)用的服務(wù)。
(4)控制服務(wù) 提供“服務(wù)-實(shí)例”轉(zhuǎn)換查詢和路由信息。
當(dāng)服務(wù)來自不同提供者時(shí),服務(wù)的接口往往也有區(qū)別,如果不進(jìn)行封裝,代理引擎將很難輕松地協(xié)調(diào)各個(gè)服務(wù)間的通信和調(diào)用。因此,本文提出一種標(biāo)準(zhǔn)消息模式[11],用以包裝通信數(shù)據(jù)。該模式只允許任務(wù)中存在活動(dòng)的雙端交互,且交互兩端的活動(dòng)只能使用通信消息進(jìn)行交互,或者使用通知消息向主持者提交狀態(tài)信息。
1.2.1 交互消息
交互消息在一次調(diào)用流程中作為執(zhí)行說明,參與者在完成自身任務(wù)后通過轉(zhuǎn)發(fā)交互消息來推進(jìn)工作。在一個(gè)交互消息(如圖2a)中,Message名稱由調(diào)用發(fā)起者在發(fā)起時(shí)產(chǎn)生,依據(jù)一定的策略使得該名稱在整個(gè)網(wǎng)絡(luò)中唯一。
交互消息M定義為一個(gè)六元組:
M=(X,H,JM,P,E,W)。
(1)
式中:X表示腳本xml,H為主持者地址host,JM表示消息被轉(zhuǎn)發(fā)次數(shù)jump,P代表前置活動(dòng)數(shù)據(jù)prior,E為活動(dòng)過期的時(shí)間expire,W表示權(quán)重?cái)?shù)weight。
X的加入使得代理引擎有能力在沒有中心控制器的情況下獨(dú)立正確地執(zhí)行工作流步驟;W的作用為活動(dòng)許可,初始值為工作流中最大路徑數(shù),在每個(gè)實(shí)際分支處會(huì)變?yōu)楫?dāng)前分支的最大路徑數(shù)。如果遇到分支,交互消息的權(quán)重值會(huì)減小,并在聚合時(shí)計(jì)算收到的同名消息的權(quán)重和,只有當(dāng)權(quán)重等于當(dāng)前分支的最大可能路徑數(shù)時(shí),活動(dòng)才會(huì)被許可。
1.2.2 通知消息
通知消息N(如圖2b)被定義為一個(gè)四元組:
N=(T,S,JN,I)。
(2)
式中:T為枚舉子類型type,S表示通知發(fā)送活動(dòng)service,JN為當(dāng)前活動(dòng)的步數(shù)jump,I為攜帶信息info。
T包含Receive,Success和Fail 3種子類型,用于表明當(dāng)前消息的子類型。其中Receive子類型用于確認(rèn)接受消息,Success用于確認(rèn)任務(wù)完成,F(xiàn)ail子類型用于確認(rèn)任務(wù)失敗。當(dāng)T=Receive時(shí),I的內(nèi)容為發(fā)送者所接受到的消息的來源,當(dāng)T=Fail時(shí),攜帶失敗返回信息,當(dāng)T=Success時(shí),I為所發(fā)送M中的P的副本,該副本被用于狀態(tài)保存,使工作流在中斷時(shí)能夠從斷點(diǎn)處恢復(fù)。
注冊(cè)到控制服務(wù)的服務(wù)需要事先使用平臺(tái)提供的代理引擎軟件開發(fā)工具包(Software Development Kit,SDK)封裝自己的接口,該SDK主要用于消息解析,參數(shù)自動(dòng)適配,消息裝配和轉(zhuǎn)發(fā)。代理引擎采用分層模型(如圖3),對(duì)于業(yè)務(wù)邏輯代碼而言,服務(wù)實(shí)例只需要調(diào)用SDK中的對(duì)應(yīng)方法發(fā)送和接受數(shù)據(jù),服務(wù)間交互就像是直接發(fā)送到目標(biāo)的,剩余的工作將交給代理引擎完成。
1.3.1 主持者
當(dāng)啟用一個(gè)工作流時(shí),引擎接受一個(gè)腳本解析并驗(yàn)證合法性(如控制服務(wù)啟用者是否具有所有包含服務(wù)的使用權(quán)限);然后主持者啟動(dòng)狀態(tài)監(jiān)聽程序,構(gòu)造交互消息,依據(jù)腳本注入?yún)?shù),設(shè)定JM=1;最后從控制服務(wù)處查詢下一活動(dòng)的可用實(shí)例并發(fā)送交互消息。
狀態(tài)監(jiān)聽程序的行為由圖4主持者狀態(tài)機(jī)說明:
(1)若設(shè)定的等待時(shí)間到達(dá)則終止監(jiān)聽并報(bào)超時(shí);
(2)若收到Receive通知?jiǎng)t更改等待時(shí)間為發(fā)送者注冊(cè)的服務(wù)最大耗時(shí);
(3)若收到Success通知?jiǎng)t更改等待時(shí)間為設(shè)定的網(wǎng)絡(luò)延遲等待時(shí)間,將P副本更新至狀態(tài)棧中;
(4)若收到Fail通知,報(bào)告Fail異常并終止監(jiān)聽;
(5)若工作流已執(zhí)行到結(jié)束事件,則從狀態(tài)信息棧中讀取所需數(shù)據(jù)并提交。
1.3.2 參與者
在參與者處建立等待隊(duì)列、就緒隊(duì)列和結(jié)果保留隊(duì)列3個(gè)存儲(chǔ)結(jié)構(gòu)。引擎將自動(dòng)拋棄存儲(chǔ)結(jié)構(gòu)中超時(shí)的數(shù)據(jù),結(jié)果保留隊(duì)列的超時(shí)時(shí)間會(huì)被自動(dòng)延長2倍。其中,等待隊(duì)列用于當(dāng)前活動(dòng)存在多個(gè)前置活動(dòng),且只有部分前置活動(dòng)完成時(shí)存儲(chǔ)相關(guān)信息;就緒隊(duì)列用于存儲(chǔ)待執(zhí)行的活動(dòng);結(jié)果保留隊(duì)列則用于存儲(chǔ)活動(dòng)的執(zhí)行結(jié)果,之所以設(shè)立結(jié)果保留站,是為了在通知消息遭遇網(wǎng)絡(luò)問題時(shí)能夠快速響應(yīng)補(bǔ)償操作所發(fā)的消息而避免重復(fù)執(zhí)行同一個(gè)任務(wù)。
參與者的行為如圖5所示。當(dāng)參與者接受到一個(gè)交互消息時(shí),首先檢查該消息是否超時(shí),未超時(shí)則向H發(fā)送Receive通知,否則直接丟棄。然后引擎會(huì)查詢結(jié)果保留隊(duì)列,若存在同名且JM相等的任務(wù),則執(zhí)行快速響應(yīng)策略,立即返回處理結(jié)果通知消息。下一步,引擎將查詢等待隊(duì)列,若存在同名且JM相等的任務(wù),則將P的參數(shù)注入任務(wù),更新E為較小者,計(jì)算新的W,檢查任務(wù)是否已就緒,若已就緒則將其轉(zhuǎn)入就緒隊(duì)列,并結(jié)束;若不存在同名且JM相等的任務(wù),則解析腳本,依據(jù)腳本生成一個(gè)任務(wù)對(duì)象并將P的參數(shù)注入,檢查任務(wù)是否已就緒,若已就緒則將其轉(zhuǎn)入就緒隊(duì)列,若未就緒,則將任務(wù)轉(zhuǎn)入等待隊(duì)列。
引擎會(huì)在本地服務(wù)處于可用狀態(tài)時(shí)主動(dòng)將就緒任務(wù)隊(duì)首提交給本地服務(wù)處理,并將任務(wù)轉(zhuǎn)至結(jié)果保留隊(duì)列。本地服務(wù)完成任務(wù)后向引擎提交輸出,并按以下策略執(zhí)行通知操作:
(1)若處理異常,構(gòu)建Fail通知發(fā)送給主持者;
(2)若處理成功,從腳本解析中獲取后續(xù)活動(dòng)信息,構(gòu)建交互消息并注入?yún)?shù),將JM+1,向控制服務(wù)查詢可用實(shí)例,將交互消息發(fā)送給所有后續(xù)活動(dòng),同時(shí)構(gòu)建Success通知發(fā)送給H。
根據(jù)以上模型,已發(fā)射的工作流中的活動(dòng)將具備以下幾種狀態(tài):等待、阻塞、就緒、正在執(zhí)行、完成、失敗、超時(shí)。由于預(yù)估了執(zhí)行延遲,“正在執(zhí)行”狀態(tài)可以合并至“就緒”狀態(tài)以減少狀態(tài)通信。為便于過程監(jiān)控,活動(dòng)主持人將維護(hù)一個(gè)工作流狀態(tài)信息棧,記錄每一個(gè)活動(dòng)的當(dāng)前狀態(tài)信息。此外,在一個(gè)分布式系統(tǒng)中,網(wǎng)絡(luò)條件也是決定一個(gè)工作能否正確執(zhí)行的決定因素之一,因此本文設(shè)計(jì)了路徑染色方案,用于判斷網(wǎng)絡(luò)狀況并決定補(bǔ)償方案。主持者依據(jù)表1的活動(dòng)狀態(tài)規(guī)則更新狀態(tài)信息棧中活動(dòng)的執(zhí)行狀態(tài),并依據(jù)表2的網(wǎng)絡(luò)狀態(tài)規(guī)則更新工作流路徑狀態(tài)。
表1 活動(dòng)狀態(tài)
在引擎中,文本設(shè)計(jì)了異常處理策略,用來在服務(wù)存在異常時(shí)進(jìn)行處理,避免偶發(fā)的網(wǎng)絡(luò)不穩(wěn)定導(dǎo)致整個(gè)工作流終止。異常處理策略分為消息補(bǔ)償和服務(wù)重定向[12],將由主持者依據(jù)狀態(tài)棧自動(dòng)執(zhí)行。
表2給出了路徑顏色和轉(zhuǎn)移條件的對(duì)應(yīng)關(guān)系。在黃色路徑上,主持者會(huì)讀取狀態(tài)棧中的參數(shù)列表,將自己模擬為前置活動(dòng)重發(fā)交互消息,新的交互消息將會(huì)按照預(yù)設(shè)定值增大超時(shí)時(shí)間戳;若在紅色路徑上,主持人將向管理平臺(tái)重新查詢可用服務(wù)實(shí)例,并重新發(fā)送補(bǔ)償消息。服務(wù)重定向后路徑轉(zhuǎn)為黑色,當(dāng)一次補(bǔ)償操作失敗或者工作流超時(shí)后,整個(gè)工作流將被立即終止。若不是因?yàn)楣ぷ髁鞒瑫r(shí)而終止,主持者需要向所有阻塞和就緒的活動(dòng)發(fā)送包含過期時(shí)間戳的交互消息,以通知所有參與者該工作流已被終止。
圖6給出了一個(gè)包含一個(gè)并行網(wǎng)關(guān)的簡單工作流的狀態(tài)信息棧結(jié)構(gòu),當(dāng)Activity 3所發(fā)的交互消息在超時(shí)前為被Activity 4通知Receive時(shí)(可能時(shí)交互消息丟失,也可能時(shí)Receive通知消息丟失),主持者將在狀態(tài)信息棧中提取信息并偽裝成Activity 3向Activity 4重發(fā)交互消息。當(dāng)Activity 4收到重發(fā)的交互消息時(shí),若活動(dòng)仍未超時(shí),則將面臨兩個(gè)狀況:①結(jié)果保留隊(duì)列存在同名且同jump任務(wù),則立即重發(fā)Success通知并更新保留時(shí)間;②結(jié)果保留棧不存在同名且同jump任務(wù),則執(zhí)行正常流程。
表2 網(wǎng)絡(luò)狀態(tài)
本文利用模擬服務(wù)網(wǎng)絡(luò)來模擬真實(shí)的執(zhí)行情況。表3說明了實(shí)驗(yàn)中的模擬服務(wù)的具體情況,這些服務(wù)會(huì)在區(qū)間范圍內(nèi)延遲隨機(jī)的時(shí)間并輸出預(yù)置結(jié)果。每個(gè)服務(wù)有200 ms的基礎(chǔ)延遲,最終延遲為基礎(chǔ)延遲加上動(dòng)態(tài)延遲范圍內(nèi)的隨機(jī)結(jié)果。其中A~E為原始服務(wù),F(xiàn)、G、H分別作為B、CD、E的替代服務(wù)。服務(wù)將根據(jù)本文中設(shè)置好的階梯概率(如表4),依據(jù)路徑流量選擇概率并隨機(jī)忽略收到的消息來模擬網(wǎng)絡(luò)不穩(wěn)定[13]。
表3 服務(wù)說明
表4 階梯延遲
實(shí)驗(yàn)包含1個(gè)實(shí)驗(yàn)組A和1個(gè)對(duì)照組B,分別在3種不同情況下執(zhí)行100 000次。其中,實(shí)驗(yàn)組A使用文中提出的服務(wù)編排框架,工作流超時(shí)時(shí)間設(shè)置為路徑上服務(wù)的平均延遲的和的2倍,對(duì)照組則使用了Conductor框架,未設(shè)置異常處理功能。3種情況分別為:①排他網(wǎng)關(guān)(圖7a)和1%服務(wù)異常概率;②排他網(wǎng)關(guān)和0.01%服務(wù)異常概率;③并行網(wǎng)關(guān)(圖7b)和0.01%服務(wù)異常概率。
性能評(píng)價(jià)指標(biāo)為工作流平均執(zhí)行時(shí)長和成功率。其中,工作流平均執(zhí)行時(shí)長為全部成功完成的工作流執(zhí)行時(shí)長的均值。
在搭建實(shí)驗(yàn)時(shí),使用Conductor框架時(shí)搭建一個(gè)簡單工作流的耗時(shí)以小時(shí)為單位,而使用本文提出的框架時(shí)僅需要數(shù)分鐘制作BPMN模型即完成了工作。這無疑證明了本文所提框架的易用性。
實(shí)驗(yàn)結(jié)果(如表5)顯示,相對(duì)于沒有補(bǔ)償操作的服務(wù)編排引擎,本文所提出的引擎付出平均完成時(shí)間增加約4.1%~6.5%的代價(jià),使得在不穩(wěn)定情況下的服務(wù)完成率獲得16.508%~20.804%的提升。其中對(duì)照組B的消息補(bǔ)償和服務(wù)重定向次數(shù)表示可執(zhí)行補(bǔ)償或重定向而未執(zhí)行的次數(shù)。
實(shí)驗(yàn)1和實(shí)驗(yàn)2對(duì)比,本文所提出的引擎對(duì)于服務(wù)質(zhì)量差的情況具有較好的抗干擾性;實(shí)驗(yàn)2和實(shí)驗(yàn)3對(duì)比,發(fā)現(xiàn)多執(zhí)行路徑任務(wù)的分支會(huì)顯著影響平均時(shí)間和成功率。
表5 實(shí)驗(yàn)結(jié)果數(shù)據(jù)
實(shí)驗(yàn)表明,本文所提出的服務(wù)編排引擎在簡化服務(wù)編排設(shè)計(jì)的情況下,引入了補(bǔ)償操作的概念,對(duì)工作流在不穩(wěn)定情況下提升執(zhí)行成功率具有顯著的效果。
本文所提到的服務(wù)編排技術(shù)成功實(shí)現(xiàn)了一個(gè)去中心化的服務(wù)編排框架,通過網(wǎng)絡(luò)代理機(jī)制使得分散的服務(wù)能夠以脫離中心控制器的方法獨(dú)立完成服務(wù)間的協(xié)調(diào)工作,補(bǔ)償機(jī)制的加入以可接受的性能損失為代價(jià)增強(qiáng)了整個(gè)服務(wù)網(wǎng)絡(luò)的魯棒性,減小了跨組織合作時(shí)服務(wù)編排的成本增長。服務(wù)實(shí)例的變動(dòng)并不會(huì)影響工作流的執(zhí)行,而編排設(shè)計(jì)也無需考慮目標(biāo)服務(wù)的可用性。
無論是商業(yè)化的服務(wù)提供平臺(tái),還是自有分布式服務(wù)管理平臺(tái),應(yīng)用該技術(shù)將在初期付出一部分代價(jià),但在后續(xù)的更新和維護(hù)場景中,簡化的服務(wù)編排模式能夠明顯縮短服務(wù)更新周期,使得整個(gè)應(yīng)用的擴(kuò)展更為靈活。
本文提出的編排技術(shù)盡管在編排流程簡化和抗干擾性上展現(xiàn)了顯著的效果,但性能方面的因素并未在之前的工作中作為重點(diǎn)進(jìn)行研究,預(yù)計(jì)復(fù)雜工作流在執(zhí)行時(shí)將會(huì)面臨較大的延遲代價(jià)。因此,基于未來服務(wù)將是多且不可靠的基本原則,該項(xiàng)技術(shù)還有以下幾個(gè)提升方向:
(1)增強(qiáng)分支處理決策能力,提高編排引擎在遞歸調(diào)用時(shí)的性能。
(2)精細(xì)化業(yè)務(wù)流程編排[14]以適應(yīng)可伸縮微服部署[15],拓寬框架的應(yīng)用場景。
(3)為控制服務(wù)添加服務(wù)推薦算法[16],動(dòng)態(tài)地向使用者提供質(zhì)量更高的服務(wù)實(shí)例,提高一次執(zhí)行的成功率,縮短平均執(zhí)行時(shí)間。