所有的訊息佇列都要保證同一條訊息不會被重復消費
- 舉個例子:假設有個系統,消費一條往資料庫里插入一條,要是你一個訊息重復兩次,你不就插入了兩條,這資料就錯了
- 所以消費到第二次的時候,自己判斷一下已經消費過了,直接扔了,就保留了一條資料
一條資料重復出現兩次,資料庫里就只有一條資料,這就保證了系統的冪等性冪等性,
- 一個請求重復多次,需要確保對應的資料是不會改變的,不能出錯,
為什么會重復消費
(1)生產者重復發送訊息:生產者在往訊息佇列發送訊息時,發生了網路抖動,生產者沒有收到確認信號,但是實際上訊息佇列已經收到了訊息,超過一定時間后生產者會重新發送訊息,這時一條訊息被發送了兩次;
(2)消費者重復接受訊息:消費者成功消費訊息后,發生了網路抖動,訊息佇列沒有收到確認信號,超過一段時間后會重新給消費者投遞相同的訊息,同一條訊息即存在被消費兩次的可能,
如何解決
通用解決方案是在訊息物體中添加全域唯一的id,例如 msg_id(訊息ID),在代碼中保證訊息的冪等性,
- 消費者在收到訊息之后,根據 msg_id 從快取或者資料庫中查詢是否存在已有訊息;
- 如果不存在已有訊息,那么消費之后,將 msg_id 對應的訊息物體或者序列化物件寫入快取或者資料庫;
- 如果存在已有訊息,說明這條訊息已被消費過,丟棄訊息并且打一條告警日志,
并且可以根據重復消費的容忍程度以及性能要求選擇使用快取還是使用資料庫,
- 如果對判斷的速度要求高,可以使用 Redis 作為快取;
- 如果對判斷的穩定性和魯棒性要求高,使用資料庫存盤訊息物體,同時將 msg_id 作為資料庫表的唯一鍵,插入重復記錄一定會拋出例外,避免資料庫因為并發問題產生臟資料,保證了訊息消費的不可重復性,
結合業務分析
- 如果是對資料庫進行寫庫,先根據主鍵查一下,如果這資料都有了,就不寫入
- 如果是寫redis,那沒問題了,反正每次都是set,天然冪等性,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/342145.html
標籤:其他
上一篇:擺爛的計劃(懂得都懂)
