微服務(wù)架構(gòu)下的事務(wù)一致性

本文轉(zhuǎn)載自:https://mp.weixin.qq.com/s?__biz=MzAwNzM1NjQyNg==&mid=2649961998&idx=1&sn=d48ba8343e048951d7c315ef4b233aeb&chksm=8378ff6bb40f767dfa8912612b680fd52c146be510fc50f856a671e3b7e238bf6f232058e37a&mpshare=1&scene=1&srcid=0829T8KCjZqWeCUwfaHxKIzc#rd

如有侵權(quán),請(qǐng)告知,本人將立即刪除

授權(quán)聲明

本文轉(zhuǎn)載自戰(zhàn)略合作伙伴中生代技術(shù)(FreshmanTechnology)

?第7篇架構(gòu)好文:8875字 | 13分鐘閱讀

摘要

傳統(tǒng)應(yīng)用使用本地事務(wù)和分布式事務(wù)保證數(shù)據(jù)一致性藕赞,但是在微服務(wù)架構(gòu)中數(shù)據(jù)都是服務(wù)私有的成肘,需要通過服務(wù)提供的api訪問,分布式事務(wù)不再適用微服務(wù)架構(gòu)斧蜕,傳統(tǒng)分布式事務(wù)不是微服務(wù)中數(shù)據(jù)一致性的最佳選擇双霍。微服務(wù)架構(gòu)中應(yīng)滿足數(shù)據(jù)最終一致性原則。

田向陽批销,普元解決方案中心架構(gòu)師洒闸,曾就職于神州數(shù)碼主特研發(fā)新一代自主渠道總線、中間業(yè)務(wù)平臺(tái)均芽。金融領(lǐng)域技術(shù)高手险耀,操作系統(tǒng)吓歇、編譯原理爰好者,喜歡問什么工程師。

大家好波桩,我是田向陽冰蘑,是現(xiàn)任普元解決方案的中心架構(gòu)師掖桦。今天我給大家分享的題目是微服務(wù)架構(gòu)下的事務(wù)一致性保證冕香。

主要內(nèi)容包括4部分:

傳統(tǒng)分布式事務(wù)不是微服務(wù)中一致性的最佳選擇

微服務(wù)架構(gòu)中應(yīng)滿足數(shù)據(jù)最終一致性原則

微服務(wù)架構(gòu)實(shí)現(xiàn)最終一致性的三種模式

對(duì)賬是最后的終極防線。

我們先來看一下第一部分镣奋,傳統(tǒng)使用本地事務(wù)和分布式事務(wù)保證一致性

傳統(tǒng)單機(jī)應(yīng)用一般都會(huì)使用一個(gè)關(guān)系型數(shù)據(jù)庫币呵,好處是應(yīng)用可以使用 ACID transactions。為保證一致性我們只需要:開始一個(gè)事務(wù)侨颈,改變(插入余赢,刪除,更新)很多行哈垢,然后提交事務(wù)(如果有異常時(shí)回滾事務(wù))妻柒。更進(jìn)一步,借助開發(fā)平臺(tái)中的數(shù)據(jù)訪問技術(shù)和框架(如Spring)温赔,我們需要做的事情更少蛤奢,只需要關(guān)注數(shù)據(jù)本身的改變。隨著組織規(guī)模不斷擴(kuò)大陶贼,業(yè)務(wù)量不斷增長啤贩,單機(jī)應(yīng)用和數(shù)據(jù)庫已經(jīng)不足以支持龐大的業(yè)務(wù)量和數(shù)據(jù)量,這個(gè)時(shí)候需要對(duì)應(yīng)用和數(shù)據(jù)庫進(jìn)行拆分拜秧,就出現(xiàn)了一個(gè)應(yīng)用需要同時(shí)訪問兩個(gè)或兩個(gè)以上的數(shù)據(jù)庫情況痹屹。開始我們用分布式事務(wù)來保證一致性,也就是我們常說的兩階段提交協(xié)議(2PC)枉氮。

本地事務(wù)和分布式事務(wù)現(xiàn)在已經(jīng)非常成熟志衍,相關(guān)介紹很豐富,此處不多作討論聊替。我們下面來討論以下為什么分布式事務(wù)不適用于微服務(wù)架構(gòu)楼肪。

首先,對(duì)于微服務(wù)架構(gòu)來說惹悄,數(shù)據(jù)訪問變得更加復(fù)雜春叫,這是因?yàn)閿?shù)據(jù)都是微服務(wù)私有的,唯一可訪問的方式就是通過API泣港。這種打包數(shù)據(jù)訪問方式使得微服務(wù)之間松耦合暂殖,并且彼此之間獨(dú)立非常容易進(jìn)行性能擴(kuò)展。

其次当纱,不同的微服務(wù)經(jīng)常使用不同的數(shù)據(jù)庫呛每。應(yīng)用會(huì)產(chǎn)生各種不同類型的數(shù)據(jù),關(guān)系型數(shù)據(jù)庫并不一定是最佳選擇坡氯。例如晨横,某個(gè)產(chǎn)生和查詢字符串的應(yīng)用采用Elasticsearch的字符搜索引擎;某個(gè)產(chǎn)生社交圖片數(shù)據(jù)的應(yīng)用可以采用圖數(shù)據(jù)庫箫柳,例如颓遏,Neo4j;基于微服務(wù)的應(yīng)用一般都使用SQL和NoSQL結(jié)合的模式滞时。但是這些非關(guān)系型數(shù)據(jù)大多數(shù)并不支持2PC叁幢。可見在微服務(wù)架構(gòu)中已經(jīng)不能選擇分布式事務(wù)了坪稽。

