此系列文章共分為三篇,第一篇介紹概念和相關模式,第二篇和第三篇針對第一篇給出的三種模式分別介紹實現方法和需要注意的問題,敬請關注此公眾號。
轉載本文需注明出處:EAII企業(yè)架構創(chuàng)新研究院,違者必究。如需加入微信群參與微服務架構下的數據一致性保證(二)、(三)微課堂直播請直接回復此公眾號:“加群 姓名 公司 職位 微信號”。
大家好,今天我給大家分享的題目是微服務架構下的數據一致性保證。
今天分享第一篇,主要內容包括:
1.傳統(tǒng)使用本地事務和分布式事務保證一致性。
2.傳統(tǒng)分布式事務不是微服務中一致性的最佳選擇。
3.微服務架構中應滿足數據最終一致性原則。
4.微服務架構實現最終一致性的三種模式。
5.對賬是最后的終極防線。
一、傳統(tǒng)使用本地事務和分布式事務保證一致性
傳統(tǒng)單機應用一般都會使用一個關系型數據庫,好處是應用可以使用 ACID transactions。為保證一致性我們只需要:開始一個事務,改變(插入,刪除,更新)很多行,然后提交事務(如果有異常時回滾事務)。更進一步,借助開發(fā)平臺中的數據訪問技術和框架(如Spring),我們需要做的事情更少,只需要關注數據本身的改變。
隨著組織規(guī)模不斷擴大,業(yè)務量不斷增長,單機應用和數據庫已經不足以支持龐大的業(yè)務量和數據量,這個時候需要對應用和數據庫進行拆分,就出現了一個應用需要同時訪問兩個或兩個以上的數據庫情況。開始我們用分布式事務來保證一致性,也就是我們常說的兩階段提交協議(2PC)。
本地事務和分布式事務現在已經非常成熟,相關介紹很豐富,此處不多作討論。
二、傳統(tǒng)分布式事務不是微服務中一致性的最佳選擇
首先,對于微服務架構來說,數據訪問變得更加復雜,這是因為數據都是微服務私有的,唯一可訪問的方式就是通過API。這種打包數據訪問方式使得微服務之間松耦合,并且彼此之間獨立非常容易進行性能擴展。
其次,不同的微服務經常使用不同的數據庫。應用會產生各種不同類型的數據,關系型數據庫并不一定是最佳選擇。
例如,某個產生和查詢字符串的應用采用Elasticsearch的字符搜索引擎;某個產生社交圖片數據的應用可以采用圖數據庫,例如,Neo4j;
基于微服務的應用一般都使用SQL和NoSQL結合的模式。但是這些非關系型數據大多數并不支持2PC。
可見在微服務架構中已經不能選擇分布式事務了。
三、微服務架構中應滿足數據最終一致性原則
依據CAP理論,必須在可用性(availability)和一致性(consistency)之間做出選擇。如果選擇提供一致性需要付出在滿足一致性之前阻塞其他并發(fā)訪問的代價。這可能持續(xù)一個不確定的時間,尤其是在系統(tǒng)已經表現出高延遲時或者網絡故障導致失去連接時。
依據目前的成功經驗,可用性一般是更好的選擇,但是在服務和數據庫之間維護數據一致性是非常根本的需求,微服務架構中選擇滿足最終一致性。
當然選擇了最終一致性,就要保證到最終的這段時間要在用戶可接受的范圍之內。
那么我們怎么實現最終一致性呢?
四、微服務架構實現最終一致性的三種模式
從一致性的本質來看,是要保證在一個業(yè)務邏輯中包含的服務要么都成功,要么都失敗。那我們怎么選擇方向呢?保證成功還是保證失敗呢?
我們說業(yè)務模式決定了我們的選擇。實現最終一致性有三種模式:可靠事件模式、業(yè)務補償模式、TCC模式。
1) 可靠事件模式
可靠事件模式屬于事件驅動架構,當某件重要事情發(fā)生時,例如更新一個業(yè)務實體,微服務會向消息代理發(fā)布一個事件。消息代理會向訂閱事件的微服務推送事件,當訂閱這些事件的微服務接收此事件時,就可以完成自己的業(yè)務,也可能會引發(fā)更多的事件發(fā)布。
1. 如訂單服務創(chuàng)建一個待支付的訂單,發(fā)布一個“創(chuàng)建訂單”的事件。
2.支付服務消費“創(chuàng)建訂單”事件,支付完成后發(fā)布一個“支付完成”事件。
3.訂單服務消費“支付完成”事件,訂單狀態(tài)更新為待出庫。
從而就實現了完成的業(yè)務流程。
這個過程可能導致出現不一致的地方在于:某個微服務在更新了業(yè)務實體后發(fā)布事件卻失??;雖然微服務發(fā)布事件成功,但是消息代理未能正確推送事件到訂閱的微服務;接受事件的微服務重復消費了事件。
可靠事件模式在于保證可靠事件投遞和避免重復消費,可靠事件投遞定義為(a)每個服務原子性的業(yè)務操作和發(fā)布事件(b)消息代理確保事件傳遞至少一次。
避免重復消費要求服務實現冪等性,如支付服務不能因為重復收到事件而多次支付。
2) 補償模式
為了描述方便,這里先定義兩個概念:
業(yè)務異常:業(yè)務邏輯產生錯誤的情況,比如賬戶余額不足、商品庫存不足等。
技術異常:非業(yè)務邏輯產生的異常,如網絡連接異常、網絡超時等。
補償模式使用一個額外的協調服務來協調各個需要保證一致性的微服務,協調服務按順序調用各個微服務,如果某個微服務調用異常(包括業(yè)務異常和技術異常)就取消之前所有已經調用成功的微服務。
補償模式建議僅用于不能避免出現業(yè)務異常的情況,如果有可能應該優(yōu)化業(yè)務模式,以避免要求補償事務。如賬戶余額不足的業(yè)務異常可通過預先凍結金額的方式避免,商品庫存不足可要求商家準備額外的庫存等。
我們通過一個實例來說明補償模式,一家旅行公司提供預訂行程的業(yè)務,可以通過公司的網站提前預訂飛機票、火車票、酒店等。
假設一位客戶規(guī)劃的行程是,(1)上海-北京6月19日9點的某某航班,(2)某某酒店住宿3晚,(3)北京-上海6月22日17點火車。在客戶提交行程后,旅行公司的預訂行程業(yè)務按順序串行的調用航班預訂服務、酒店預訂服務、火車預訂服務。最后的火車預訂服務成功后整個預訂業(yè)務才算完成。
如果火車票預訂服務沒有調用成功,那么之前預訂的航班、酒店都得取消。取消之前預訂的酒店、航班即為補償過程。
需要注意的是酒店的取消預訂、航班的取消預訂同樣不能保證一定成功,所以補償過程往往也同樣需要實現最終一致性,需要保證取消服務至少被調用一次和取消服務必須實現冪等性。
我們應該盡可能通過設計避免采用補償方式,比如上面的例子中,在預訂火車票失敗的時候可以提示客戶更改其他的時間。
3) TCC模式(Try-Confirm-Cancel)
一個完整的TCC業(yè)務由一個主業(yè)務服務和若干個從業(yè)務服務組成,主業(yè)務服務發(fā)起并完成整個業(yè)務活動,TCC模式要求從服務提供三個接口:Try、Confirm、Cancel。
1) Try:完成所有業(yè)務檢查
預留必須業(yè)務資源
2) Confirm:真正執(zhí)行業(yè)務
不作任何業(yè)務檢查
只使用Try階段預留的業(yè)務資源
Confirm操作滿足冪等性
3) Cancel:
釋放Try階段預留的業(yè)務資源
Cancel操作滿足冪等性
整個TCC業(yè)務分成兩個階段完成。
第一階段:主業(yè)務服務分別調用所有從業(yè)務的try操作,并在活動管理器中登記所有從業(yè)務服務。當所有從業(yè)務服務的try操作都調用成功或者某個從業(yè)務服務的try操作失敗,進入第二階段。
第二階段:活動管理器根據第一階段的執(zhí)行結果來執(zhí)行confirm或cancel操作。如果第一階段所有try操作都成功,則活動管理器調用所有從業(yè)務活動的confirm操作。否則調用所有從業(yè)務服務的cancel操作。
需要注意的是第二階段confirm或cancel操作本身也是滿足最終一致性的過程,在調用confirm或cancel的時候也可能因為某種原因(比如網絡)導致調用失敗,所以需要活動管理支持重試的能力,同時這也就要求confirm和cancel操作具有冪等性。
五、對賬是最后的終極防線
如果有些業(yè)務由于瞬時的網絡故障或調用超時等問題,通過上文所講的3種模式一般都能得到很好的解決。但是在當今云計算環(huán)境下,很多服務是依賴于外部系統(tǒng)的可用性情況,在一些重要的業(yè)務場景下還需要周期性的對賬來保證真實的一致性。比如支付系統(tǒng)和銀行之間每天日終是都會有對賬過程。
以上就是今天分享的內容,主要介紹的是微服務架構中需要滿足最終一致性原則以及實現最終一致性的3種模式。關于每種模式的實現方法以及可能遇到的問題會在今后逐步和大家分享。
謝謝大家!
關于作者: