微服務(wù)的普及酥筝,使用隊列處理服務(wù)之間通信成為一種潮流,利用隊列消息解耦系統(tǒng)不可避免的會出現(xiàn)數(shù)據(jù)不一致問題掸掏。
產(chǎn)生原因
發(fā)布方問題:運行的系統(tǒng)無法避免的存在單點故障問題宙帝,保存本地事務(wù)和推送隊列無論是哪個先執(zhí)行都無法保證這兩個一定都執(zhí)行完成,先保存本地事務(wù)愿待,服務(wù)發(fā)生故障靴患,消息沒推送,反之同理。
訂閱方問題:消費收到消息后厨幻,執(zhí)行過程中發(fā)生錯誤或宕機,導致沒執(zhí)行成功饭宾。
發(fā)布方解決方案
選出兩種比較簡單的并且不同體系的產(chǎn)品來對比(阿里的RockMq/.net core的CAP框架)格了,先了解下兩種方案的實現(xiàn)過程
.net core 的CAP框架
首先,在你項目運行時候會在你項目指定得數(shù)據(jù)庫生成一張表(cap.published)這張表是用來存儲要發(fā)送消息的日志弹惦。消息有三個狀態(tài)(Scheduled悄但,Succeeded檐嚣,F(xiàn)ailed),啟動程序時候同時還會啟動一個監(jiān)聽程序,隔幾分鐘把表中Failed的消息重新發(fā)送隐解。
我用下訂單來舉個詳細例子
這種設(shè)計方式相對于2PC/TCC來說诫睬,復雜性降低了一個級別,而且支持多種數(shù)據(jù)庫和消息隊列溜嗜,擴展性極強架谎,我覺得缺點應(yīng)該是依賴數(shù)據(jù)庫,發(fā)布消息需要插入日志消息到數(shù)據(jù)庫土全,受限于單機數(shù)據(jù)庫的瓶頸会涎,如果分庫分表還要處理這塊,要么就得在數(shù)據(jù)庫層面做分庫分表概页。CAP文檔
阿里的RocketMq
Rocketmq的功能十分強大练慕,有普通消息,定時消息项鬼,全局/局部順序消息以及事務(wù)消息劲阎,在阿里云可以直接買服務(wù)來使用。RocketMq的事務(wù)采用了TCC模式(Try-Confirm-Cancel)
提交mq半事務(wù)
半事務(wù)消息成功
確認mq事務(wù)
回查事務(wù)
回滾mq事務(wù)
有以下幾種情況
1.下圖是完美成功情況
2.下圖是 消息發(fā)送方?jīng)]有通知到位的情況
細節(jié)可以上阿里云搜Rocketmq查看該產(chǎn)品使用手冊。
阿里的RocketMq 與 CAP 使用架構(gòu)場景分析
CAP適合于發(fā)送隊列消息與業(yè)務(wù)在同一個服務(wù)的場景(消息一致性完全依賴本地事務(wù))稚虎,而中臺架構(gòu)就不適合偎捎,因為中臺架構(gòu)分基礎(chǔ)服務(wù)和業(yè)務(wù)中臺序攘,隊列一般在業(yè)務(wù)中臺跟業(yè)務(wù)掛鉤寻拂,比如有一個訂單基礎(chǔ)服務(wù),但有N個應(yīng)用中臺都是調(diào)用這個訂單基礎(chǔ)服務(wù)存儲訂單數(shù)據(jù)瞄沙,每個中臺都相當于一個應(yīng)用慌核,邏輯可能差異很大,更傾向于在中臺決定推不推送消息和推什么消息垫桂,這種情況下CAP就完全不適合粟按。而RocketMq正好解耦了消息保障功能
訂閱方解決方案
1. 系統(tǒng)突然崩潰導致丟失
系統(tǒng)的瞬態(tài)故障產(chǎn)生的問題,重試便可以解決
2. 程序出現(xiàn)bug導致一直重試一直失敗
這種情況重試是解決不了問題的疼鸟,需要開發(fā)人員做好PlanB庙曙,重試N次不成功便執(zhí)行PlanB。
3. 冪等性問題
發(fā)送端監(jiān)聽重復推送導致的問題姑裂,有兩種方案可以解決男旗。
- 根據(jù)業(yè)務(wù)狀態(tài)判斷欣鳖,比如訂單支付完成后重復推送根據(jù)完成狀態(tài)忽略掉重復那條
- 執(zhí)行業(yè)務(wù)邏輯前查詢該消息是否被執(zhí)行過,因為重復推送消息的消息id必然是一樣的什荣,可以根據(jù)這個消息id進行判定怀酷。
- 針對資源型數(shù)據(jù),訂閱會接收整個資源數(shù)據(jù)的實體桅锄,直接更新進數(shù)據(jù)庫,此時需要有個更新時間翠肘,比對數(shù)據(jù)庫這條數(shù)據(jù)的更新時間辫秧,只更新最新的。
回到選中的兩大框架的消費端
CAP框架
同發(fā)送端一樣绪妹,在你項目運行時候會在你項目指定得數(shù)據(jù)庫生成一張表(cap.received)這張表是用來存儲消費的消息日志柿究。消息有三個狀態(tài)(Scheduled,Succeeded廊移,F(xiàn)ailed)探入,啟動程序時候同時還會啟動一個監(jiān)聽程序,隔幾分鐘把表中Failed的消息重消費苗膝。
發(fā)送端演示下單植旧,消費端就來個扣庫存的。
RocketMq
訂閱消息有兩種方式:
1.通過http拉任是浴(注意 官方的SDK的http請求性能很差域庇,建議最好自己寫)
2.開啟tcp監(jiān)聽獲雀不(注意 .net的TCP監(jiān)聽獲取消息的SDK至今沒有Linux版本--2019年12月13)
獲取消息需要在代碼里進行ack確認
總結(jié)
CAP框架:功能單一,使用簡單尉姨,.net體系的可自行擴展吗冤,適合自治微服務(wù)架構(gòu)九府。
RocketMq:功能豐富昔逗,維護簡單篷朵,穩(wěn)定性強,但使用還需要自己做相關(guān)開發(fā)笔链,使用成本高腮猖,對.net支持不太好,適合中臺服務(wù)澈缺。