如何保證最少消費一次redis的list隊列數據

 

簡使用pop,不能保證最少消費一次,比如pop超時可能中途丟失,或者消費者處理過程中異常而未能處理完。

解決此問題有多種方法:

  1. 方法一:使用rpoplpush替代pop

這種方法相當於建立了一個回滾,由於操作是在redis端完成的,可保證數據不會丟,當消費者完成業務邏輯後,再清掉lpush的另一隊列,這步有點類似於事務的commit提交。如果在處理過程中消費者異常重啓,則在重啓時先檢查lpush的隊列,完成處理後再清lpush的隊列。

  1. 方法二:使用lrange+ltrim替代pop

消費時先lrange拿到數據,處理完後再使用ltrim清掉已處理的數據(這步也類似於事務的commit提交)。

不過這裏存在一個缺陷:同時只能有一個消費者,不能多線程多進程和多機器同時處理同一個隊列,因此消費者存在單點問題,基於Zookeeper等來解決單點有些重,而且在切換會有些延遲,存在短暫停頓問題。

  1. 方法三:使用eval(lua)+lrange+ltrim替代pop

站在redis端,list可看作是一個本地隊列,藉助eval+lua,可實際這個轉換。既然是本地隊列,則可輕鬆的實現多消費者併發消費(本質是串型的),通過lua取list中的數據,並維護list數據的移動。

第一步是lua方式取得數據,並更新消費偏移;第二步是lua方式提交更新(也類似於事務的commit提交)。

 

上述三種方法,方法二缺陷明顯。而方法一如果消費者在提交前掛掉,另lpush隊列中的數據需要另外處理。方法三相對好維護,即使消費者在提交前掛掉,另外的消費在提交時可以幫助解決消費位置移動(實際是調用ltrim)問題。

當然由於redis的主節點和複製節點間是異步複製,該機制存在的丟數據問題無法通過上述三個方法來解決。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章