業務處理成功,發送MQ失敗?

記得上次面試官問了我一個問題:

  • 面試官:你說你們項目用到了MQ,那麼你往MQ發消息是在你業務事務提交之前還是之後呢?

  • 我:……

那接下來分析一下這個問題。


場景復現

比如有個搶購,用戶服務點擊搶購,訂單服務先返回排隊中,訂單服務處理完了之後肯定是通過MQ異步通知去支付的。現在的問題是,發MQ告訴用戶搶去付款這個操作是在訂單相關操作(比如扣庫存,訂單入庫等)的事務提交之前還是之後呢?如果是之前,那如果事務回滾了就會出現用戶付了錢但是訂單沒入庫的情況;如果是之後,那就可能會出現訂單入庫了但是沒通知用戶去付款的情況。


簡言之,就是要讓數據庫操作和發送MQ是在同一個事務內!


事務消息

可能有人想到了,這不就是事務消息嘛!沒錯,不過不同的MQ事務消息也有所不同。

kafka事務消息

kafka事務類似數據庫事務,就是一條消息要發往多個分區的時候,它可以保證發往的這多個分區同時成功或者失敗,這種事務顯然不能解決上面的問題。


RocketMQ事務消息
  • 流程:它是兩階段提交事務,可以很好地解決上面的問題。一階段先發送一條half消息到MQ Server,此時這條消息對消費者是不可見的;接着執行業務邏輯;二階段根據業務邏輯的執行結果,判斷MQ的事務是提交還是回滾,如果提交,那麼這條消息就可以被消費者消費了。
  • 補償措施:如果根據業務邏輯對MQ事務執行提交或者回滾時因爲超時等原因失敗了,MQ Server會回調業務端的接口,通過這個接口去查詢剛纔的業務到底成功了沒有,根據查詢結果再決定MQ的事務要提交還是回滾。這個回調接口是需要我們自己去實現的。


其他方案

  • 新建一個表用來保存生產者生產的消息;
  • 在執行業務邏輯的方法裏,不直接把消息發往MQ,而是先入庫;
  • 這樣可以保證這兩個入庫操作是同一個數據庫事務;
  • 最後通過定時任務去查詢庫中的消息,發往MQ,發失敗了還可以通過該任務重發


總結

RocketMQ的兩階段提交事務可以解決這個問題,但是每個場景我們都需要寫對應的回調接口;先入庫再通過定時任務去發消息這種方案可能就會有一點點的延時,即定時任務執行的頻率就是消息消費的延時時長,比如你5秒執行一次,那麼消息入庫後最多就需要5秒鐘後纔會被查出來去消費。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章