依據(jù)CAP理論曼玩,必須在可用性(availability)和一致性(consistency)之間做出選擇。如果選擇提供一致性需要付出在滿足一致性之前阻塞其他并發(fā)訪問的代價(jià)窒百。這可能持續(xù)一個(gè)不確定的時(shí)間黍判,尤其是在系統(tǒng)已經(jīng)表現(xiàn)出高延遲時(shí)或者網(wǎng)絡(luò)故障導(dǎo)致失去連接時(shí)。

依據(jù)目前的成功經(jīng)驗(yàn)篙梢,可用性一般是更好的選擇顷帖,但是在服務(wù)和數(shù)據(jù)庫之間維護(hù)數(shù)據(jù)一致性是非常根本的需求,微服務(wù)架構(gòu)中應(yīng)選擇滿足最終一致性。

當(dāng)然選擇了最終一致性贬墩,就要保證到最終的這段時(shí)間要在用戶可接受的范圍之內(nèi)榴嗅。那么我們?cè)趺磳?shí)現(xiàn)最終一致性呢?

從一致性的本質(zhì)來看陶舞,是要保證在一個(gè)業(yè)務(wù)邏輯中包含的服務(wù)要么都成功嗽测,要么都失敗。那我們?cè)趺催x擇方向呢肿孵?保證成功還是保證失敗呢唠粥?我們說業(yè)務(wù)模式?jīng)Q定了我們的選擇。實(shí)現(xiàn)最終一致性有三種模式:可靠事件模式停做、業(yè)務(wù)補(bǔ)償模式晤愧、TCC模式。

可靠事件模式屬于事件驅(qū)動(dòng)架構(gòu)蛉腌,當(dāng)某件重要事情發(fā)生時(shí)养涮,例如更新一個(gè)業(yè)務(wù)實(shí)體,微服務(wù)會(huì)向消息代理發(fā)布一個(gè)事件眉抬。消息代理會(huì)向訂閱事件的微服務(wù)推送事件贯吓,當(dāng)訂閱這些事件的微服務(wù)接收此事件時(shí),就可以完成自己的業(yè)務(wù)蜀变,也可能會(huì)引發(fā)更多的事件發(fā)布悄谐。1. 如訂單服務(wù)創(chuàng)建一個(gè)待支付的訂單,發(fā)布一個(gè)“創(chuàng)建訂單”的事件

支付服務(wù)消費(fèi)“創(chuàng)建訂單”事件库北,支付完成后發(fā)布一個(gè)“支付完成”事件

訂單服務(wù)消費(fèi)“支付完成”事件爬舰,訂單狀態(tài)更新為待出庫。

從而就實(shí)現(xiàn)了完成的業(yè)務(wù)流程寒瓦。但是這并不是一個(gè)完美的流程情屹。

這個(gè)過程可能導(dǎo)致出現(xiàn)不一致的地方在于:某個(gè)微服務(wù)在更新了業(yè)務(wù)實(shí)體后發(fā)布事件卻失敗杂腰;雖然微服務(wù)發(fā)布事件成功垃你,但是消息代理未能正確推送事件到訂閱的微服務(wù);接受事件的微服務(wù)重復(fù)消費(fèi)了事件喂很。

可靠事件模式在于保證可靠事件投遞和避免重復(fù)消費(fèi)惜颇,可靠事件投遞定義為:(a)每個(gè)服務(wù)原子性的業(yè)務(wù)操作和發(fā)布事件

(b)消息代理確保事件傳遞至少一次。避免重復(fù)消費(fèi)要求服務(wù)實(shí)現(xiàn)冪等性少辣,如支付服務(wù)不能因?yàn)橹貜?fù)收到事件而多次支付凌摄。

因?yàn)楝F(xiàn)在流行的消息隊(duì)列都實(shí)現(xiàn)了事件的持久化和at least once的投遞模式,(b)特性(消息代理確保事件投遞至少一次)已經(jīng)滿足漓帅,今天不做展開锨亏。

下面分享的內(nèi)容主要從可靠事件投遞和實(shí)現(xiàn)冪等性兩方面來討論痴怨,我們先來看可靠事件投遞。首先我們來看一個(gè)實(shí)現(xiàn)的代碼片段器予,這是從某生產(chǎn)系統(tǒng)上截取下來的浪藻。

根據(jù)上述代碼及注釋,初看可能出現(xiàn)3種情況:

操作數(shù)據(jù)庫成功劣摇,向消息代理投遞事件也成功

操作數(shù)據(jù)庫失敗,不會(huì)向消息代理中投遞事件了

操作數(shù)據(jù)庫成功弓乙,但是向消息代理中投遞事件時(shí)失敗末融,向外拋出了異常,剛剛執(zhí)行的更新數(shù)據(jù)庫的操作將被回滾從上面分析的幾種情況來看暇韧,貌似沒有問題勾习。但是仔細(xì)分析不難發(fā)現(xiàn)缺陷所在,在上面的處理過程中存在一段隱患時(shí)間窗口懈玻。

微服務(wù)A投遞事件的時(shí)候可能消息代理已經(jīng)處理成功巧婶,但是返回響應(yīng)的時(shí)候網(wǎng)絡(luò)異常,導(dǎo)致append操作拋出異常涂乌。最終結(jié)果是事件被投遞艺栈,數(shù)據(jù)庫確被回滾。

