JAVA面試如何保證消息不被重複消費?如何保證消息消費的冪等性?

狂野女子


其實這是很常見的一個問題,這倆問題基本可以連起來問。既然是消費消息,那肯定要考慮會不會重複消費?能不能避免重複消費?或者重複消費了也別造成系統異常可以嗎?這個是 MQ 領域的基本問題,其實本質上還是問你使用消息隊列如何保證冪等性,這個是你架構裡要考慮的一個問題。

面試題剖析

回答這個問題,首先你別聽到重複消息這個事兒,就一無所知吧,你先大概說一說可能會有哪些重複消費的問題。

首先,比如 RabbitMQ、RocketMQ、Kafka,都有可能會出現消息重複消費的問題,正常。因為這問題通常不是 MQ 自己保證的,是由我們開發來保證的。挑一個 Kafka 來舉個例子,說說怎麼重複消費吧。

Kafka 實際上有個 offset 的概念,就是每個消息寫進去,都有一個 offset,代表消息的序號,然後consumer 消費了數據之後,每隔一段時間(定時定期),會把自己消費過的消息的 offset 提交一下,表示“我已經消費過了,下次我要是重啟啥的,你就讓我繼續從上次消費到的 offset 來繼續消費吧”。

但是凡事總有意外,比如我們之前生產經常遇到的,就是你有時候重啟系統,看你怎麼重啟了,如果碰到點著急的,直接 kill 進程了,再重啟。這會導致 consumer 有些消息處理了,但是沒來得及提交 offset,尷尬了。重啟之後,少數消息會再次消費一次。


夜玫瑰163


今天,讓我們一起看看保證 MQ 的冪等性有哪些方案。


01. 冪等性的概念

先說說什麼是冪等性。

當用戶對同一操作請求了一次或者多次(消息發送或接收了多次),最終的結果是一致的,並不會因為多次請求產生副作用;比如同一個訂單支付了兩次,最後應該只扣客戶一次錢。

  • 查詢和刪除:查詢具有天然的冪等性,在數據不變的前提下,相同查詢條件查詢一次和查詢多次的結果都是一樣的;刪除也一樣,相同的條件刪除一次和刪除多次,可能刪除的數據量不一樣,但是數據庫中的數據不會因為執行了多次刪除而不同。

  • 新增和修改:如果不做冪等性處理,可能就會產生問題;執行多次新增操作,可能會導致一模一樣的數據產生了多條(主鍵自動生成);修改操作,如果只是把某些字段更新成固定的值,不會有冪等性問題,但是如果新值要在舊值上做處理做計算,如增加多少、減少多少,那麼多次執行的結果就會有差異。

02. MQ 消息出現非冪等的情況

1. 生產者發送消息給 MQ,為了保證消息可達,通常會使用超時重傳機制,但是如果生產者的消息已經發出去,但是由於網絡原因未收到確認信息,那麼可能會進行重發,最終造成了消息的重複發送。

2. 消費者消費的過程也類似,消費者接受到 MQ 的消息,但是 MQ 未收到確認信息,那麼該條消息可能會重新發送給其他消費者,或者網絡恢復再次發送給消費者,最終造成重複消費。


03. 解決方法

1. 唯一索引

使用唯一索引,可以有效的防止新增髒數據:當表中存在唯一索引的時候,併發新增相同數據的時候就會報錯,不過這在單庫單表的時候才有效,如果項目數據量很大,採用了分庫分表的策略,就不能再通過數據庫的唯一性索引來解決冪等性的問題了。


2. 全局唯一 ID

每條消息,都攜帶一個全局的唯一 ID,消費者接收到消息,在執行前判斷這個 ID 是否已經在本地存在,如果不存在,則執行交易後記錄 ID(存到數據庫或Redis中,表示該交易已經執行);如果已經存在,表示消息已經消費掉了,不能再次執行。

許多分佈式架構中,生成全局唯一 ID 都會被作為一個基礎的微服務,當然這個服務的可靠性要求極高,或者可以使用全局唯一 ID 算法,由每個應用自己生成。不過總的來說,引入全局唯一 ID 這個方案,實現起來還是非常繁瑣的。

3. 業務狀態

保證消息的冪等性,也可以結合業務流程考慮,比如很多業務流程每一步都是有狀態的,比如網上購物可能會有:訂單創建、付款、發貨,那麼付款之前保單狀態為“待付款”,付款之後可以將保單的狀態修改為“待發貨”;那麼如果發起重複扣款的話,第二次扣款的時候保單狀態已經變化了,就會扣款失敗。

4. 去重表

如果業務中有唯一性的標識時,可以使用去重表,把這個唯一性的表示保存到去重表中,如果重複插入,那麼會被校驗住。

比如上面的場景,一個訂單隻會付款一次,那麼在付款的時候,把訂單號作為唯一性的標識,保存到去重表中,可以保證付款操作只會發生一次;這個方法也用到了唯一 ID,不過和全局唯一 ID 不同,這個唯一 ID 是針對具體業務的。

我將持續分享Java開發、架構設計、程序員職業發展等方面的見解,希望能得到你的關注。


會點代碼的大叔


太複雜了簡短文字難以說明問題,比如說:“Kafka 實際上有個 offset 的概念,就是每個消息寫進去,都有一個 offset,代表消息的序號,然後 consumer 消費了數據之後,每隔一段時間(定時定期),會把自己消費過的消息的 offset 提交一下,表示“我已經消費過了,下次我要是重啟啥的,你就讓我繼續從上次消費到的 offset 來繼續消費吧”。


來者不俗


這要從提安全性,同步設置,標註同步,註銷同步設置,這是軟件沒置問題。如果做到標記與消費信息實現同步,就不會出現重複的問題了。


覃紹繼


問答來了,我可說,面試等我不會重複消費,因為老人連什麼什麼都不認識,絕對不會走漏風聲,慎重保密無重複。下次再答,謝謝!


某30094317


以上的這個問題我確實知道的很少,我無法回答對不起我讓樓主失望了!


zhangyong7660



御v虹v宇v勳


這個問題太容易回答,根本就不知道這是什麼問題,沒法回答,只能說不知道。


雷神159299026


這個問題比較犀利,因為我不是這個專業人員,希望有專業人員幫你答覆


心心月亮灣


這個問題提的好,我感覺都快崩潰了。原因很簡單,我不懂,從中實在找不出樂趣來。


分享到:


相關文章: