使用数据库+延时队列实现高精度长延时任务
在系统设计中,长时间延时任务(如几天、几个月后的任务)是一个常见需求。比如电商平台的“订单超时自动确认收货”功能,银行系统中的“定期转账”,或者社交平台的“消息延迟发送”。这些任务通常具有以下特点:
- 延时跨度较长,从几天到几个月不等。
- 需要在到期时刻实现精确触发,以秒级为最佳。
- 不允许任务丢失,数据需要可靠的持久化。
直接用延时队列(如 Redis、RabbitMQ)实现长延时任务面临挑战,消息队列一般不适合持久化保存几个月的数据;而仅依赖数据库轮询也难以实现秒级触发精度。针对这种需求,我们可以结合数据库+短期延时队列的方案,以达到可靠的持久化存储和精确触发的平衡。
方案介绍
整体思路:将延时时间较长的任务先存储在数据库中,然后通过定时任务周期性地检查数据库中即将到期的任务,提前一段时间(如24小时或1小时)将这些即将到期的任务加入到短期的延时队列中(如 Redis Zset 或 RabbitMQ 的延时队列)。通过短期延时队列实现秒级精度的触发。
为什么要结合数据库和延时队列?
- 数据库:适合持久化存储任务,确保任务不会因为系统故障而丢失。数据库查询也支持复杂的筛选条件,可以方便地批量筛选即将到期的任务。
- 短期延时队列:可以提供高精度的触发。Redis Zset 或 RabbitMQ 延时队列等可以让任务到期后立即被消费和处理,达到秒级的触发精度。
使用场景
- 订单超时自动处理:在电商平台上,用户下单后有一段时间可以申请退款或退货。如果在设定的时间内未操作,系统会自动确认收货。
- 自动续费和账单处理:在 SaaS 平台或订阅系统中,可能需要在服务到期时自动续费或发送账单提醒。
- 社交或消息延时功能:在社交平台上,有时会有特定的消息、提醒需要在特定的时间点自动发送,比如生日祝福、定期提醒等。
方案实现步骤
-
数据库设计
- 创建一个“延时任务表”(例如
delayed_tasks
),用于存储所有延时任务。字段设计如下:CREATE TABLE delayed_tasks ( task_id BIGINT PRIMARY KEY AUTO_INCREMENT, task_name VARCHAR(255) NOT
- 创建一个“延时任务表”(例如