2) 在投遞完成后到數(shù)據(jù)庫commit操作之間如果微服務(wù)A宕機(jī)也將造成數(shù)據(jù)庫操作因?yàn)檫B接異常關(guān)閉而被回滾湾盒。最終結(jié)果還是事件被投遞湿右,數(shù)據(jù)庫卻被回滾。這個(gè)實(shí)現(xiàn)往往運(yùn)行很長時(shí)間都沒有出過問題罚勾,但是一旦出現(xiàn)了將會(huì)讓人感覺莫名很難發(fā)現(xiàn)問題所在毅人。下面給出兩種可靠事件投遞的實(shí)現(xiàn)方式:

一.本地事件表

本地事件表方法將事件和業(yè)務(wù)數(shù)據(jù)保存在同一個(gè)數(shù)據(jù)庫中,使用一個(gè)額外的“事件恢復(fù)”服務(wù)來恢復(fù)事件尖殃,由本地事務(wù)保證更新業(yè)務(wù)和發(fā)布事件的原子性丈莺。考慮到事件恢復(fù)可能會(huì)有一定的延時(shí)送丰,服務(wù)在完成本地事務(wù)后可立即向消息代理發(fā)布一個(gè)事件缔俄。

微服務(wù)在同一個(gè)本地事務(wù)中記錄業(yè)務(wù)數(shù)據(jù)和事件

微服務(wù)實(shí)時(shí)發(fā)布一個(gè)事件立即通知關(guān)聯(lián)的業(yè)務(wù)服務(wù),如果事件發(fā)布成功立即刪除記錄的事件

事件恢復(fù)服務(wù)定時(shí)從事件表中恢復(fù)未發(fā)布成功的事件器躏,重新發(fā)布牵现,重新發(fā)布成功才刪除記錄的事件其中第2條的操作主要是為了增加發(fā)布事件的實(shí)時(shí)性,由第三條保證事件一定被發(fā)布邀桑。本地事件表方式業(yè)務(wù)系統(tǒng)和事件系統(tǒng)耦合比較緊密瞎疼,額外的事件數(shù)據(jù)庫操作也會(huì)給數(shù)據(jù)庫帶來額外的壓力,可能成為瓶頸壁畸。

二贼急、外部事件表

外部事件表方法將事件持久化到外部的事件系統(tǒng)茅茂,事件系統(tǒng)需提供實(shí)時(shí)事件服務(wù)以接受微服務(wù)發(fā)布事件,同時(shí)事件系統(tǒng)還需要提供事件恢復(fù)服務(wù)來確認(rèn)和恢復(fù)事件太抓。

業(yè)務(wù)服務(wù)在事務(wù)提交前空闲,通過實(shí)時(shí)事件服務(wù)向事件系統(tǒng)請(qǐng)求發(fā)送事件,事件系統(tǒng)只記錄事件并不真正發(fā)送

業(yè)務(wù)服務(wù)在提交后走敌,通過實(shí)時(shí)事件服務(wù)向事件系統(tǒng)確認(rèn)發(fā)送碴倾,事件得到確認(rèn)后事件系統(tǒng)才真正發(fā)布事件到消息代理

業(yè)務(wù)服務(wù)在業(yè)務(wù)回滾時(shí),通過實(shí)時(shí)事件向事件系統(tǒng)取消事件

如果業(yè)務(wù)服務(wù)在發(fā)送確認(rèn)或取消之前停止服務(wù)了怎么辦呢掉丽?事件系統(tǒng)的事件恢復(fù)服務(wù)會(huì)定期找到未確認(rèn)發(fā)送的事件向業(yè)務(wù)服務(wù)查詢狀態(tài)跌榔,根據(jù)業(yè)務(wù)服務(wù)返回的狀態(tài)決定事件是要發(fā)布還是取消該方式將業(yè)務(wù)系統(tǒng)和事件系統(tǒng)獨(dú)立解耦,都可以獨(dú)立伸縮捶障。但是這種方式需要一次額外的發(fā)送操作僧须,并且需要發(fā)布者提供額外的查詢接口介紹完了可靠事件投遞再來說一說冪等性的實(shí)現(xiàn),有些事件本身是冪等的项炼,有些事件卻不是担平。

如果事件本身描述的是某個(gè)時(shí)間點(diǎn)的固定值(如賬戶余額為100),而不是描述一條轉(zhuǎn)換指令(如余額增加10)锭部,那么這個(gè)事件是冪等的暂论。我們要意識(shí)到事件可能出現(xiàn)的次數(shù)和順序是不可預(yù)測(cè)的,需要保證冪等事件的順序執(zhí)行拌禾,否則結(jié)果往往不是我們想要的空另。如果我們先后收到兩條事件,(1)賬戶余額更新為100蹋砚,(2)賬戶余額更新為120扼菠。

1.微服務(wù)收到事件(1)

2.微服務(wù)收到事件(2)

3. 微服務(wù)再次收到事件1

顯然結(jié)果是錯(cuò)誤的,所以我們需要保證事件(2)一旦執(zhí)行事件(1)就不能再處理坝咐,否則賬戶余額仍不是我們想要的結(jié)果循榆。

為保證事件的順序一個(gè)簡單的做法是在事件中添加時(shí)間戳,微服務(wù)記錄每類型的事件最后處理的時(shí)間戳墨坚,如果收到的事件的時(shí)間戳早于我們記錄的秧饮,丟棄該事件。如果事件不是在同一個(gè)服務(wù)器上發(fā)出的泽篮,那么服務(wù)器之間的時(shí)間同步是個(gè)難題盗尸,更穩(wěn)妥的做法是使用一個(gè)全局遞增序列號(hào)替換時(shí)間戳。

對(duì)于本身不具有冪等性的操作帽撑,主要思想是為每條事件存儲(chǔ)執(zhí)行結(jié)果泼各,當(dāng)收到一條事件時(shí)我們需要根據(jù)事件的id查詢?cè)撌录欠褚呀?jīng)執(zhí)行過,如果執(zhí)行過直接返回上一次的執(zhí)行結(jié)果亏拉,否則調(diào)度執(zhí)行事件扣蜻。

重復(fù)處理開銷大事件使用事件存儲(chǔ)過濾重復(fù)事件

在這個(gè)思想下我們需要考慮重復(fù)執(zhí)行一條事件和查詢存儲(chǔ)結(jié)果的開銷逆巍。重復(fù)處理開銷小的事件重復(fù)處理如果重復(fù)處理一條事件開銷很小,或者可預(yù)見只有非常少的事件會(huì)被重復(fù)接收莽使,可以選擇重復(fù)處理一次事件锐极,在將事件數(shù)據(jù)持久化時(shí)由數(shù)據(jù)庫拋出唯一性約束異常。

如果重復(fù)處理一條事件的開銷相比額外一次查詢的開銷要高很多芳肌,使用一個(gè)過濾服務(wù)來過濾重復(fù)的事件灵再,過濾服務(wù)使用事件存儲(chǔ)存儲(chǔ)已經(jīng)處理過的事件和結(jié)果。

當(dāng)收到一條事件時(shí)亿笤,過濾服務(wù)首先查詢事件存儲(chǔ)翎迁,確定該條事件是否已經(jīng)被處理過,如果事件已經(jīng)被處理過责嚷,直接返回存儲(chǔ)的結(jié)果鸳兽;否則調(diào)度業(yè)務(wù)服務(wù)執(zhí)行處理掂铐,并將處理完的結(jié)果存儲(chǔ)到事件存儲(chǔ)中罕拂。

一般情況下上面的方法能夠運(yùn)行得很好,如果我們的微服務(wù)是RPC類的服務(wù)我們需要更加小心全陨,可能出現(xiàn)的問題在于爆班,(1)過濾服務(wù)在業(yè)務(wù)處理完成后才將事件結(jié)果存儲(chǔ)到事件存儲(chǔ)中,但是在業(yè)務(wù)處理完成前有可能就已經(jīng)收到重復(fù)事件辱姨,由于是RPC服務(wù)也不能依賴數(shù)據(jù)庫的唯一性約束柿菩;(2)業(yè)務(wù)服務(wù)的處理結(jié)果可能出現(xiàn)位置狀態(tài),一般出現(xiàn)在正常提交請(qǐng)求但是沒有收到響應(yīng)的時(shí)候雨涛。

對(duì)于問題(1)可以按步驟記錄事件處理過程枢舶,比如事件的記錄事件的處理過程為“接收”、“發(fā)送請(qǐng)求”替久、“收到應(yīng)答”凉泄、“處理完成”。好處是過濾服務(wù)能及時(shí)的發(fā)現(xiàn)重復(fù)事件蚯根,進(jìn)一步還能根據(jù)事件狀態(tài)作不同的處理后众。

對(duì)于問題(2)可以通過一次額外的查詢請(qǐng)求來確定事件的實(shí)際處理狀態(tài),要注意額外的查詢會(huì)帶來更長時(shí)間的延時(shí)颅拦,更進(jìn)一步可能某些RPC服務(wù)根本不提供查詢接口蒂誉。此時(shí)只能選擇接收暫時(shí)的不一致,時(shí)候采用對(duì)賬和人工接入的方式來保證一致性距帅。

補(bǔ)償模式

為了描述方便右锨,這里先定義兩個(gè)概念:

業(yè)務(wù)異常:業(yè)務(wù)邏輯產(chǎn)生錯(cuò)誤的情況,比如賬戶余額不足碌秸、商品庫存不足等陡蝇。

技術(shù)異常:非業(yè)務(wù)邏輯產(chǎn)生的異常痊臭,如網(wǎng)絡(luò)連接異常、網(wǎng)絡(luò)超時(shí)等登夫。

補(bǔ)償模式使用一個(gè)額外的協(xié)調(diào)服務(wù)來協(xié)調(diào)各個(gè)需要保證一致性的微服務(wù)广匙,協(xié)調(diào)服務(wù)按順序調(diào)用各個(gè)微服務(wù),如果某個(gè)微服務(wù)調(diào)用異常(包括業(yè)務(wù)異常和技術(shù)異常)就取消之前所有已經(jīng)調(diào)用成功的微服務(wù)恼策。

補(bǔ)償模式建議僅用于不能避免出現(xiàn)業(yè)務(wù)異常的情況鸦致,如果有可能應(yīng)該優(yōu)化業(yè)務(wù)模式,以避免要求補(bǔ)償事務(wù)涣楷。如賬戶余額不足的業(yè)務(wù)異撤滞伲可通過預(yù)先凍結(jié)金額的方式避免,商品庫存不足可要求商家準(zhǔn)備額外的庫存等狮斗。

我們通過一個(gè)實(shí)例來說明補(bǔ)償模式绽乔,一家旅行公司提供預(yù)訂行程的業(yè)務(wù),可以通過公司的網(wǎng)站提前預(yù)訂飛機(jī)票碳褒、火車票折砸、酒店等。

假設(shè)一位客戶規(guī)劃的行程是沙峻,

