學(xué)習(xí)完整課程請移步 互聯(lián)網(wǎng) Java 全棧工程師
問題的起源
在電商等業(yè)務(wù)中,系統(tǒng)一般由多個(gè)獨(dú)立的服務(wù)組成硼控,如何解決分布式調(diào)用時(shí)候數(shù)據(jù)的一致性?
具體業(yè)務(wù)場景如下,比如一個(gè)業(yè)務(wù)操作碰镜,如果同時(shí)調(diào)用服務(wù) A、B习瑰、C绪颖,需要滿足要么同時(shí)成功;要么同時(shí)失敗甜奄。A柠横、B、C 可能是多個(gè)不同部門開發(fā)课兄、部署在不同服務(wù)器上的遠(yuǎn)程服務(wù)牍氛。
在分布式系統(tǒng)來說,如果不想犧牲一致性第喳,CAP 理論告訴我們只能放棄可用性糜俗,這顯然不能接受。為了便于討論問題曲饱,先簡單介紹下數(shù)據(jù)一致性的基礎(chǔ)理論悠抹。
強(qiáng)一致
當(dāng)更新操作完成之后,任何多個(gè)后續(xù)進(jìn)程或者線程的訪問都會返回最新的更新過的值扩淀。這種是對用戶最友好的楔敌,就是用戶上一次寫什么,下一次就保證能讀到什么驻谆。根據(jù) CAP 理論卵凑,這種實(shí)現(xiàn)需要犧牲可用性庆聘。
弱一致性
系統(tǒng)并不保證續(xù)進(jìn)程或者線程的訪問都會返回最新的更新過的值。系統(tǒng)在數(shù)據(jù)寫入成功之后勺卢,不承諾立即可以讀到最新寫入的值伙判,也不會具體的承諾多久之后可以讀到。
最終一致性
弱一致性的特定形式黑忱。系統(tǒng)保證在沒有后續(xù)更新的前提下宴抚,系統(tǒng)最終返回上一次更新操作的值。在沒有故障發(fā)生的前提下甫煞,不一致窗口的時(shí)間主要受通信延遲菇曲,系統(tǒng)負(fù)載和復(fù)制副本的個(gè)數(shù)影響。DNS 是一個(gè)典型的最終一致性系統(tǒng)抚吠。
在工程實(shí)踐上常潮,為了保障系統(tǒng)的可用性,互聯(lián)網(wǎng)系統(tǒng)大多將強(qiáng)一致性需求轉(zhuǎn)換成最終一致性的需求楷力,并通過系統(tǒng)執(zhí)行冪等性的保證喊式,保證數(shù)據(jù)的最終一致性。但在電商等場景中萧朝,對于數(shù)據(jù)一致性的解決方法和常見的互聯(lián)網(wǎng)系統(tǒng)(如 MySQL 主從同步)又有一定區(qū)別垃帅,群友的討論分成以下 6 種解決方案。
1. 規(guī)避分布式事務(wù)——業(yè)務(wù)整合
業(yè)務(wù)整合方案主要采用將接口整合到本地執(zhí)行的方法剪勿。拿問題場景來說,則可以將服務(wù) A方庭、B厕吉、C 整合為一個(gè)服務(wù) D 給業(yè)務(wù),這個(gè)服務(wù) D 再通過轉(zhuǎn)換為本地事務(wù)的方式械念,比如服務(wù) D 包含本地服務(wù)和服務(wù) E头朱,而服務(wù) E 是本地服務(wù) A ~ C 的整合。
優(yōu)點(diǎn):解決(規(guī)避)了分布式事務(wù)龄减。
缺點(diǎn):顯而易見项钮,把本來規(guī)劃拆分好的業(yè)務(wù),又耦合到了一起希停,業(yè)務(wù)職責(zé)不清晰烁巫,不利于維護(hù)。
由于這個(gè)方法存在明顯缺點(diǎn)宠能,通常不建議使用亚隙。
2. 經(jīng)典方案 - eBay 模式
此方案的核心是將需要分布式處理的任務(wù)通過消息日志的方式來異步執(zhí)行。消息日志可以存儲到本地文本违崇、數(shù)據(jù)庫或消息隊(duì)列阿弃,再通過業(yè)務(wù)規(guī)則自動或人工發(fā)起重試诊霹。人工重試更多的是應(yīng)用于支付場景,通過對賬系統(tǒng)對事后問題的處理渣淳。
消息日志方案的核心是保證服務(wù)接口的冪等性脾还。
考慮到網(wǎng)絡(luò)通訊失敗、數(shù)據(jù)丟包等原因入愧,如果接口不能保證冪等性鄙漏,數(shù)據(jù)的唯一性將很難保證。
eBay 方式的主要思路如下砂客。
BASE:一種 ACID 的替代方案
此方案是 eBay 的架構(gòu)師 Dan Pritchett 在 2008 年發(fā)表給 ACM 的文章泥张,是一篇解釋 BASE 原則,或者說最終一致性的經(jīng)典文章鞠值。文中討論了 BASE 與 ACID 原則在保證數(shù)據(jù)一致性的基本差異媚创。
如果 ACID 為分區(qū)的數(shù)據(jù)庫提供一致性的選擇,那么如何實(shí)現(xiàn)可用性呢彤恶?
BASE (basically available, soft state, eventually consistent)
BASE 的可用性是通過 支持局部故障 而不是系統(tǒng)全局故障來實(shí)現(xiàn)的钞钙。下面是一個(gè)簡單的例子:如果將用戶分區(qū)在 5 個(gè)數(shù)據(jù)庫服務(wù)器上,BASE 設(shè)計(jì)鼓勵(lì)類似的處理方式声离,一個(gè)用戶數(shù)據(jù)庫的故障只影響這臺特定主機(jī)那 20% 的用戶芒炼。這里不涉及任何魔法,不過它確實(shí)可以帶來更高的可感知的系統(tǒng)可用性术徊。
文章中描述了一個(gè)最常見的場景本刽,如果產(chǎn)生了一筆交易,需要在交易表增加記錄赠涮,同時(shí)還要修改用戶表的金額子寓。這兩個(gè)表屬于不同的遠(yuǎn)程服務(wù),所以就涉及到分布式事務(wù)一致性的問題
文中提出了一個(gè)經(jīng)典的解決方法笋除,將主要修改操作以及更新用戶表的消息放在 一個(gè)本地事務(wù) 來完成斜友。同時(shí)為了避免重復(fù)消費(fèi)用戶表消息帶來的問題,達(dá)到多次重試的冪等性垃它,增加一個(gè)更新記錄表 updates_applied 來記錄已經(jīng)處理過的消息鲜屏。
系統(tǒng)的執(zhí)行偽代碼如下:
Begin transaction
Insert into transaction(id, selller_id, buyer_id, amount);
Queue message "update user('seller', selller_id, amount)";
Queue message "update user('buyer', buyer_id, amount)";
End transaction
For each message in queue
Peek message
Begin transaction
Select count(*) as processed where trans_id = message.trans_id
and balance = message.balance and user_id = message.user_id
if processed == 0
if message.balance == "seller"
Update user set amt_sold = amt_sold + message.amount
where id = message.id;
Else
Update user set amt_bought = amt_bought + message.amount
where id = message.id
End if
Insert int updates_applied
(message.trans_id, message.balance, message.user_id);
End if
End transaction
if transaction successful
Remove message from queue
End if
End for
基于以上方法,在第一階段国拇,通過本地的數(shù)據(jù)庫的事務(wù)保障洛史,增加了 transaction 表及消息隊(duì)列 。
在第二階段酱吝,分別讀出消息隊(duì)列(但不刪除)虹菲,通過判斷更新記錄表 updates_applied 來檢測相關(guān)記錄是否被執(zhí)行,未被執(zhí)行的記錄會修改 user 表掉瞳,然后增加一條操作記錄到 updates_applied毕源,事務(wù)執(zhí)行成功之后再刪除隊(duì)列浪漠。
通過以上方法,達(dá)到了分布式系統(tǒng)的最終一致性霎褐。進(jìn)一步了解 eBay 的方案可以參考文末鏈接址愿。
3. 去哪兒網(wǎng)分布式事務(wù)方案
隨著業(yè)務(wù)規(guī)模不斷地?cái)U(kuò)大,電商網(wǎng)站一般都要面臨拆分之路冻璃。就是將原來一個(gè)單體應(yīng)用拆分成多個(gè)不同職責(zé)的子系統(tǒng)响谓。比如以前可能將面向用戶、客戶和運(yùn)營的功能都放在一個(gè)系統(tǒng)里省艳,現(xiàn)在拆分為訂單中心娘纷、代理商管理、運(yùn)營系統(tǒng)跋炕、報(bào)價(jià)中心赖晶、庫存管理等多個(gè)子系統(tǒng)。
拆分首先要面臨的是什么呢辐烂?
最開始的單體應(yīng)用所有功能都在一起遏插,存儲也在一起。比如運(yùn)營要取消某個(gè)訂單纠修,那直接去更新訂單表狀態(tài)胳嘲,然后更新庫存表就 ok 了。因?yàn)槭菃误w應(yīng)用扣草,庫在一起了牛,這些都可以在一個(gè)事務(wù)里,由關(guān)系數(shù)據(jù)庫來保證一致性辰妙。
但拆分之后就不同了白魂,不同的子系統(tǒng)都有自己的存儲。比如訂單中心就只管理自己的訂單庫上岗,而庫存管理也有自己的庫。那么運(yùn)營系統(tǒng)取消訂單的時(shí)候就是通過接口調(diào)用等方式來調(diào)用訂單中心和庫存管理的服務(wù)了蕴坪,而不是直接去操作庫肴掷。這就涉及一個(gè)『分布式事務(wù)』的問題。
分布式事務(wù)有兩種解決方式
優(yōu)先使用異步消息
上文已經(jīng)說過背传,使用異步消息 Consumer 端需要實(shí)現(xiàn)冪等呆瞻。
冪等有兩種方式,一種方式是業(yè)務(wù)邏輯保證冪等径玖。比如接到支付成功的消息訂單狀態(tài)變成支付完成痴脾,如果當(dāng)前狀態(tài)是支付完成,則再收到一個(gè)支付成功的消息則說明消息重復(fù)了梳星,直接作為消息成功處理赞赖。
另外一種方式如果業(yè)務(wù)邏輯無法保證冪等滚朵,則要增加一個(gè)去重表或者類似的實(shí)現(xiàn)。對于 producer 端在業(yè)務(wù)數(shù)據(jù)庫的同實(shí)例上放一個(gè)消息庫前域,發(fā)消息和業(yè)務(wù)操作在同一個(gè)本地事務(wù)里辕近。發(fā)消息的時(shí)候消息并不立即發(fā)出,而是向消息庫插入一條消息記錄匿垄,然后在事務(wù)提交的時(shí)候再異步將消息發(fā)出移宅,發(fā)送消息如果成功則將消息庫里的消息刪除,如果遇到消息隊(duì)列服務(wù)異炒涣疲或網(wǎng)絡(luò)問題漏峰,消息沒有成功發(fā)出那么消息就留在這里了,會有另外一個(gè)服務(wù)不斷地將這些消息掃出重新發(fā)送届榄。
有的業(yè)務(wù)不適合異步消息的方式浅乔,事務(wù)的各個(gè)參與方都需要同步的得到結(jié)果
這種情況的實(shí)現(xiàn)方式其實(shí)和上面類似,每個(gè)參與方的本地業(yè)務(wù)庫的同實(shí)例上面放一個(gè)事務(wù)記錄庫痒蓬。
比如 A 同步調(diào)用 B童擎,C。A 本地事務(wù)成功的時(shí)候更新本地事務(wù)記錄狀態(tài)攻晒,B 和 C 同樣顾复。如果有一次 A 調(diào)用 B 失敗了,這個(gè)失敗可能是 B 真的失敗了鲁捏,也可能是調(diào)用超時(shí)芯砸,實(shí)際 B 成功。則由一個(gè)中心服務(wù)對比三方的事務(wù)記錄表给梅,做一個(gè)最終決定假丧。假設(shè)現(xiàn)在三方的事務(wù)記錄是 A 成功,B 失敗动羽,C 成功包帚。那么最終決定有兩種方式,根據(jù)具體場景:
- 重試 B运吓,直到 B 成功渴邦,事務(wù)記錄表里記錄了各項(xiàng)調(diào)用參數(shù)等信息;
- 執(zhí)行 A 和 B 的補(bǔ)償操作(一種可行的補(bǔ)償方式是回滾)拘哨。
對 b 場景做一個(gè)特殊說明:比如 B 是扣庫存服務(wù)谋梭,在第一次調(diào)用的時(shí)候因?yàn)槟撤N原因失敗了,但是重試的時(shí)候庫存已經(jīng)變?yōu)?0倦青,無法重試成功瓮床,這個(gè)時(shí)候只有回滾 A 和 C 了。
那么可能有人覺得在業(yè)務(wù)庫的同實(shí)例里放消息庫或事務(wù)記錄庫,會對業(yè)務(wù)侵入隘庄,業(yè)務(wù)還要關(guān)心這個(gè)庫踢步,是否一個(gè)合理的設(shè)計(jì)?
實(shí)際上可以依靠運(yùn)維的手段來簡化開發(fā)的侵入峭沦,我們的方法是讓 DBA 在公司所有 MySQL 實(shí)例上預(yù)初始化這個(gè)庫贾虽,通過框架層(消息的客戶端或事務(wù) RPC 框架)透明的在背后操作這個(gè)庫,業(yè)務(wù)開發(fā)人員只需要關(guān)心自己的業(yè)務(wù)邏輯吼鱼,不需要直接訪問這個(gè)庫蓬豁。
總結(jié)起來,其實(shí)兩種方式的根本原理是類似的菇肃,也就是將分布式事務(wù)轉(zhuǎn)換為多個(gè)本地事務(wù)地粪,然后依靠重試等方式達(dá)到最終一致性。
4. 蘑菇街交易創(chuàng)建過程中的分布式一致性方案
交易創(chuàng)建的一般性流程
我們把交易創(chuàng)建流程抽象出一系列可擴(kuò)展的功能點(diǎn)琐谤,每個(gè)功能點(diǎn)都可以有多個(gè)實(shí)現(xiàn)(具體的實(shí)現(xiàn)之間有組合/互斥關(guān)系)蟆技。把各個(gè)功能點(diǎn)按照一定流程串起來,就完成了交易創(chuàng)建的過程斗忌。
面臨的問題
每個(gè)功能點(diǎn)的實(shí)現(xiàn)都可能會依賴外部服務(wù)质礼。那么如何保證各個(gè)服務(wù)之間的數(shù)據(jù)是一致的呢?比如鎖定優(yōu)惠券服務(wù)調(diào)用超時(shí)了织阳,不能確定到底有沒有鎖券成功眶蕉,該如何處理?再比如鎖券成功了唧躲,但是扣減庫存失敗了造挽,該如何處理?
方案選型
服務(wù)依賴過多弄痹,會帶來管理復(fù)雜性增加和穩(wěn)定性風(fēng)險(xiǎn)增大的問題饭入。試想如果我們強(qiáng)依賴 10 個(gè)服務(wù),9 個(gè)都執(zhí)行成功了肛真,最后一個(gè)執(zhí)行失敗了谐丢,那么是不是前面 9 個(gè)都要回滾掉?這個(gè)成本還是非常高的蚓让。
所以在拆分大的流程為多個(gè)小的本地事務(wù)的前提下乾忱,對于非實(shí)時(shí)、非強(qiáng)一致性的關(guān)聯(lián)業(yè)務(wù)寫入凭疮,在本地事務(wù)執(zhí)行成功后,我們選擇發(fā)消息通知串述、關(guān)聯(lián)事務(wù)異步化執(zhí)行的方案执解。
消息通知往往不能保證 100% 成功;且消息通知后,接收方業(yè)務(wù)是否能執(zhí)行成功還是未知數(shù)衰腌。前者問題可以通過重試解決新蟆;后者可以選用事務(wù)消息來保證。
但是事務(wù)消息框架本身會給業(yè)務(wù)代碼帶來侵入性和復(fù)雜性右蕊,所以我們選擇基于 DB 事件變化通知到 MQ 的方式做系統(tǒng)間解耦琼稻,通過訂閱方消費(fèi) MQ 消息時(shí)的 ACK 機(jī)制,保證消息一定消費(fèi)成功饶囚,達(dá)到最終一致性帕翻。由于消息可能會被重發(fā),消息訂閱方業(yè)務(wù)邏輯處理要做好冪等保證萝风。
所以目前只剩下需要實(shí)時(shí)同步做嘀掸、有強(qiáng)一致性要求的業(yè)務(wù)場景了。在交易創(chuàng)建過程中规惰,鎖券和扣減庫存是這樣的兩個(gè)典型場景睬塌。
要保證多個(gè)系統(tǒng)間數(shù)據(jù)一致,乍一看歇万,必須要引入分布式事務(wù)框架才能解決揩晴。但引入非常重的類似二階段提交分布式事務(wù)框架會帶來復(fù)雜性的急劇上升;在電商領(lǐng)域贪磺,絕對的強(qiáng)一致是過于理想化的硫兰,我們可以選擇準(zhǔn)實(shí)時(shí)的最終一致性。
我們在交易創(chuàng)建流程中缘挽,首先創(chuàng)建一個(gè)不可見訂單瞄崇,然后在同步調(diào)用鎖券和扣減庫存時(shí),針對調(diào)用異常(失敗或者超時(shí))壕曼,發(fā)出廢單消息到MQ苏研。如果消息發(fā)送失敗,本地會做時(shí)間階梯式的異步重試腮郊;優(yōu)惠券系統(tǒng)和庫存系統(tǒng)收到消息后摹蘑,會進(jìn)行判斷是否需要做業(yè)務(wù)回滾,這樣就準(zhǔn)實(shí)時(shí)地保證了多個(gè)本地事務(wù)的最終一致性轧飞。
5. 支付寶及螞蟻金融云的分布式服務(wù) DTS 方案
業(yè)界常用的還有支付寶的一種 xts 方案衅鹿,由支付寶在 2PC 的基礎(chǔ)上改進(jìn)而來。主要思路如下过咬,大部分信息引用自官方網(wǎng)站大渤。
分布式事務(wù)服務(wù)簡介
分布式事務(wù)服務(wù) (Distributed Transaction Service, DTS) 是一個(gè)分布式事務(wù)框架,用來保障在大規(guī)模分布式環(huán)境下事務(wù)的最終一致性掸绞。DTS 從架構(gòu)上分為 xts-client 和 xts-server 兩部分泵三,前者是一個(gè)嵌入客戶端應(yīng)用的 JAR 包,主要負(fù)責(zé)事務(wù)數(shù)據(jù)的寫入和處理;后者是一個(gè)獨(dú)立的系統(tǒng)烫幕,主要負(fù)責(zé)異常事務(wù)的恢復(fù)俺抽。
核心特性
傳統(tǒng)關(guān)系型數(shù)據(jù)庫的事務(wù)模型必須遵守 ACID 原則。在單數(shù)據(jù)庫模式下较曼,ACID 模型能有效保障數(shù)據(jù)的完整性磷斧,但是在大規(guī)模分布式環(huán)境下,一個(gè)業(yè)務(wù)往往會跨越多個(gè)數(shù)據(jù)庫捷犹,如何保證這多個(gè)數(shù)據(jù)庫之間的數(shù)據(jù)一致性弛饭,需要其他行之有效的策略。在 JavaEE 規(guī)范中使用 2PC (2 Phase Commit, 兩階段提交) 來處理跨 DB 環(huán)境下的事務(wù)問題伏恐,但是 2PC 是反可伸縮模式孩哑,也就是說,在事務(wù)處理過程中翠桦,參與者需要一直持有資源直到整個(gè)分布式事務(wù)結(jié)束横蜒。這樣,當(dāng)業(yè)務(wù)規(guī)模達(dá)到千萬級以上時(shí)销凑,2PC 的局限性就越來越明顯丛晌,系統(tǒng)可伸縮性會變得很差《酚祝基于此澎蛛,我們采用 BASE 的思想實(shí)現(xiàn)了一套類似 2PC 的分布式事務(wù)方案,這就是 DTS蜕窿。DTS在充分保障分布式環(huán)境下高可用性谋逻、高可靠性的同時(shí)兼顧數(shù)據(jù)一致性的要求,其最大的特點(diǎn)是保證數(shù)據(jù)最終一致 (Eventually consistent)桐经。
簡單的說毁兆,DTS 框架有如下特性:
最終一致:事務(wù)處理過程中,會有短暫不一致的情況阴挣,但通過恢復(fù)系統(tǒng)气堕,可以讓事務(wù)的數(shù)據(jù)達(dá)到最終一致的目標(biāo)。
協(xié)議簡單:DTS 定義了類似 2PC 的標(biāo)準(zhǔn)兩階段接口畔咧,業(yè)務(wù)系統(tǒng)只需要實(shí)現(xiàn)對應(yīng)的接口就可以使用 DTS 的事務(wù)功能茎芭。
與 RPC 服務(wù)協(xié)議無關(guān):在 SOA 架構(gòu)下,一個(gè)或多個(gè) DB 操作往往被包裝成一個(gè)一個(gè)的 Service誓沸,Service 與 Service 之間通過 RPC 協(xié)議通信梅桩。DTS 框架構(gòu)建在 SOA 架構(gòu)上,與底層協(xié)議無關(guān)拜隧。
與底層事務(wù)實(shí)現(xiàn)無關(guān): DTS 是一個(gè)抽象的基于 Service 層的概念宿百,與底層事務(wù)實(shí)現(xiàn)無關(guān)煮寡,也就是說在 DTS 的范圍內(nèi),無論是關(guān)系型數(shù)據(jù)庫 MySQL犀呼,Oracle,還是 KV 存儲 MemCache薇组,或者列存數(shù)據(jù)庫 HBase外臂,只要將對其的操作包裝成 DTS 的參與者,就可以接入到 DTS 事務(wù)范圍內(nèi)律胀。
以下是分布式事務(wù)框架的流程圖
實(shí)現(xiàn)
一個(gè)完整的業(yè)務(wù)活動由一個(gè)主業(yè)務(wù)服務(wù)與若干從業(yè)務(wù)服務(wù)組成宋光。
主業(yè)務(wù)服務(wù)負(fù)責(zé)發(fā)起并完成整個(gè)業(yè)務(wù)活動。
從業(yè)務(wù)服務(wù)提供 TCC 型業(yè)務(wù)操作罪佳。
業(yè)務(wù)活動管理器控制業(yè)務(wù)活動的一致性黑低,它登記業(yè)務(wù)活動中的操作赘艳,并在活動提交時(shí)確認(rèn)所有的兩階段事務(wù)的 confirm 操作克握,在業(yè)務(wù)活動取消時(shí)調(diào)用所有兩階段事務(wù)的 cancel 操作蕾管。”
與 2PC 協(xié)議比較
沒有單獨(dú)的 Prepare 階段掰曾,降低協(xié)議成本
系統(tǒng)故障容忍度高停团,恢復(fù)簡單
6. 農(nóng)信網(wǎng)數(shù)據(jù)一致性方案
電商業(yè)務(wù)
公司的支付部門旷坦,通過接入其它第三方支付系統(tǒng)來提供支付服務(wù)給業(yè)務(wù)部門,支付服務(wù)是一個(gè)基于 Dubbo 的 RPC 服務(wù)佑稠。
對于業(yè)務(wù)部門來說秒梅,電商部門的訂單支付讶坯,需要調(diào)用
支付平臺的支付接口來處理訂單;
同時(shí)需要調(diào)用積分中心的接口漱办,按照業(yè)務(wù)規(guī)則婉烟,給用戶增加積分。
從業(yè)務(wù)規(guī)則上需要同時(shí)保證業(yè)務(wù)數(shù)據(jù)的實(shí)時(shí)性和一致性似袁,也就是支付成功必須加積分。
我們采用的方式是同步調(diào)用扬霜,首先處理本地事務(wù)業(yè)務(wù)×瑁考慮到積分業(yè)務(wù)比較單一且業(yè)務(wù)影響低于支付材原,由積分平臺提供增加與回撤接口。
具體的流程是先調(diào)用積分平臺增加用戶積分卷胯,再調(diào)用支付平臺進(jìn)行支付處理威酒,如果處理失敗,catch 方法調(diào)用積分平臺的回撤方法卵慰,將本次處理的積分訂單回撤。
用戶信息變更
公司的用戶信息裳朋,統(tǒng)一由用戶中心維護(hù)吓著,而用戶信息的變更需要同步給各業(yè)務(wù)子系統(tǒng),業(yè)務(wù)子系統(tǒng)再根據(jù)變更內(nèi)容暖眼,處理各自業(yè)務(wù)纺裁。用戶中心作為 MQ 的 producer,添加通知給 MQ欺缘。APP Server 訂閱該消息,同步本地?cái)?shù)據(jù)信息丧鸯,再處理相關(guān)業(yè)務(wù)比如 APP 退出下線等钝吮。
我們采用異步消息通知機(jī)制罩扇,目前主要使用 ActiveMQ穆刻,基于 Virtual Topic 的訂閱方式杠步,保證單個(gè)業(yè)務(wù)集群訂閱的單次消費(fèi)。
總結(jié)
分布式服務(wù)對衍生的配套系統(tǒng)要求比較多,特別是我們基于消息试躏、日志的最終一致性方案设褐,需要考慮消息的積壓、消費(fèi)情況助析、監(jiān)控、報(bào)警等外冀。