在电商、支付等领域,往往会有这样的场景,用户下单后放弃支付了,那这笔订单会在指定的时间段后进行关闭操作。
细心的你一定发现了像某宝、某东都有这样的逻辑,而且时间很准确,误差在 1s 内,那他们是怎么实现的呢?
一般实现的方法有几种:
-
使用 RocketMQ、RabbitMQ、Pulsar 等消息队列的延时投递功能
-
使用 Redisson 提供的 DelayedQueue
有一些方案虽然广为流传但存在着致命缺陷,不要用来实现延时任务:
-
使用 Redis 的过期监听
-
使用 RabbitMQ 的死信队列
-
使用非持久化的时间轮
Redis 过期监听
在 Redis 官方手册的 keyspace-notifications: timing-of-expired-events 中明确指出:
Basically expired events are generated when the Redis server deletes the key and not when the time to live theoretically reaches the value of zero
Redis 自动过期的实现方式是:定时任务离线扫描并删除部分过期键;在访问键时惰性检查是否过期并删除过期键。
Redis 从未保证会在设定的过期时间立即删除并发送过期通知。实际上,过期通知晚于设定的过期时间数分钟的情况也比较常见。