訊息佇列三 訊息重複消費問題(冪等性)

2021-09-23 10:21:06 字數 1613 閱讀 1971

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

首先就是比如rabbitmq、rocketmq、kafka,都有可能會出現消費重複消費的問題,正常。因為這問題通常不是mq自己保證的,是給你保證的。然後我們挑乙個kafka來舉個例子,說說怎麼重複消費吧。

kafka實際上有個offset的概念,就是每個訊息寫進去,都有乙個offset,代表他的序號,然後consumer消費了資料之後,每隔一段時間,會把自己消費過的訊息的offset提交一下,代表我已經消費過了,下次我要是重啟啥的,你就讓我繼續從上次消費到的offset來繼續消費吧。

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

其實重複消費不可怕,可怕的是你沒考慮到重複消費之後,怎麼保證冪等性。

給你舉個例子吧。假設你有個系統,消費一條往資料庫裡插入一條,要是你乙個訊息重複兩次,你不就插入了兩條,這資料不就錯了?但是你要是消費到第二次的時候,自己判斷一下已經消費過了,直接扔了,不就保留了一條資料?

一條資料重複出現兩次,資料庫裡就只有一條資料,這就保證了系統的冪等性

冪等性,我通俗點說,就乙個資料,或者乙個請求,給你重複來多次,你得確保對應的資料是不會改變的,不能出錯。

那所以第二個問題來了,怎麼保證訊息佇列消費的冪等性?

其實還是得結合業務來思考,我這裡給幾個思路:

(1)比如你拿個資料要寫庫,你先根據主鍵查一下,如果這資料都有了,你就別插入了,update一下好吧

(2)比如你是寫redis,那沒問題了,反正每次都是set,天然冪等性

(3)比如你不是上面兩個場景,那做的稍微複雜一點,你需要讓生產者傳送每條資料的時候,裡面加乙個全域性唯一的id,類似訂單id之類的東西,然後你這裡消費到了之後,先根據這個id去比如redis里查一下,之前消費過嗎?如果沒有消費過,你就處理,然後這個id寫redis。如果消費過了,那你就別處理了,保證別重複處理相同的訊息即可。

還有比如基於資料庫的唯一鍵來保證重複資料不會重複插入多條,我們之前線上系統就有這個問題,就是拿到資料的時候,每次重啟可能會有重複,因為kafka消費者還沒來得及提交offset,重複資料拿到了以後我們插入的時候,因為有唯一鍵約束了,所以重複資料只會插入報錯,不會導致資料庫**現髒資料

如何保證mq的消費是冪等性的,需要結合具體的業務來看

訊息佇列 保證訊息消費的冪等

昨天業務反饋了乙個問題,乙個使用者的月流水賬單重複了,拿到userid,開始定位問題之路。檢視資料庫記錄,如下圖,使用者月流水資料確實重複了 taskid同乙個批次,每個月資料都有二條 1.首先,看外部資料 商是否重複推送業務資料給我,我程式中是會設定攔截重複訊息 2.檢視訊息接收,以及訊息推送到m...

訊息冪等 如何保證訊息不被重複消費?

應用的冪等是在分布式系統設計時必須要考慮的乙個方面,如果對冪等沒有額外的考慮,那麼在訊息失敗重新投遞,或者遠端服務重試時,可能會出現許多詭異的問題。一起來看一下,在訊息佇列應用中,如何處理因為重複投遞等原因導致的冪等問題。不同訊息佇列支援的投遞方式 業務上如何處理冪等 首先明確一下,冪等並不是問題,...

訊息佇列 重複消費問題

所謂冪等性,就是資料無論操作多少次,所產生的影響跟執行一次是一樣的,比如對於讀操作來說,無論讀取多少次資料,都跟讀取一次的資料是一樣的,所以讀操作是乙個冪等性操作,而新增操作,新增多次會有多條記錄,因而寫操作則是非冪等性操作。因而對於以上場景,只要保證訊息消費的冪等性,就能解決重複消費的問題。常見的...