您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關MQ中消息重復消費及解決是怎樣的,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
因為在網絡延遲的情況下,消息重復發送的問題不可避免的發生,如果非要實現消息不可重復發送,那基本太難,因為網絡環境無法預知,還會使程序復雜度加大,因此默認允許消息重復發送。
只要通過網絡交換數據,就無法避免這個問題。所以解決這個問題的辦法就是繞過這個問題。那么問題就變成了:如果消費端收到兩條一樣的消息,應該怎樣處理?
RabbitMQ、RocketMQ、Kafka,都有可能會出現消息重復消費的問題,正常。因為這問題通常不是 MQ 自己保證的,是由我們開發來保證的。
RabbitMQ 不保證消息不重復,如果你的業務需要保證嚴格的不重復消息,需要你自己在業務端去重。
AMQP 消費者確認機制
AMQP 定義了消費者確認機制(message ack),如果一個消費者應用崩潰掉(此時連接會斷掉,broker 會得知),但是 broker 尚未獲得 ack,那么消息會被重新放入隊列。所以 AMQP 提供的是“至少一次交付”(at-least-once delivery),異常情況下,消息會被重復消費,此時業務要實現冪等性(重復消息處理)。
消息重復發布:不存在,因為 AMQP 定義了事務(tx transaction)來確保生產消息被 broker 接收并成功入隊。TX 事務是阻塞調用,生產者需等待 broker 寫磁盤后返回的確認,之后才能繼續發送消息。事務提交失敗時(如 broker 宕機場景),broker 并不保證提交的消息全部入隊。RabbitMQ 使用 confirm 機制來優化生產消息的確認(可以持續發布消息,但會批量回復確認)。
消息重復消費:AMQP 提供的是“至少一次交付”(at-least-once delivery),異常情況下,消息會被重復消費,此時業務要實現冪等性(重復消息處理)。
Kafka
Kafka 實際上有個 offset 的概念,就是每個消息寫進去,都有一個 offset,代表消息的序號,然后 consumer 消費了數據之后,每隔一段時間(定時定期),會把自己消費過的消息的 offset 提交一下。
假如,有這么個場景。數據 1/2/3 依次進入 kafka,kafka 會給這三條數據每條分配一個 offset,代表這條數據的序號,分配的 offset 依次是 152,153,154。消費者從 kafka 去消費的時候,也是按照這個順序去消費。假如當消費者消費了 offset=153 的這條數據,剛準備去提交 offset 到 zookeeper,此時消費者進程被重啟了。那么此時消費過的數據 1,2 的 offset 并沒有提交,kafka 也就不知道你已經消費了 offset=153 這條數據。那么重啟之后,消費者會找 kafka 把上次消費到的那個地方后面的數據繼續傳遞過來。數據 1,2 再次被消費。
如果消費者干的事兒是拿一條數據就往數據庫里寫一條,會導致說,你可能就把數據 1,2 在數據庫里插入了 2 次,那么數據就錯啦。其實重復消費不可怕,可怕的是你沒考慮到重復消費之后,怎么保證冪等性。
解決方案
消費端處理消息的業務邏輯保持冪等性。
冪等性,通俗點說,就一個數據,或者一個請求,給你重復來多次,你得確保對應的數據是不會改變的,不能出錯。
比如,你拿到這個消息做數據庫的insert操作。那就容易了,給這個消息做一個唯一主鍵,那么就算出現重復消費的情況,就會導致主鍵沖突,避免數據庫出現臟數據。
再比如,你拿到這個消息做redis的set的操作,那就容易了,不用解決,因為你無論set幾次結果都是一樣的,set操作本來就算冪等操作。
如果上面兩種情況還不行,上大招。準備一個第三方介質,來做消費記錄。以redis為例,給消息分配一個全局id,只要消費過該消息,將<id,message>以K-V形式寫入redis。那消費者開始消費前,先去redis中查詢有沒消費記錄即可。
關于MQ中消息重復消費及解決是怎樣的就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。