为了防止用户恶意下单,导致商品少卖。订单需要设置30分钟自动过期。
统一来说,业务有“在一段时间之后,完成一个工作任务”的需求。
实现这种定时任务的方法有一下几种

被动处理

定时轮询

如果数据量很大,需要分页查询,分页update,这将会是一个for循环。

弊端:

  1. 时效性差,会有一定的延迟,这个延迟时间最大就是每隔一定时间的大小,如果你设置每分钟定时轮询一次,那么理论上订单取消时间的最大误差就有一分钟,当然也可能更大,比如一分钟之内有大量数据,但是一分钟没处理完,那么下一分钟的就会顺延。

  2. 效率低。

被动取消,只有当用户查询订单时,判断订单是否超时

弊端:

  1. 会导致少卖

  2. 会产生额外影响
    比如统计,订单数量等产生影响

  3. 影响用户体验
    用户打开订单列表可能要处理大量数据,影响显示的实时性。

延时消息

延迟消息其实本质上也是被动处理机制

主要包含两个重要的数据结构

  • 环形队列
    如可以创建一个包含3600个solt的环形队列(本质是一个数组)

  • 任务集合
    环上每一个slot是一个Set

同时启动一个timer,这个timer每隔一秒,在上述环形队列中移动一格,又一个Current Index指针来标识正在检测的slot。
订单30分钟后失效,触发一个30分钟后的延迟消息即可。插入solt为(Current Index+1800)%3600

优点:

  1. 无需轮询全部订单(全量io),效率高

  2. 时效性好,精确到秒

主动处理

被动处理的最大弊端就是需要不停轮询,且有一定延迟时间。
要做到让订单一到时间,主动发出信号进行处理。

利用redis key的自动过期机制,将订单id作为key写入redis,过期时间30分钟。
开启redis key过期提醒

redis.conf

notify-keyspace-events Ex

K:keyspace事件,事件以__keyspace@<db>__为前缀进行发布;         
E:keyevent事件,事件以__keyevent@<db>__为前缀进行发布;         
g:一般性的,非特定类型的命令,比如del,expire,rename等;        
$:字符串特定命令;         
l:列表特定命令;         
s:集合特定命令;         
h:哈希特定命令;         
z:有序集合特定命令;         
x:过期事件,当某个键过期并删除时会产生该事件;         
e:驱逐事件,当某个键因maxmemore策略而被删除时,产生该事件;         
A:g$lshzxe的别名,因此”AKE”意味着所有事件。
Scroll to Top