業務背景
7號10:00創建活動,7號0:00到7號10:00之間下單未支付的用戶push催付,7號10:00後用戶下單5分鐘內沒有支付,以PUSH的方式催付
方案
0-10點間數據可理解爲離線數據,可通過創建一個ad-hoc查詢任務,並吐出人羣到給發送服務。
下單後5分鐘後沒有支付以push催付,採用Redis的延遲列隊方案
如果爲下單半個小時後催付,建議採用DB輪詢方案。
https://blog.csdn.net/asd491310/article/details/90418292中列舉了延遲任務的解決方案,不論是RocketMQ、TimingWheel等方案,基本思路是有效減少掃描數據集。
集合S按時間排序,T1輪詢隊頭若干個元素,判斷是否符合條件,若符合條件,就取出所有符合條件的元素。
假設每5分鐘符合預期的元素有1000個以上,建議通過消息中間件發送給專門消息上發送的集羣處理
假設每5分鐘符合預期的元素在1000以內,建議採用Reactor線程池模式。
方案思考:
優點:實現簡單,輪詢消耗資源少
缺點:按延遲時間建立延遲隊列,建議按1、5、10分鐘做延遲隊列,不建義隨意創建延遲隊列,不好維護,一個隊列最大吞吐量爲單臺Redis的吞吐量。
數據結構
假設每5分鐘內的訂單數據爲10000以內,5秒輪詢一次
a. Sorted sets,timestamp爲score
1. 查找元素是否到達可發送時間:
ZREMRANGEBYSCORE key min max
時間複雜度: O( log(N)+ M),其中 N 是已排序集合中元素的數量,M 是由操作移除的元素數量,複雜度爲1004
注意:這裏不使用ZCOUNT key min max
時間複雜度: O( log(N)),其中 N 是有序集合中元素的數量。複雜度爲4。當ZREMRANGEBYSCORE 沒有返回數據時時間複雜度均爲O( log(N)),同ZREMRANGEBYSCORE 可簡化應用代碼邏輯,查找、獲取數據、刪除數據代碼統一了。也可取一個元素存儲在本地做輪詢。減少輪詢對Redis的開銷
2. 刪除已移除購物車的元素
ZREM key member [member ...]
時間複雜度: O( M * log(N)),其中 N 是有序集合中元素的數量,M 是要移除的元素的數量,複雜度爲4*1
3. 新增元素
ZADD key [NX|XX] [CH] [INCR] score member [score member ...]
時間複雜度:添加每個項目的O(log(N)),其中N是排序集合中元素的數量,複雜度爲4
延遲時間內數據量10000以內,Sorted sets爲筆者建議數據結構,數據量在往上建議,查找元素步驟與獲取數據步驟分離,減少對Redis的壓力。
b. List ,按插入順序存儲
假設秒級誤差可以忽略,那麼從5秒級的視角看,List也是一個有效有序的列表,且符合業務預期
1. 查找元素是否到達可發送時間:
LINDEX key index
時間複雜度: O(N)其中N是要到達索引處元素的遍歷元素的數量。
LINDEX key 0 查詢列表第一個元素,複雜度爲1
2. 刪除已移除購物車元素
LREM key count value,時間複雜度爲O(N),不建議使用。移除購物車的訂單建議使用string結構存儲,有效期爲10分鐘。
不支持
3. 新增元素
lpush/rpush,複雜度爲1
4. 獲取元素
lpop/rpop,複雜度爲1