寫資料庫同時發mq訊息事務一致性的一種解決方案

普通程式設計師發表於2022-12-05

一、引子

《事務註解(@Transactional)引起的資料覆蓋故障》一文收到不少反饋。

事務裡不要有rpc,基本原則,sb封裝的太好了,把很多人養傻了,function級別的事務,坑太大。
網友一

這個是mysql資料庫併發更新問題,update未提交,並不能阻塞mq讀取後的select操作。很明顯select會取到未提交的快照,在a事務提交之後b提交覆蓋原值。並且事務中間是絕對不應該有外部呼叫的
網友二
去哪qmq的玩法是利用資料庫的事務 所有庫上加一個mq的邏輯庫 mq實際先提交一條資料到mq庫 再用統一的消費者消費mq庫 實現訊息的隔離和最終一致
網友三

隨著公司業務的增長,單體應用架構很難滿足業務快速迭代以及效能方面的需求,都會進行服務化改造,按照業務等要素將原來龐大的單體應用拆分成不同的服務。那麼在進行服務化改造之前首先就是面臨是服務化基礎設施的技術選型,其中最重要的就是服務之間的通訊中介軟體。服務之間的通訊可以分為同步方式和非同步方式。同步的方式的代表就是 RPC,非同步方式一般會選用mq。


二、問題的現實意義


如果我們要在服務化拆分中使用訊息佇列,那麼我們需要解決哪些問題呢?首先去哪兒網提供了旅遊產品線上預訂服務,那麼就涉及電商交易,在電商交易中我們認為資料的一致性是非常關鍵的要素。那麼我們的 MQ 必須提供一致性保證。


MQ 提供一致性保證又分為兩個方面。發訊息時我們如何確保業務操作和發訊息一致的,也就是不能出現業務操作成功訊息未發出或者訊息發出了但是業務並沒有成功的情況。舉例來說,支付服務使用訊息通知出票服務,那麼不能出現支付成功,但是訊息沒有發出,這會引起使用者投訴;但是也不能出現支付未成功,但是訊息發出最後出票了,這會導致公司損失。總結一下就是發訊息和業務需要有事務保證。一致性的另一端是消費者,比如消費者臨時出錯或網路故障,我們如何確保訊息最終被處理了。那麼我們透過消費 ACK 和重試來達到最終一致性


三、利用資料庫事務解決一致性問題


提到一致性,大家肯定就想到事務,而一提到事務,肯定就想到關係型資料庫,那麼我們是不是可以藉助關係型 DB 裡久經考驗的事務來實現這個一致性呢。我們以 MySQL 為例,對於 MySQL 中同一個例項裡面的 db,如果共享相同的 Connection 的話是可以在同一個事務裡的。以下圖為例,我們有一個 MySQL 例項監聽在 3306 埠上,然後該例項上有 A,B 兩個 DB,那麼下面的虛擬碼是可以跑在同一個事務裡的

寫資料庫同時發mq訊息事務一致性的一種解決方案


寫資料庫同時發mq訊息事務一致性的一種解決方案


有了這層保證,我們就可以透明的實現業務操作和訊息傳送在同一個事務裡了,首先我們在公司所有 MySQL 例項裡初始化出一個 message db,這個可以放到自動化流程中(據說在去哪兒由運維團隊完成),對應用透明。然後我們只要將發訊息與業務操作放到同一個 DB 事務裡即可。


我們來看一個實際的場景,在支付場景中,支付成功後我們需要插入一條支付流水,並且傳送一條支付完成的訊息通知其他系統。那麼這裡插入支付流水和傳送訊息就需要是一致的,任何一步沒有成功最後都會導致問題。那麼就有下面的程式碼

寫資料庫同時發mq訊息事務一致性的一種解決方案

上面的程式碼可以用下面的虛擬碼解釋

寫資料庫同時發mq訊息事務一致性的一種解決方案


實際上在 producer.sendMessage 執行的時候,訊息並沒有透過網路傳送出去,而僅僅是往業務 DB 同一個例項上的訊息庫插入一條記錄,然後註冊事務的回撥,在這個事務真正提交後訊息才從網路傳送出去,這個時候如果傳送到 server 成功的話訊息會被立即刪除掉。而如果訊息傳送失敗則訊息就留在訊息庫裡,這個時候我們會有一個補償任務會將這些訊息從訊息庫裡撈出然後重新傳送,直到傳送成功。整個流程就如下圖所示

寫資料庫同時發mq訊息事務一致性的一種解決方案

1、begin tx 開啟本地事務

2、do work 執行業務操作

3、insert message 向同例項訊息庫插入訊息

4、end tx 事務提交

5、send message 網路向 server 傳送訊息

6、reponse server 回應訊息

7、delete message 如果 server 回覆成功則刪除訊息

8、scan messages 補償任務掃描未傳送訊息

9、send message 補償任務補償訊息

10、delete messages 補償任務刪除補償成功的訊息 


四、更多的東西


去哪兒完整的方案,還包括了訊息的儲存模型以及延遲佇列的儲存模型,分別解決效能業務問題。

當然訊息儲存模型這部分,本公眾號之前關於IM的文章的做法也值得參考 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31556438/viewspace-2668318/,如需轉載,請註明出處,否則將追究法律責任。

相關文章