(1)上海-北京6月19日9點(diǎn)的某某航班睦授,

(2)某某酒店住宿3晚,

(3)北京-上海6月22日17點(diǎn)火車摔寨。在客戶提交行程后去枷,旅行公司的預(yù)訂行程業(yè)務(wù)按順序串行的調(diào)用航班預(yù)訂服務(wù)、酒店預(yù)訂服務(wù)是复、火車預(yù)訂服務(wù)删顶。最后的火車預(yù)訂服務(wù)成功后整個(gè)預(yù)訂業(yè)務(wù)才算完成。

如果火車票預(yù)訂服務(wù)沒有調(diào)用成功淑廊,那么之前預(yù)訂的航班逗余、酒店都得取消。取消之前預(yù)訂的酒店蒋纬、航班即為補(bǔ)償過程猎荠。

為了降低開發(fā)的復(fù)雜性和提高效率,協(xié)調(diào)服務(wù)實(shí)現(xiàn)為一個(gè)通用的補(bǔ)償框架蜀备。補(bǔ)償框架提供服務(wù)編排和自動(dòng)完成補(bǔ)償?shù)哪芰Α?/p>

要實(shí)現(xiàn)補(bǔ)償過程关摇,我們需要做到兩點(diǎn):

首先要確定失敗的步驟和狀態(tài),從而確定需要補(bǔ)償?shù)姆秶?/b>

在上面的例子中我們不光要知道第3個(gè)步驟(預(yù)訂火車)失敗碾阁,還要知道失敗的原因输虱。如果是因?yàn)轭A(yù)訂火車服務(wù)返回?zé)o票,那么補(bǔ)償過程只需要取消前兩個(gè)步驟就可以了脂凶;但是如果失敗的原因是因?yàn)榫W(wǎng)絡(luò)超時(shí)宪睹,那么補(bǔ)償過程除前兩個(gè)步驟之外還需要包括第3個(gè)步驟愁茁。

其次要能提供補(bǔ)償操作使用到的業(yè)務(wù)數(shù)據(jù)。

比如一個(gè)支付微服務(wù)的補(bǔ)償操作要求參數(shù)包括支付時(shí)的業(yè)務(wù)流水id亭病、賬號(hào)和金額鹅很。理論上說實(shí)際完成補(bǔ)償操作可以根據(jù)唯一的業(yè)務(wù)流水id就可以,但是提供更多的要素有益于微服務(wù)的健壯性罪帖,微服務(wù)在收到補(bǔ)償操作的時(shí)候可以做業(yè)務(wù)的檢查促煮,比如檢查賬戶是否相等,金額是否一致等等整袁。

做到上面兩點(diǎn)的辦法是記錄完整的業(yè)務(wù)流水菠齿,可以通過業(yè)務(wù)流水的狀態(tài)來確定需要補(bǔ)償?shù)牟襟E,同時(shí)業(yè)務(wù)流水為補(bǔ)償操作提供需要的業(yè)務(wù)數(shù)據(jù)坐昙。

當(dāng)客戶的一個(gè)預(yù)訂請(qǐng)求達(dá)到時(shí)绳匀,協(xié)調(diào)服務(wù)(補(bǔ)償框架)為請(qǐng)求生成一個(gè)全局唯一的業(yè)務(wù)流水號(hào)。并在調(diào)用各個(gè)工作服務(wù)的同時(shí)記錄完整的狀態(tài)炸客。

記錄調(diào)用bookFlight的業(yè)務(wù)流水疾棵,調(diào)用bookFlight服務(wù),更新業(yè)務(wù)流水狀態(tài)

記錄調(diào)用bookHotel的業(yè)務(wù)流水嚷量,調(diào)用bookHotel服務(wù)陋桂,更新業(yè)務(wù)流水狀態(tài)

記錄調(diào)用bookTrain的業(yè)務(wù)流水逆趣,調(diào)用bookTrain服務(wù)蝶溶,更新業(yè)務(wù)流水狀態(tài)

當(dāng)調(diào)用某個(gè)服務(wù)出現(xiàn)異常時(shí),比如第3步驟(預(yù)訂火車)異常

協(xié)調(diào)服務(wù)(補(bǔ)償框架)同樣會(huì)記錄第3步的狀態(tài)宣渗,同時(shí)會(huì)另外記錄一條事件抖所,說明業(yè)務(wù)出現(xiàn)了異常。然后就是執(zhí)行補(bǔ)償過程了痕囱,可以從業(yè)務(wù)流水的狀態(tài)中知道補(bǔ)償?shù)姆秶镌a(bǔ)償過程中需要的業(yè)務(wù)數(shù)據(jù)從記錄的業(yè)務(wù)流水中獲取。

對(duì)于一個(gè)通用的補(bǔ)償框架來說鞍恢,預(yù)先知道微服務(wù)需要記錄的業(yè)務(wù)要素是不可能的傻粘。那么就需要一種方法來保證業(yè)務(wù)流水的可擴(kuò)展性,這里介紹兩種方法:大表和關(guān)聯(lián)表帮掉。

大表顧明思議就是設(shè)計(jì)時(shí)除必須的字段外弦悉,還需要預(yù)留大量的備用字段,框架可以提供輔助工具來幫助將業(yè)務(wù)數(shù)據(jù)映射到備用字段中蟆炊。

