RocketMQ學習筆記(14)----RocketMQ的去重策略
1. Exactly Only Once
(1). 傳送訊息階段,不允許傳送重複的訊息
(2). 消費訊息階段,不允許消費重複的訊息。
只有以上兩個條件都滿足情況下,才能認為訊息是“Exactly Only Once”,而要實現以上兩點,在分散式系統環
境下,不可避免要產生巨大的開銷。所以RocketMQ 為了追求高效能,並不保證此特性,要求在業務上進行去重,也就是說消費訊息要做到冪等性。RocketMQ 雖然不能嚴格保證不重複,但是正常情況下很少會出現重複傳送、消
費情況,只有網路異常,Consumer 啟停等異常情況下會出現訊息重複。
此問題的本質原因是網路呼叫存在不確定性,即既不成功也不失敗的第三種狀態,所以才產生了訊息重複性問
題。
2. 重複消費的原因
在於回饋機制。正常情況下,消費者在消費訊息時候,消費完畢後,會發送一個ACK確認資訊給訊息佇列(broker),訊息佇列(broker)就知道該訊息被消費了,就會將該訊息從訊息佇列中刪除。
不同的訊息佇列傳送的確認資訊形式不同,例如RabbitMQ是傳送一個ACK確認訊息,RocketMQ是返回一個CONSUME_SUCCESS成功標誌,kafka實際上有個offset的概念。
造成重複消費的原因?,就是因為網路原因閃斷,ACK返回失敗等等故障,確認資訊沒有傳送到訊息佇列,導致訊息佇列不知道自己已經消費過該訊息了,再次將該訊息分發給其他的消費者。(因為訊息重試等機制的原因,如果一個consumer斷了,rocketmq有consumer叢集,會將該訊息重新發給其他consumer)
3. 去重策略
去重原則:1.冪等性 2.業務去重
冪等性:(處理必須唯一) 無論這個業務請求被(consumer)執行多少次,我們的資料庫的結果都是唯一的,不可變的。
去重策略:去重表機制,業務拼接去重策略(比如唯一流水號)
1.建立一個訊息表,拿到這個訊息做資料庫的insert操作。給這個訊息做一個唯一主鍵(primary key)或者唯一約束,那麼就算出現重複消費的情況,就會導致主鍵衝突。
高併發下去重:採用Redis去重(key天然支援原子性並要求不可重複),但是由於不在一個事務,要求有適當的補償策略,但是對於很重要的業務,不應該支援補償
2.利用redis事務,主鍵(我們必須把全量的操作資料都存放在redis裡,然後定時去和資料庫做資料同步)—-即消費處理後,該處理本來應該儲存在資料庫的,先儲存在redis,再通過一定業務方式從redis中取資料進行db持久化
3.利用redis和關係型資料庫一起做去重機制
4.拿到這個訊息做redis的set的操作.redis就是天然冪等性
5.準備一個第三方介質,來做消費記錄。以redis為例,給訊息分配一個全域性id,只要消費過該訊息,將 < id,message>以K-V形式寫入redis。那消費者開始消費前,先去redis中查詢有沒消費記錄即可。