最終一致性解決方案
1. 兩階段提交
2.異步確保(沒有事務消息)
3.異步確保(事務消息)
4. 補償交易(Compensating? Transaction)
5.消息重試
6.冪等(接口支持重入)
A給B轉100元。
1. 兩階段提交
有協(xié)調(diào)者,協(xié)調(diào)操作流程。Pre commit鎖資源,commit或rollback時提交或釋放資源。
調(diào)用A的commit接口超時了,繼續(xù)重試。要求下游接口冪等。下游故障,短時重試不能解決,定時處理中間狀態(tài):扔到重試MQ。重試策略,失敗返回

2.異步確保(沒有事務消息)
不只為一致性,考慮響應時間,下游穩(wěn)定性等
關鍵要有消息表。一般有隊列(不丟消息,但不支持事務消息),基本思路:
生產(chǎn)方:消息表記錄消息發(fā)送狀態(tài),和數(shù)據(jù)一個事務提交(存儲耦合)。只是增加一個字段跟業(yè)務強耦合,處理不同交易數(shù)據(jù)可通用處理。
消費方:需處理消息成功,給生產(chǎn)方confirm。失敗放MQ。支持重試省事兒,不支持放回隊尾或建隊列處理。如成功才繼續(xù),block(不會這么做)。Kafka lowlevel接口是支持自己設置offset的,可實現(xiàn)block。
生產(chǎn)方定時掃描本地消息表,沒處理完的消息由發(fā)送一遍。自動對賬補賬,這一步可省略。丟消息或者下游處理失敗場景少??礃I(yè)務上能不能容忍不一致到對賬補賬周期。
ps:不要MQ。腳本處理低頻場景,離線掃表讓人不爽。業(yè)務量初期也可以
一致性要求不高兜底方案(對賬補賬),不需要confirm,扔給消息萬事大吉

3.異步確保(事務消息)
理想:消息扔到MQ,肯定被消費成功。不用擔心失敗,丟失。
現(xiàn)實:處理失敗,繼續(xù)消費,直到成功為止
大部分MQ都不支持事務消息比如kafka。RocketMQ號稱支持,事務消息關鍵封裝消息狀態(tài)和重發(fā)等。沒成熟事務消息MQ。網(wǎng)傳RMQ提供2PC提交接口。
1.生產(chǎn)方發(fā)送prepared消息給RMQ。失敗返回。
2.執(zhí)行本地事務,成功發(fā)Confirm消息給RMQ。失敗,調(diào)用RMQ cancel接口。
3.步超時如何處理呢?第四步驟
4.生產(chǎn)方實現(xiàn)check接口,告知RMQ自己本地事務是否執(zhí)行成功(第4步)。定時輪訓pre消息,調(diào)用check接口,決定是否可提交。
5.可能失敗。這時候需要RMQ支持消息重試。處理失敗的消息果斷時間再進行重試,直到成功為止(超過重試次數(shù)后會進死信隊列,可能得人肉處理了,因為沒用過所以細節(jié)不是很了解)。
支持消息重試

P.S. 阿里內(nèi)部因歷史原因,用notify比RMQ要多,原理類似。
4. 補償交易(Compensating? Transaction)
和操作本身一個事務里完成。跟2PC比,核心價值少鎖代價。
如A:-100? B:+100。如B:+100失敗,補償A:+100。看起來跟注冊個單庫事務一樣簡單。做到業(yè)務無感知。

5.消息重試
事務消息解決生產(chǎn)者和MQ之間一致性,重試確保消費者和MQ之間的一致性
pull,push模式。失敗,放重試隊列。延遲時間固定(2s),隊首消息,時間到達才被消費。
時間為水位,期望執(zhí)行時間大于當前時間的消息高于水位。其他消息對consumer不可見。如消息延遲時間不一樣:
(1)基于隊列方案:按秒建多個隊列。按執(zhí)行時間入不同隊列,一天86400個隊列(一般丑陋)。按時間消費不同隊列。
(2)基于DB:不依賴隊列,支付時消息進去時候,設置下次執(zhí)行時間,對時間做索引
(3)redis的延時隊列,支持重試。zset按處理時間排序。遇到的持久化問題,內(nèi)存數(shù)據(jù)丟失問題,重試次數(shù)控制,消息追溯等
總結:MQ提供消息重試最好
6.冪等(接口支持重入)
沒有MQ,重試也是無處不在的。冪等怎么做?
insert,依賴唯一鍵,異?;貪L事務。
update,那么狀態(tài)機控制和版本控制異常重要。這里要多加小心。
引入log表。該log對操作id(消息id?)插入log失敗整個回滾
不能查log表或者用redis,加鎖。除非在事務里查。唯一鍵沖突回滾掉就好
用唯一鍵擋重入是目前為止個人覺得最有安全感的方式。當然對數(shù)據(jù)庫會有一些額外性能損耗。問題就變成了有多大的并發(fā),其中又有多大是需要重試的?
Fasion IO卡+分庫分表之后,不會到db性能瓶頸(對金融類場景)。
后記
最終一致性問題,萬惡之源是RPC本身會失敗。生涯大部分時間都會跟各種失敗和timeout搏斗了。用MQ實現(xiàn)最終一致性原因:
1. MQ強大,可不丟數(shù)據(jù)。對事務消息更普及。
2. 異步處理能力(響應時間、吞吐量)和穩(wěn)定性(99.99%的服務依賴99.9%的服務)服務之間解耦
https://zhuanlan.zhihu.com/p/25933039