關(guān)聯(lián)表稽莉,分為框架表和業(yè)務(wù)表,技術(shù)表中保存為實(shí)現(xiàn)補(bǔ)償操作所需要的技術(shù)數(shù)據(jù)涩搓,業(yè)務(wù)表保存業(yè)務(wù)數(shù)據(jù)污秆,通過在技術(shù)表中增加業(yè)務(wù)表名和業(yè)務(wù)表主鍵來建立和業(yè)務(wù)數(shù)據(jù)的關(guān)聯(lián)劈猪。

大表對(duì)于框架層實(shí)現(xiàn)起來簡單,但是也有一些難點(diǎn)良拼,比如預(yù)留多少字段合適战得,每個(gè)字段又需要預(yù)留多少長度。另外一個(gè)難點(diǎn)是如果向從數(shù)據(jù)層面來查詢數(shù)據(jù)庸推,很難看出備用字段的業(yè)務(wù)含義贡避,維護(hù)過程不友好。

關(guān)聯(lián)表在業(yè)務(wù)要素上更靈活予弧,能支持不同的業(yè)務(wù)類型記錄不同的業(yè)務(wù)要素刮吧;但是對(duì)于框架實(shí)現(xiàn)上難度更高,另外每次查詢都需要復(fù)雜的關(guān)聯(lián)動(dòng)作掖蛤,性能方面會(huì)受影響杀捻。

有了上面的完整的流水記錄,協(xié)調(diào)服務(wù)就可以根據(jù)工作服務(wù)的狀態(tài)在異常時(shí)完成補(bǔ)償過程蚓庭。但是補(bǔ)償由于網(wǎng)絡(luò)等原因致讥,補(bǔ)償操作并不一定能保證100%成功,這時(shí)候我們還要做更多一點(diǎn)器赞。

通過重試保證補(bǔ)償過程的完整垢袱。從而滿足最終一致性。

補(bǔ)償過程作為一個(gè)服務(wù)調(diào)用過程同樣存在調(diào)用不成功的情況港柜,這個(gè)時(shí)候需要通過重試的機(jī)制來保證補(bǔ)償?shù)某晒β是肫酢.?dāng)然這也就要求補(bǔ)償操作本身具備冪等性。

關(guān)于冪等性的實(shí)現(xiàn)在前面做過討論夏醉。

重試策略

如果只是一味的失敗就立即重試會(huì)給工作服務(wù)造成不必要的壓力爽锥,我們要根據(jù)服務(wù)執(zhí)行失敗的原因來選擇不同的重試策略。

如果失敗的原因不是暫時(shí)性的畔柔,由于業(yè)務(wù)因素導(dǎo)致(如業(yè)務(wù)要素檢查失斅纫摹)的業(yè)務(wù)錯(cuò)誤,這類錯(cuò)誤是不會(huì)重發(fā)就能自動(dòng)恢復(fù)的靶擦,那么應(yīng)該立即終止重試腮考。

如果錯(cuò)誤的原因是一些罕見的異常,比如因?yàn)榫W(wǎng)絡(luò)傳輸過程出現(xiàn)數(shù)據(jù)丟失或者錯(cuò)誤玄捕,應(yīng)該立即再次重試踩蔚,因?yàn)轭愃频腻e(cuò)誤一般很少會(huì)再次發(fā)生。

如果錯(cuò)誤的原因是系統(tǒng)繁忙(比如http協(xié)議返回的500或者另外約定的返回碼)或者超時(shí)桩盲,這個(gè)時(shí)候需要等待一些時(shí)間再重試寂纪。

重試操作一般會(huì)指定重試次數(shù)上線,如果重試次數(shù)達(dá)到了上限就不再進(jìn)行重試了。這個(gè)時(shí)候應(yīng)該通過一種手段通知相關(guān)人員進(jìn)行處理捞蛋。

對(duì)于等待重試的策略如果重試時(shí)仍然錯(cuò)誤孝冒,可逐漸增加等待的時(shí)間,直到達(dá)到一個(gè)上限后拟杉,以上限作為等待時(shí)間庄涡。

如果某個(gè)時(shí)刻聚集了大量需要重試的操作,補(bǔ)償框架需要控制請(qǐng)求的流量搬设,以防止對(duì)工作服務(wù)造成過大的壓力穴店。

另外關(guān)于補(bǔ)償模式還有幾點(diǎn)補(bǔ)充說明:

微服務(wù)實(shí)現(xiàn)補(bǔ)償操作不是簡單的回退到業(yè)務(wù)發(fā)生時(shí)的狀態(tài),因?yàn)榭赡苓€有其他的并發(fā)的請(qǐng)求同時(shí)更改了狀態(tài)拿穴。一般都使用逆操作的方式完成補(bǔ)償泣洞。

補(bǔ)償過程不需要嚴(yán)格按照與業(yè)務(wù)發(fā)生的相反順序執(zhí)行,可以依據(jù)工作服務(wù)的重用程度優(yōu)先執(zhí)行默色,甚至是可以并發(fā)的執(zhí)行球凰。

有些服務(wù)的補(bǔ)償過程是有依賴關(guān)系的,被依賴服務(wù)的補(bǔ)償操作沒有成功就要及時(shí)終止補(bǔ)償過程腿宰。

如果在一個(gè)業(yè)務(wù)中包含的工作服務(wù)不是都提供了補(bǔ)償操作呕诉,那我們編排服務(wù)時(shí)應(yīng)該把提供補(bǔ)償操作的服務(wù)放在前面,這樣當(dāng)后面的工作服務(wù)錯(cuò)誤時(shí)還有機(jī)會(huì)補(bǔ)償吃度。

