溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

MQ中消息重復(fù)消費(fèi)及解決是怎樣的

發(fā)布時間:2021-12-06 09:53:40 來源:億速云 閱讀:658 作者:柒染 欄目:大數(shù)據(jù)

這篇文章將為大家詳細(xì)講解有關(guān)MQ中消息重復(fù)消費(fèi)及解決是怎樣的,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關(guān)知識有一定的了解。

重復(fù)消費(fèi)原因

因?yàn)樵诰W(wǎng)絡(luò)延遲的情況下,消息重復(fù)發(fā)送的問題不可避免的發(fā)生,如果非要實(shí)現(xiàn)消息不可重復(fù)發(fā)送,那基本太難,因?yàn)榫W(wǎng)絡(luò)環(huán)境無法預(yù)知,還會使程序復(fù)雜度加大,因此默認(rèn)允許消息重復(fù)發(fā)送。
只要通過網(wǎng)絡(luò)交換數(shù)據(jù),就無法避免這個問題。所以解決這個問題的辦法就是繞過這個問題。那么問題就變成了:如果消費(fèi)端收到兩條一樣的消息,應(yīng)該怎樣處理?

重復(fù)消費(fèi)問題例子

RabbitMQ、RocketMQ、Kafka,都有可能會出現(xiàn)消息重復(fù)消費(fèi)的問題,正常。因?yàn)檫@問題通常不是 MQ 自己保證的,是由我們開發(fā)來保證的。

RabbitMQ

RabbitMQ 不保證消息不重復(fù),如果你的業(yè)務(wù)需要保證嚴(yán)格的不重復(fù)消息,需要你自己在業(yè)務(wù)端去重。

AMQP 消費(fèi)者確認(rèn)機(jī)制
AMQP 定義了消費(fèi)者確認(rèn)機(jī)制(message ack),如果一個消費(fèi)者應(yīng)用崩潰掉(此時連接會斷掉,broker 會得知),但是 broker 尚未獲得 ack,那么消息會被重新放入隊列。所以 AMQP 提供的是“至少一次交付”(at-least-once delivery),異常情況下,消息會被重復(fù)消費(fèi),此時業(yè)務(wù)要實(shí)現(xiàn)冪等性(重復(fù)消息處理)。

  1. 消息重復(fù)發(fā)布:不存在,因?yàn)?AMQP 定義了事務(wù)(tx transaction)來確保生產(chǎn)消息被 broker 接收并成功入隊。TX 事務(wù)是阻塞調(diào)用,生產(chǎn)者需等待 broker 寫磁盤后返回的確認(rèn),之后才能繼續(xù)發(fā)送消息。事務(wù)提交失敗時(如 broker 宕機(jī)場景),broker 并不保證提交的消息全部入隊。RabbitMQ 使用 confirm 機(jī)制來優(yōu)化生產(chǎn)消息的確認(rèn)(可以持續(xù)發(fā)布消息,但會批量回復(fù)確認(rèn))。

  2. 消息重復(fù)消費(fèi):AMQP 提供的是“至少一次交付”(at-least-once delivery),異常情況下,消息會被重復(fù)消費(fèi),此時業(yè)務(wù)要實(shí)現(xiàn)冪等性(重復(fù)消息處理)。
    Kafka
    Kafka 實(shí)際上有個 offset 的概念,就是每個消息寫進(jìn)去,都有一個 offset,代表消息的序號,然后 consumer 消費(fèi)了數(shù)據(jù)之后,每隔一段時間(定時定期),會把自己消費(fèi)過的消息的 offset 提交一下。

假如,有這么個場景。數(shù)據(jù) 1/2/3 依次進(jìn)入 kafka,kafka 會給這三條數(shù)據(jù)每條分配一個 offset,代表這條數(shù)據(jù)的序號,分配的 offset 依次是 152,153,154。消費(fèi)者從 kafka 去消費(fèi)的時候,也是按照這個順序去消費(fèi)。假如當(dāng)消費(fèi)者消費(fèi)了 offset=153 的這條數(shù)據(jù),剛準(zhǔn)備去提交 offset 到 zookeeper,此時消費(fèi)者進(jìn)程被重啟了。那么此時消費(fèi)過的數(shù)據(jù) 1,2 的 offset 并沒有提交,kafka 也就不知道你已經(jīng)消費(fèi)了 offset=153 這條數(shù)據(jù)。那么重啟之后,消費(fèi)者會找 kafka 把上次消費(fèi)到的那個地方后面的數(shù)據(jù)繼續(xù)傳遞過來。數(shù)據(jù) 1,2 再次被消費(fèi)。

如果消費(fèi)者干的事兒是拿一條數(shù)據(jù)就往數(shù)據(jù)庫里寫一條,會導(dǎo)致說,你可能就把數(shù)據(jù) 1,2 在數(shù)據(jù)庫里插入了 2 次,那么數(shù)據(jù)就錯啦。其實(shí)重復(fù)消費(fèi)不可怕,可怕的是你沒考慮到重復(fù)消費(fèi)之后,怎么保證冪等性。

解決方案
消費(fèi)端處理消息的業(yè)務(wù)邏輯保持冪等性。
冪等性,通俗點(diǎn)說,就一個數(shù)據(jù),或者一個請求,給你重復(fù)來多次,你得確保對應(yīng)的數(shù)據(jù)是不會改變的,不能出錯。

  1. 比如,你拿到這個消息做數(shù)據(jù)庫的insert操作。那就容易了,給這個消息做一個唯一主鍵,那么就算出現(xiàn)重復(fù)消費(fèi)的情況,就會導(dǎo)致主鍵沖突,避免數(shù)據(jù)庫出現(xiàn)臟數(shù)據(jù)。

  2. 再比如,你拿到這個消息做redis的set的操作,那就容易了,不用解決,因?yàn)槟銦o論set幾次結(jié)果都是一樣的,set操作本來就算冪等操作。

  3. 如果上面兩種情況還不行,上大招。準(zhǔn)備一個第三方介質(zhì),來做消費(fèi)記錄。以redis為例,給消息分配一個全局id,只要消費(fèi)過該消息,將<id,message>以K-V形式寫入redis。那消費(fèi)者開始消費(fèi)前,先去redis中查詢有沒消費(fèi)記錄即可。

關(guān)于MQ中消息重復(fù)消費(fèi)及解決是怎樣的就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

mq
AI