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

2021-10-02 14:44:18 字數 1602 閱讀 3851

如何保證訊息不被重複消費?或者說,如何保證訊息消費的冪等性?

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

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

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

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

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

舉個栗子。

有這麼個場景。資料 1/2/3 依次進入 kafka,kafka 會給這三條資料每條分配乙個 offset,代表這條資料的序號,我們就假設分配的 offset 依次是 152/153/154。消費者從 kafka 去消費的時候,也是按照這個順序去消費。假如當消費者消費了offset=153的這條資料,剛準備去提交 offset 到 zookeeper,此時消費者程序被重啟了。那麼此時消費過的資料 1/2 的 offset 並沒有提交,kafka 也就不知道你已經消費了offset=153這條資料。那麼重啟之後,消費者會找 kafka 說,嘿,哥兒們,你給我接著把上次我消費到的那個地方後面的資料繼續給我傳遞過來。由於之前的 offset 沒有提交成功,那麼資料 1/2 會再次傳過來,如果此時消費者沒有去重的話,那麼就會導致重複消費。

如果消費者幹的事兒是拿一條資料就往資料庫裡寫一條,會導致說,你可能就把資料 1/2 在資料庫裡插入了 2 次,那麼資料就錯啦。

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

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

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

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

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

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

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

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

如何保證訊息不被重複消費啊 如何保證訊息消費時的冪等性 首先就是比如rabbitmq rocketmq kafka,都有可能會出現消費重複消費的問題,正常。因為這問題通常不是mq自己保證的,是給你保證的。然後我們挑乙個kafka來舉個例子,說說怎麼重複消費吧。kafka實際上有個offset的概念,...

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

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

RabbitMQ 如何保證消費不被重複消費?

為什麼會出現訊息重複?訊息重複的原因有兩個 1.生產時訊息重複,2.消費時訊息重複。由於生產者傳送訊息給mq,在mq確認的時候出現了網路波動,生產者沒有收到確認,實際上mq已經接收到了訊息。這時候生產者就會重新傳送一遍這條訊息。生產者中如果訊息未被確認,或確認失敗,我們可以使用定時任務 redis ...