1、保證訊息不被重複消費的關鍵是保證訊息佇列的冪等性,這個問題針對業務場景來答分以下幾點:
生產者的訊息沒有投遞到mq中怎麼辦?從生產者弄丟資料這個角度來看,rabbitmq提供transaction和confirm模式來確保生產者不丟訊息。
transaction機制就是說,傳送訊息前,開啟事物(channel.txselect()),然後傳送訊息,如果傳送過程**現什麼異常,事務就會回滾(channel.txrollback()),如果傳送成功則提交事物(channel.txcommit())。然而缺點就是吞吐量下降了。
因此,按照博主的經驗,生產上用confirm模式的居多。一旦channel進入confirm模式,所有在該通道上面發布的訊息都將會被指派乙個唯一的id(從1開始),一旦訊息被投遞到所有匹配的佇列之後,rabbitmq就會傳送乙個ack給生產者(包含訊息的唯一id),這就使得生產者知道訊息已經正確到達目的佇列了。如果rabiitmq沒能處理該訊息,則會傳送乙個nack訊息給你,你可以進行重試操作。
處理訊息佇列丟資料的情況一般是開啟持久化磁碟的配置。這個持久化配置可以和confirm機制配合使用,你可以在訊息持久化磁碟後,再給生產者傳送乙個ack訊號。這樣,如果訊息持久化磁碟之前,rabbitmq陣亡了,那麼生產者收不到ack訊號,生產者會自動重發。那麼如何持久化呢,這裡順便說一下吧,其實也很容易,就下面兩步:
①將queue的持久化標識durable設定為true,則代表是乙個持久的佇列
②傳送訊息的時候將deliverymode=2這樣設定以後,rabbitmq就算掛了,重啟後也能恢復資料。在訊息還沒有持久化到硬碟時,可能服務已經死掉,這種情況可以通過引入mirrored-queue即映象佇列,但也不能保證訊息百分百不丟失(整個集群都掛掉)
啟用手動確認模式可以解決這個問題
①自動確認模式,消費者掛掉,待ack的訊息回歸到佇列中。消費者丟擲異常,訊息會不斷的被重發,直到處理成功。不會丟失訊息,即便服務掛掉,沒有處理完成的訊息會重回佇列,但是異常會讓訊息不斷重試。
②手動確認模式,如果消費者來不及處理就死掉時,沒有響應ack時會重**送一條資訊給其他消費者;如果監聽程式處理異常了,且未對異常進行捕獲,會一直重複接收訊息,然後一直拋異常;如果對異常進行了捕獲,但是沒有在finally裡ack,也會一直重**送訊息(重試機制)。
③不確認模式,acknowledge=「none」 不使用確認機制,只要訊息傳送完成會立即在佇列移除,無論客戶端異常還是斷開,只要傳送完就移除,不會重發。
針對這個問題,通過某種演算法,將需要保持先後順序的訊息放到同乙個訊息佇列中。然後只用乙個消費者去消費該佇列。同乙個queue裡的訊息一定是順序訊息的。我的觀點是保證入隊有序就行,出隊以後的順序交給消費者自己去保證,沒有固定套路。例如b訊息的業務應該保證在a訊息後業務後執行,那麼我們保證a訊息先進queuea,b訊息後進queueb就可以了。
rabbitMQ如何避免重複消費
由於生產者傳送訊息給mq,在mq確認的時候出現了網路波動,生產者沒有收到確認,實際上mq已經接收到了訊息。這時候生產者就會重新傳送一遍這條訊息。生產者中如果訊息未被確認,或確認失敗,我們可以使用定時任務 redis db 來進行訊息重試 消費者消費成功後,再給mq確認的時候出現了網路波動,mq沒有接...
RabbitMQ 如何保證消費不被重複消費?
為什麼會出現訊息重複?訊息重複的原因有兩個 1.生產時訊息重複,2.消費時訊息重複。由於生產者傳送訊息給mq,在mq確認的時候出現了網路波動,生產者沒有收到確認,實際上mq已經接收到了訊息。這時候生產者就會重新傳送一遍這條訊息。生產者中如果訊息未被確認,或確認失敗,我們可以使用定時任務 redis ...
RabbitMQ如何解決被重複消費和資料丟失的問題
為什麼要使用mq?1.解耦,系統a在 中直接呼叫系統b和系統c的 如果將來d系統接入,系統a還需要修改 過於麻煩!2.非同步,將訊息寫入訊息佇列,非必要的業務邏輯以非同步的方式執行,加快響應速度 3.削峰,併發量大的時候,所有的請求直接懟到資料庫,造成資料庫連線異常 使用了訊息佇列會有什麼缺點?1....