設(shè)計(jì)工作服務(wù)的補(bǔ)償接口時(shí)應(yīng)該以協(xié)調(diào)服務(wù)請(qǐng)求的業(yè)務(wù)要素作為條件甩挫,不要以工作服務(wù)的應(yīng)答要素作為條件。因?yàn)檫€存在超時(shí)需要補(bǔ)償?shù)那闆r椿每,這時(shí)補(bǔ)償框架就沒法提供補(bǔ)償需要的業(yè)務(wù)要素伊者。

補(bǔ)償模式就介紹到這里,下面介紹第三種模式:TCC模式(Try-Confirm-Cancel)

一個(gè)完整的TCC業(yè)務(wù)由一個(gè)主業(yè)務(wù)服務(wù)和若干個(gè)從業(yè)務(wù)服務(wù)組成拖刃,主業(yè)務(wù)服務(wù)發(fā)起并完成整個(gè)業(yè)務(wù)活動(dòng)删壮,TCC模式要求從服務(wù)提供三個(gè)接口:Try贪绘、Confirm兑牡、Cancel。

1) Try:完成所有業(yè)務(wù)檢查 預(yù)留必須業(yè)務(wù)資源2) Confirm:真正執(zhí)行業(yè)務(wù) 不作任何業(yè)務(wù)檢查 只使用Try階段預(yù)留的業(yè)務(wù)資源 Confirm操作滿足冪等性3) Cancel: 釋放Try階段預(yù)留的業(yè)務(wù)資源 Cancel操作滿足冪等性整個(gè)TCC業(yè)務(wù)分成兩個(gè)階段完成税灌。

第一階段:主業(yè)務(wù)服務(wù)分別調(diào)用所有從業(yè)務(wù)的try操作均函,并在活動(dòng)管理器中登記所有從業(yè)務(wù)服務(wù)。當(dāng)所有從業(yè)務(wù)服務(wù)的try操作都調(diào)用成功或者某個(gè)從業(yè)務(wù)服務(wù)的try操作失敗菱涤,進(jìn)入第二階段苞也。

第二階段:活動(dòng)管理器根據(jù)第一階段的執(zhí)行結(jié)果來執(zhí)行confirm或cancel操作。如果第一階段所有try操作都成功粘秆,則活動(dòng)管理器調(diào)用所有從業(yè)務(wù)活動(dòng)的confirm操作如迟。否則調(diào)用所有從業(yè)務(wù)服務(wù)的cancel操作。

需要注意的是第二階段confirm或cancel操作本身也是滿足最終一致性的過程,在調(diào)用confirm或cancel的時(shí)候也可能因?yàn)槟撤N原因(比如網(wǎng)絡(luò))導(dǎo)致調(diào)用失敗殷勘,所以需要活動(dòng)管理支持重試的能力此再,同時(shí)這也就要求confirm和cancel操作具有冪等性。

在補(bǔ)償模式中一個(gè)比較明顯的缺陷是玲销,沒有隔離性输拇。從第一個(gè)工作服務(wù)步驟開始一直到所有工作服務(wù)完成(或者補(bǔ)償過程完成),不一致是對(duì)其他服務(wù)可見的贤斜。另外最終一致性的保證還充分的依賴了協(xié)調(diào)服務(wù)的健壯性策吠,如果協(xié)調(diào)服務(wù)異常,就沒法達(dá)到一致性瘩绒。

TCC模式在一定程度上彌補(bǔ)了上述的缺陷猴抹,在TCC模式中直到明確的confirm動(dòng)作,所有的業(yè)務(wù)操作都是隔離的(由業(yè)務(wù)層面保證)锁荔。另外工作服務(wù)可以通過指定try操作的超時(shí)時(shí)間洽糟,主動(dòng)的cancel預(yù)留的業(yè)務(wù)資源,從而實(shí)現(xiàn)自治的微服務(wù)堕战。

TCC模式和補(bǔ)償模式一樣需要需要有協(xié)調(diào)服務(wù)和工作服務(wù)坤溃,協(xié)調(diào)服務(wù)也可以作為通用服務(wù)一般實(shí)現(xiàn)為框架。與補(bǔ)償模式不同的是TCC服務(wù)框架不需要記錄詳細(xì)的業(yè)務(wù)流水嘱丢,完成confirm和cancel操作的業(yè)務(wù)要素由業(yè)務(wù)服務(wù)提供薪介。

在第4步確認(rèn)預(yù)訂之前,訂單只是pending狀態(tài)越驻,只有等到明確的confirm之后訂單才生效汁政。

如果3個(gè)服務(wù)中某個(gè)服務(wù)try操作失敗,那么可以向TCC服務(wù)框架提交cancel缀旁,或者什么也不做由工作服務(wù)自己超時(shí)處理记劈。

TCC模式也不能百分百保證一致性,如果業(yè)務(wù)服務(wù)向TCC服務(wù)框架提交confirm后并巍,TCC服務(wù)框架向某個(gè)工作服務(wù)提交confirm失斈磕尽(比如網(wǎng)絡(luò)故障),那么就會(huì)出現(xiàn)不一致懊渡,一般稱為heuristic exception刽射。

需要說明的是為保證業(yè)務(wù)成功率,業(yè)務(wù)服務(wù)向TCC服務(wù)框架提交confirm以及TCC服務(wù)框架向工作服務(wù)提交confirm/cancel時(shí)都要支持重試剃执,這也就要confirm/cancel的實(shí)現(xiàn)必須具有冪等性誓禁。如果業(yè)務(wù)服務(wù)向TCC服務(wù)框架提交confirm/cancel失敗,不會(huì)導(dǎo)致不一致肾档,因?yàn)榉?wù)最后都會(huì)超時(shí)而取消摹恰。

