目錄: 1. 編制、編排傻傻分不清楚 2. 「編排」的關鍵在於流程+適配 3. 「編排」中的分佈式事務應知足最終一致性 4. 「編排」須要更友好的運維工具支撐
相對於傳統架構,微服務架構下更須要經過各微服務之間的協做來實現一個完整的業務流程,能夠說服務編排是微服務架構下的必備技能。可是,編排涉及到RPC、分佈式事務等等,編排的質量不能僅僅取決於老師傅的手藝,須要有完善的編排框架來支撐。php
首先做一點說明,咱們認爲流程有長流程和短流程之分,長流程是指包含人工活動的流程,流程的完成時間由於人的因素會在一個較大範圍內波動;短流程指的是不包含人工活動的流程,在流程啓動後會在一個較短的預期時間內完成。web
相對於長流程,短流程會更關注與響應時間和tps等指標,也更關注自動保證事務一致性的能力。因此在技術設計上長流程和短流程會有較大的區別,今天本文主要介紹的是短流程相關的那些事兒。數據庫
1、編制、編排傻傻分不清楚編程
說到編排,不得不提兩個概念:編制和編排。
編制的英文是Orchestration,本意是樂隊指揮,在演出的時候,樂隊由指揮來統一的進行指揮和控制。緩存
編排的英文是Choreography,本意是舞蹈編舞,舞蹈表演一般是舞蹈演員對外部感應做出響應,好比音樂的響應,而且須要與舞伴的行動和表情進行配合。安全
這兩個詞用在微服務下,也有相似的含義:
微服務的編制強調的是經過一個可執行的中心流程來協同內部及外部的服務交互。經過中心流程來控制整體的目標,涉及的操做,服務調用順序。restful
微服務的編排強調的是協做,經過消息的交互序列來控制各個部分資源的交互。參與交互的資源都是對等的,沒有集中的控制。網絡
可能仍是不太好理解,借一個現成的例子:
編制(Orchestration)就好像交通訊號燈,控制着車輛何時能夠通行。而編排(Choreography)就好像是環島,沒有集中的控制,只有一系列的規則來指明車輛在接近十字路口的時候必需要等待,直到有空間進入環島環繞系統,而後尋找適當的時候離開。架構
編制初看起來好像沒有編排自由,靈活。可是編排也有不完美的地方:併發
編排使一個業務流程會嵌入到多個服務中,維護會困難重重。
編排的對等特色,使得兩端的服務強耦合,將表現爲很難適應需求的變化。
在擴展性上和工程化上編制在必定程度上更優於編排,在一個業務域內編制更適用,而編排更適用跨業務域的流程。
後面要分享的內容,其實是編制的模式,因此在小節標題上甚至都加了引號。仍然使用編排是由於:第一,他已經太深刻人心了,幾乎沒有聽到服務編制的說法。第二,我認爲刻意的區分「編制」與「編排」並無多大價值,重要的是保證各參與方對所用的術語有共同的理解。
2、「編排」的關鍵在於流程+適配
前段時間我參加了一個devops的項目,其中有一部分是這樣子的:
在這短短的120行代碼中,有25行註釋,12行空行,83行功能,包括12次參數校驗,18此Rpc(包括14次寫操做),包括6大業務步驟,主要功能是實現添加一個用戶。可是啊可是,這裏面絕大部分是沒有事務控制的,可想而知,當真的出現數據不一致的時候咱們修復的過程是有多頭疼。
咱們不能把代碼質量徹底寄託於老師傅的手藝,編排徹底是有章可循的。結合咱們本身的產品經驗,來講一說要構建一個編排框架要作些什麼事兒,這裏不可能覆蓋全部的細節,所講的都是我的認爲比較重要的。
編排包含3個基本的活動模型(賦值、invoke(調用)、空)和5個基本的控制模型(順序、分支、異常拋出、異常捕獲、並行)。
固然不少編排框架提供了更多方便的活動,好比普元的編排框架提供了本地調用、rest調用、webservice調用等活動,從而在使用上更加的方便。
有了這些基本的模型,咱們就能方便的編排出複雜的業務流程。
做爲一個老師傅,在invoke的時候咱們知道有同步和異步的區別,同步實現起來簡單,可是在多級級聯編排的時候要避免由於某個服務的長響應時間致使雪崩效應,通常能夠經過設置合理的超時事件和服務熔斷策略來避免;一樣在異步調用的時候,應該能自動緩存上下文和避免緩存爆掉,能自動創建異步響應和請求之間的關聯。
一樣提到並行也必須考慮不一樣的聚合方式,部分聚合?所有聚合?
流程編排完成以後也僅僅是走完了第一步,咱們還須要給每一個被編的服務提供正確的參數,是一個適配的過程。
一個編排服務(abcd)由a、b、c、d服務編排而成,每一個服務都會有本身的出參入參。適配的過程就是從上下文中給入參賦值以及將出參的結果寫入到上下文中。
編排服務執行到不一樣階段,組成上下文的模型也是不同的。從最初服務的開始執行的時候,上下文中只有系統級的參數和入參(請求報文)。到執行完一個被編服務後上下問就會增長這個被編服務的出參(響應報文),執行上下文是一個不斷增大的過程。
因此適配不只僅存在與編排服務的入參和被編服務的入參之間,還存在於被編服務和在其以前的服務出參之間。
最直接的莫過於依靠咱們勤勞的雙手,完成點到點的映射賦值。只是吧,「勤勞」完了也是沒有什麼成就感的。
固然,咱們做爲老師傅仍是有一些過人之處的,咱們有一種解放雙手的武器。
這個武器就是元數據,咱們經過使用元數據對全部的出參和入參標記着色,而後就能夠自動完成一樣顏色之間的自動映射。
以前說到執行上下文的組成模型的時候還包括一個框架產生的部分,這一部分數據主要是流水號(id)和安全方面的考量。按照《基於微服務的企業應用架構設計範式》流水號的生成應該遵循GAIR模式。
globalId: 全局流水號,若是請求中的globalId爲空,則編排服務生成;不然保持不變。
answerId: 響應流水號,服務提供者生成;能夠做爲提供者受理的憑證
inRequestId: 前臺流水號,由前臺生成
requestId: 請求流水號,編排服務的協調器生成;生成規則由服務提供者定義
能編排流程,能適配參數,這個編排框架已經具有運行的能力,後面咱們要考慮的就是事務的一致性問題。
3、「編排」中的分佈式事務應知足最終一致性
依據CAP理論,必須在可用性(availability)和一致性(consistency)之間作出選擇。若是選擇提供一致性須要付出在知足一致性以前阻塞其餘併發訪問的代價。這可能持續一個不肯定的時間,尤爲是在系統已經表現出高延遲時或者網絡故障致使失去鏈接時。
依據目前的成功經驗,可用性通常是更好的選擇,可是在服務和數據庫之間維護數據一致性是很是根本的需求,咱們的編排框架應該選擇知足最終一致性。補償模式就是就是一種很好的實現最終一致性的途徑。
咱們經過一個實例來講明補償模式,一家旅行公司提供預訂行程的業務,能夠經過公司的網站提早預訂飛機票、火車票、酒店等。
假設一位客戶規劃的行程是,(1)上海-北京6月19日9點的某某航班,(2)某某酒店住宿3晚,(3)北京-上海6月22日17點火車。在客戶提交行程後,旅行公司的預訂行程業務按順序串行的調用航班預訂服務、酒店預訂服務、火車預訂服務。最後的火車預訂服務成功後整個預訂業務纔算完成。
若是火車票預訂服務沒有調用成功,那麼以前預訂的航班、酒店都得取消。取消以前預訂的酒店、航班即爲補償過程。
在補償模式中,咱們要求參與補償的微服務必須提供補償操做,而且補償操做必須是冪等的。補償框架能夠在異常時自動調用補償操做完成補償。
如今restful做爲一個輕量級的rpc協議已經被普遍採用,能不能很好的支持restful服務的事務一致性也是衡量一個編排框架的是否成熟的一個標準。咱們公司的王博士設計了一套restful擴展規範來支持補償模式的事務一致性。
經過PATCH的HTTP Method來表示compensation操做,而且支持經過服務來查詢編排服務執行的狀態。
再說一個常見的坑:
因爲是經過rpc的調用,由於網絡和調度的關係,可能出現補償請求比原交易先到達的狀況。這會致使補償操做直接會失敗,由於此時原交易還沒有發生;最終原交易到達時會被成功的執行,最終就致使了事務不一致。
填這個坑的辦法就是在編排框架發現補償操做補償的原交易不存在時,補記錄一條原交易的流水,從而保證原交易晚到時會由於記錄流水失敗而不會成功。
關於事務一致性的更多內容能夠參考以前的關於數據一致性的分享:
《微服務架構下的數據一致性保證(一)》
《微服務架構下的數據一致性保證(二)》
《微服務架構下的數據一致性保證(三)》
4、「編排」須要更友好的運維工具支撐
在生產環境中,咱們須要經過查看日誌來排除故障,應該有支持日誌全路徑回放的工具,來幫助咱們快速定位故障。
另外我所講的編排實際是編制,是一種集中式的控制,也就意味着若是被編排的服務有響應緩慢的狀況,可能會影響到其餘服務。這時候咱們須要更快的監控來幫助咱們發現這類服務,從而儘早優化。
5、總結
最後,總結一下,服務編排有兩種:編排和編制。編制是集中式控制,編排強調的是協做。在擴展性上和工程化上編制在必定程度上更優於編排,在一個業務域內編制更適用,而編排更適用跨業務域的流程。
考慮到服務編排的複雜性,咱們不能徹底依靠經驗豐富的老師傅,使用編排框架能大大提供生產力。構造一個編排框架至少要支持3+5模型,應該採用元數據着色來自動適配服務參數的方法,更進一步要考慮事務(分佈式)一致性,補償模式一般是一種很好的保證事務一致性的方法。
關於做者
田向陽
現任普元解決方案中心架構師。曾就任於神州數碼主持研發新一代自主渠道主線、中間業務平臺。金融領域技術高手,操做系統、編程原理愛好者,喜歡問爲何的工程師。