靈感來襲,基於Redis的分佈式延遲隊列(續)

背景

上一篇(靈感來襲,基於Redis的分佈式延遲隊列)講述了基於Java DelayQueue和Redis實現了分佈式延遲隊列,這種方案實現比較簡單,應用於延遲小,消息量不大的場景是沒問題的,畢竟Java DelayQueue是佔用內存的。針對現用方案的不足,因而利用Redis的Sorted Set數據結構簡單實現分佈式延遲隊列。html

Sorted Set

  • Redis 有序集合和集合同樣也是string類型元素的集合,且不容許重複的成員。
  • 不一樣的是每一個元素都會關聯一個double類型的分數。redis正是經過分數來爲集合中的成員進行從小到大的排序。
  • 有序集合的成員是惟一的,但分數(score)卻能夠重複。

設計思路

  1. 使用Redis的Sorted Set做爲中轉隊列,爲防止延遲消息量過大,維護多個Sorted Set,將延遲消息按照hash值平均分佈到不一樣的Sorted Set中。
  2. 因爲Sorted Set自己具有有序性,將延遲時間做爲score值和延遲消息綁定到一塊兒存入Sorted Set中。
  3. 另起Java定時任務,每隔必定時間掃描全部Sorted Set,並經過ZRANGEBYSCORE操做取出符合條件的延遲消息,而後放入目標隊列等待消費者消費。

代碼實現

延遲隊列建立

根據queueName分別建立中轉隊列(Sorted Set)和 目標隊列key值,其中queueSize是中轉隊列的大小。redis

延遲消息投遞

根據延遲消息的hash值,平均分配到不一樣的中轉隊列(Sorted Set)中去。數據結構

中轉定時任務

 

經過分佈式鎖來鎖定惟一的線程來執行延遲消息遷移到目標隊列的操做。遍歷所有的中轉隊列,由於延遲消息是和延遲時間戳關聯的,使用ZRANGEBYSCORE命令,取出延遲時間小於當前時間的50條消息並經過LPUSH命令放入目標隊列裏。分佈式

延遲消息消費

 經過RPOP命令不斷的從目標隊列獲取延遲消息,執行相應的消費邏輯。線程

總結

本文描述的實現方案還有諸多異常狀況還沒有考慮,好比生產者發送失敗、消費者消費失敗的狀況,沒法保證極端狀況下生產者和消費者兩端的數據一致性。該方案能夠知足業務量不是很大、延遲時間較長、容許部分數據可能丟失的場景,好比用戶簽到提醒,能夠根據用戶簽到的時間,次日在相應的時間點推送消息提醒用戶繼續簽到。設計

相關文章
相關標籤/搜索