在电商、支付等领域,往往会有这样的场景,用户下单后放弃支付了,那这笔订单会在指定的时间段后进行关闭操作,细心的你一定发现了像某宝、某东都有这样的逻辑,而且时间很准确,误差在1s内;那他们是怎么实现的呢?
一般实现的方法有几种:
- 使用 rocketmq、rabbitmq、pulsar 等消息队列的延时投递功能
- 使用 redisson 提供的 DelayedQueue
- 使用 redis 的过期监听
- 使用 rabbitmq 的死信队列
- 使用非持久化的时间轮
Basically expired events are generated when the Redis server deletes the key and not when the time to live theoretically reaches the value of zeroredis 自动过期的实现方式是:定时任务离线扫描并删除部分过期键;在访问键时惰性检查是否过期并删除过期键 。redis 从未保证会在设定的过期时间立即删除并发送过期通知 。实际上,过期通知晚于设定的过期时间数分钟的情况也比较常见 。
此外键空间通知采用的是发送即忘(fire and forget)策略,并不像消息队列一样保证送达 。当订阅事件的客户端会丢失所有在断线期间所有分发给它的事件 。
这是一种比定时扫描数据库更 “LOW” 的解决方案,请不要使用 。
有另一位大佬做了测试 请勿过度依赖Redis的过期监听, 有兴趣的朋友可以自行查阅 。
rabbitmq 死信#死信(Dead Letter) 是 rabbitmq 提供的一种机制 。当一条消息满足下列条件之一那么它会成为死信:
- 消息被否定确认(如channel.basicNack) 并且此时requeue 属性被设置为false 。
- 消息在队列的存活时间超过设置的TTL时间
- 消息队列的消息数量已经超过最大队列长度
在 rabbitmq 中创建死信队列的操作流程大概是:
- 创建一个交换机作为死信交换机
- 在业务队列中配置 x-dead-letter-exchange 和 x-dead-letter-routing-key,将第一步的交换机设为业务队列的死信交换机
- 在死信交换机上创建队列,并监听此队列
为了解决这个问题,rabbit 官方推出了延迟投递插件
rabbitmq-delayed-message-exchange,推荐使用官方插件来做延时消息 。
这里说点题外话,使用 redis 过期监听或者 rabbitmq 死信队列做延时任务都是以设计者预想之外的方式使用中间件,这种出其不意必自毙的行为通常会存在某些隐患,比如缺乏一致性和可靠性保证,吞吐量较低、资源泄漏等 。比较出名的一个事例是很多人使用 redis 的 list 作为消息队列,以致于最后作者看不下去写了 disque 并最后演变为 redis stream 。工作中还是尽量不要滥用中间件,用专业的组件做专业的事时间轮#时间轮是一种很优秀的定时任务的数据结构,然而绝大多数时间轮实现是纯内存没有持久化的 。运行时间轮的进程崩溃之后其中所有的任务都会灰飞烟灭,所以奉劝各位勇士谨慎使用 。
redisson delayqueue#redisson delayqueue 是一种基于 redis zset 结构的延时队列实现 。delayqueue 中有一个名为 timeoutSetName 的有序集合,其中元素的 score 为投递时间戳 。delayqueue 会定时使用 zrangebyscore 扫描已到投递时间的消息,然后把它们移动到就绪消息列表中 。
delayqueue 保证 redis 不崩溃的情况下不会丢失消息,在没有更好的解决方案时不妨一试 。
在数据库索引设计良好的情况下,定时扫描数据库中未完成的订单产生的开销并没有想象中那么大 。在使用 redisson delayqueue 等定时任务中间件时可以同时使用扫描数据库的方法作为补偿机制,避免中间件故障造成任务丢失 。
结论#
- 首先推荐使用 rocketmq、pulsar 等拥有定时投递功能的消息队列 。
- 在不方便获得专业消息队列时可以考虑使用 redisson delayqueue 等基于 redis 的延时队列方案,但要为 redis 崩溃等情况设计补偿保护机制 。
推荐阅读
- GO编程:小技巧
- 电脑word如何删除空白页面
- 使用电饭锅的注意事项 使用电饭锅需要注意些什么
- 北京疾控建议暑假不出国旅行-
- 五招告别大圆脸,懒人瘦脸小技巧! 建议码住,反复练习!
- 选电脑桌,建议大家“五不买”,这是过来人的经验
- 专家建议卧室内不要摆放,房间不能摆放什么东西-
- 十大减肥秘方轻松吃出苗条
- 无性婚姻必须放弃,无性无爱的婚姻要不要继续-
- 夏天要擦面霜吗-夏天要涂面霜吗-夏天要不要涂面霜