实现功能:超时未支付的订单自动关闭

245 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 6 天,点击查看活动详情

定时任务

启动cron定时任务扫表,将超时订单状态设置为失败

基于消息队列的延迟队列

用户下单,向mq投放消息到交换机,设置过期时间为30min,消息到a队列,a队列绑定私信交换机,不设置aa队列的消费者。超过30min后,过期消息投递到死信交换机,死信队列,由死信消费者消费,订单未支付则取消。

使用rabbitmq的死信交换机(exchange)和消息的存活时间(ttl)

死信交换机就是普通的交换机,存放过期信息:

  • 消息被consumer拒收,且设置不会再次放入队列中被其他消费者使用
  • 消息队列的消息数量超过最大队列长度
  • 消息在队列的存活时间超过ttl

缺点:

  • 第一条消息成为死信前,后面的消息即使过期也不会投递到死信

时间轮算法

环形队列,环上每个slot是一个任务列表。根据过期时间,计算订单所在时间轮的cycle和slot。环的index不停移动,移动到新的slot,删除对应的task

redis

基于notify-keyspace-events事件通知

notify-keyspace-events,配置消息监听,

用户下单生成令牌有效期30min,存入redis。redis.set(orderToken,orderID),并将id存储入库。redis客户端监听,过期后获取orderID,去数据库查询订单,没有支付则关闭订单。

缺点

  • 键空间通知采用发送即忘(fire and foget),订阅事件的客户端会丢失所有在断线期间分发给它的事件
  • 定时任务离线扫描并删除部分过期键,访问键时惰性检查是否过期并删除过期键。不保证在设定的过期时间内立即删除并发送过期通知。

基于redis的延迟队列

使用zset,订单超时时间戳和订单号分别设置为score和member,通过score扫描最小元素判断是否超时。

高并发条件下多消费者可能取到同一个订单号,需要加入分布式锁实现幂等性,降低性能。

参考

blog.csdn.net/zhangshengq…

juejin.cn/post/699608…

juejin.cn/post/710835…