RabbitMQ如何解決被重複消費和資料丟失的問題

2021-09-24 04:47:30 字數 2241 閱讀 6366

為什麼要使用mq?

1.解耦,系統a在**中直接呼叫系統b和系統c的**,如果將來d系統接入,系統a還需要修改**,過於麻煩!

2.非同步,將訊息寫入訊息佇列,非必要的業務邏輯以非同步的方式執行,加快響應速度

3.削峰,併發量大的時候,所有的請求直接懟到資料庫,造成資料庫連線異常

使用了訊息佇列會有什麼缺點?

1.系統可用性降低:你想啊,本來其他系統只要執行好好的,那你的系統就是正常的。現在你非要加個訊息佇列進去,那訊息佇列掛了,你的系統不是呵呵了。因此,系統可用性降低

2.系統複雜性增加:要多考慮很多方面的問題,比如一致性問題、如何保證訊息不被重複消費,如何保證保證訊息可靠傳輸。因此,需要考慮的東西更多,系統複雜性增大。

如何保證訊息佇列是高可用的?

使用集群的方式維持mq的可高用性。

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

保證訊息不被重複消費的關鍵是保證訊息佇列的冪等性,這個問題針對業務場景來答分以下幾點:

1.比如,你拿到這個訊息做資料庫的insert操作。那就容易了,給這個訊息做乙個唯一主鍵,那麼就算出現重複消費的情況,就會導致主鍵衝突,避免資料庫出現髒資料。

2.再比如,你拿到這個訊息做redis的set的操作,那就容易了,不用解決,因為你無論set幾次結果都是一樣的,set操作本來就算冪等操作。

3.如果上面兩種情況還不行,上大招。準備乙個第三方介質,來做消費記錄。以redis為例,給訊息分配乙個全域性id,只要消費過該訊息,將以k-v形式寫入redis。那消費者開始消費前,先去redis中查詢有沒消費記錄即可。

如何解決丟資料的問題?

1.生產者丟資料

生產者的訊息沒有投遞到mq中怎麼辦?從生產者弄丟資料這個角度來看,rabbitmq提供transaction和confirm模式來確保生產者不丟訊息。

transaction機制就是說,傳送訊息前,開啟事物(channel.txselect()),然後傳送訊息,如果傳送過程**現什麼異常,事物就會回滾(channel.txrollback()),如果傳送成功則提交事物(channel.txcommit())。

然而缺點就是吞吐量下降了。因此,按照博主的經驗,生產上用confirm模式的居多。一旦channel進入confirm模式,所有在該通道上面發布的訊息都將會被指派乙個唯一的id(從1開始),一旦訊息被投遞到所有匹配的佇列之後,rabbitmq就會傳送乙個ack給生產者(包含訊息的唯一id),這就使得生產者知道訊息已經正確到達目的佇列了.如果rabiitmq沒能處理該訊息,則會傳送乙個nack訊息給你,你可以進行重試操作。

2.訊息佇列丟資料

處理訊息佇列丟資料的情況,一般是開啟持久化磁碟的配置。這個持久化配置可以和confirm機制配合使用,你可以在訊息持久化磁碟後,再給生產者傳送乙個ack訊號。這樣,如果訊息持久化磁碟之前,rabbitmq陣亡了,那麼生產者收不到ack訊號,生產者會自動重發。

那麼如何持久化呢,這裡順便說一下吧,其實也很容易,就下面兩步

①、將queue的持久化標識durable設定為true,則代表是乙個持久的佇列

②、傳送訊息的時候將deliverymode=2

這樣設定以後,rabbitmq就算掛了,重啟後也能恢復資料。在訊息還沒有持久化到硬碟時,可能服務已經死掉,這種情況可以通過引入mirrored-queue即映象佇列,但也不能保證訊息百分百不丟失(整個集群都掛掉)

3.消費者丟資料

啟用手動確認模式可以解決這個問題

①自動確認模式,消費者掛掉,待ack的訊息回歸到佇列中。消費者丟擲異常,訊息會不斷的被重發,直到處理成功。不會丟失訊息,即便服務掛掉,沒有處理完成的訊息會重回佇列,但是異常會讓訊息不斷重試。

②手動確認模式,如果消費者來不及處理就死掉時,沒有響應ack時會重**送一條資訊給其他消費者;如果監聽程式處理異常了,且未對異常進行捕獲,會一直重複接收訊息,然後一直拋異常;如果對異常進行了捕獲,但是沒有在finally裡ack,也會一直重**送訊息(重試機制)。

③不確認模式,acknowledge="none" 不使用確認機制,只要訊息傳送完成會立即在佇列移除,無論客戶端異常還是斷開,只要傳送完就移除,不會重發。

如何保證訊息的順序性?

針對這個問題,通過某種演算法,將需要保持先後順序的訊息放到同乙個訊息佇列中。然後只用乙個消費者去消費該佇列。同乙個queue裡的訊息一定是順序訊息的。我的觀點是保證入隊有序就行,出隊以後的順序交給消費者自己去保證,沒有固定套路。例如b訊息的業務應該保證在a訊息後業務後執行,那麼我們保證a訊息先進queuea,b訊息後進queueb就可以了。

如何解決「重複定義」

標頭檔案中一般只包含宣告,不包含變數的定義,如果沒辦法必須在標頭檔案中包含定義的話,多次引用該標頭檔案時,常遇到函式或者變數被重複定義的錯誤,比喻file1.h中定義了int a file2.h中也定義了 int a 此時在file.c中既包含file1.h也包含file2.h,在預編譯是,file...

如何解決oracle分頁查詢資料重複問題

本文 未作修改。oracle分頁查詢時,會遇到資料重複的問題,下面就教您乙個解決oracle分頁查詢資料重複問題的方法,希望對您能夠有所幫助。在oracle分頁查詢中,我們採用類似以下所示的公認的比較高效的資料庫分頁查詢語句 effective oracle by design中有描述 眾多orac...

如何解決 shell 指令碼重複執行的問題

flock 是檔案鎖命令,它可以保證linux系統上程序之間安全的訪問臨界資源,在shell指令碼中,可以用來控制邏輯的互斥性 現有指令碼 a.sh,內容如下 bin bash echo date y m d h m s begin pid sleep 10 echo date y m d h m ...