另外heuristic exception是不可杜絕的辫继,但是可以通過設(shè)置合適的超時(shí)時(shí)間,以及重試頻率和監(jiān)控措施使得出現(xiàn)這個(gè)異常的可能性降低到很小俗慈。如果出現(xiàn)了heuristic exception是可以通過人工的手段補(bǔ)救的骇两。

如果有些業(yè)務(wù)由于瞬時(shí)的網(wǎng)絡(luò)故障或調(diào)用超時(shí)等問題,通過上文所講的3種模式一般都能得到很好的解決姜盈。但是在當(dāng)今云計(jì)算環(huán)境下低千,很多服務(wù)是依賴于外部系統(tǒng)的可用性情況,在一些重要的業(yè)務(wù)場(chǎng)景下還需要周期性的對(duì)賬來保證真實(shí)的一致性馏颂。比如支付系統(tǒng)和銀行之間每天日終是都會(huì)有對(duì)賬過程示血。

以上就是今天分享的內(nèi)容,主要介紹的是微服務(wù)架構(gòu)中需要滿足最終一致性原則以及實(shí)現(xiàn)最終一致性的3種模式救拉。

Q&A

Q:如果要保證事物难审,是不是要開發(fā)一套成功的流程外,還有開發(fā)一套失敗保障的流程呢亿絮?

A:也不是一套保障流程告喊,是服務(wù)除正常操作外還得提供其他相應(yīng)的操作

Q:請(qǐng)問一下實(shí)現(xiàn)后兩種模式所需要的內(nèi)存開支是怎樣的,能否介紹一下派昧?

A:補(bǔ)償模式和TCC模式對(duì)內(nèi)存沒有太多的要求黔姜,中間狀態(tài)保持一般會(huì)持久化到db中,要考慮到業(yè)務(wù)操作和補(bǔ)償操作可能會(huì)相差的時(shí)間比較長蒂萎,持久化是更好的選擇秆吵。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市五慈,隨后出現(xiàn)的幾起案子纳寂,更是在濱河造成了極大的恐慌,老刑警劉巖泻拦,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件毙芜,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡争拐,警方通過查閱死者的電腦和手機(jī)腋粥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來陆错,“玉大人灯抛,你說我怎么就攤上這事∫舸桑” “怎么了?”我有些...
    開封第一講書人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵夹抗,是天一觀的道長绳慎。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么杏愤? 我笑而不...
    開封第一講書人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上帝雇,老公的妹妹穿的比我還像新娘绪爸。我一直安慰自己,他們只是感情好厕宗,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開白布画舌。 她就那樣靜靜地躺著,像睡著了一般已慢。 火紅的嫁衣襯著肌膚如雪曲聂。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評(píng)論 1 299
  • 那天佑惠,我揣著相機(jī)與錄音朋腋,去河邊找鬼。 笑死膜楷,一個(gè)胖子當(dāng)著我的面吹牛旭咽,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播赌厅,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼轻专,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了察蹲?” 一聲冷哼從身側(cè)響起请垛,我...
    開封第一講書人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎洽议,沒想到半個(gè)月后宗收,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡亚兄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年混稽,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片审胚。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡匈勋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出膳叨,到底是詐尸還是另有隱情洽洁,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布菲嘴,位于F島的核電站饿自,受9級(jí)特大地震影響汰翠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜昭雌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一复唤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧烛卧,春花似錦佛纫、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至间聊,卻和暖如春攒盈,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背哎榴。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來泰國打工型豁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人尚蝌。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓迎变,卻偏偏與公主長得像,于是被迫代替她去往敵國和親飘言。 傳聞我的和親對(duì)象是個(gè)殘疾皇子衣形,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 本人最近學(xué)習(xí)了一下微服務(wù)下數(shù)據(jù)一致性的特點(diǎn),總結(jié)了下目前的保障微服務(wù)下數(shù)據(jù)一致性的幾種實(shí)現(xiàn)方式如下姿鸿,以備后查谆吴。此篇...
    SawyerZhou閱讀 31,953評(píng)論 11 66
  • 寫在前面 隨著微服務(wù)架構(gòu)的推廣句狼,越來越多的公司采用微服務(wù)架構(gòu)來構(gòu)建自己的業(yè)務(wù)平臺(tái)。就像前邊的文章說的热某,微服務(wù)架構(gòu)為...
    阿斯蒂芬2閱讀 1,757評(píng)論 0 7
  • 概念:微服務(wù)就是一些可獨(dú)立運(yùn)行腻菇、可協(xié)同工作的小的服務(wù)。微服務(wù)是現(xiàn)在特別流行的服務(wù)昔馋,微服務(wù)的字面意思是大家都很好理解...
    程序員技術(shù)圈閱讀 3,346評(píng)論 2 47
  • 直到此時(shí)才明白筹吐,有些幸福明明在身旁,卻沒有發(fā)現(xiàn)秘遏。等到時(shí)過境遷丘薛,發(fā)生變化,才明白當(dāng)初的美好不復(fù)存在時(shí)垄提。只剩下回憶留做...
    唯愛芳芳閱讀 141評(píng)論 0 0
  • 今日體驗(yàn):今天父親節(jié)榔袋,我在家陪爸爸媽媽逛街周拐、買衣服铡俐,和家人一起吃飯凰兑,愿父母健康快樂!
    A鄭淑英閱讀 132評(píng)論 0 0