1. 程式人生 > >RocketMQ學習筆記(14)----RocketMQ的去重策略

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中查詢有沒消費記錄即可。