当前位置: 首页 > news >正文

分布式延时任务方案:Redis ZSet + 时间轮 (Time Wheel)

1. 方案背景

在电商等高并发场景下,订单超时取消、预定提醒等延时任务需要满足以下核心需求:

  • 高可靠性:任务不能丢失,即使服务器宕机也需能恢复。

  • 高精度:触发时间偏差应在毫秒级或秒级。

  • 高性能:避免大批量任务直接轮询数据库导致的 I/O 瓶颈。

  • 分布式扩展:支持多实例部署,任务不重复执行。

2. 核心架构设计

本方案采用“二级调度”思想:将 Redis 作为全局持久化任务池,将本地时间轮作为高精度触发器。

2.1 数据结构设计

  • 总任务池 (order:timeout:all)

    • 类型:ZSet

    • Score:任务执行的绝对时间戳(如15:30:0015:30:0015:30:00)。

    • Value:任务唯一标识(如orderId)。

  • 实例私有桶 (order:timeout:processing:{instanceId})

    • 类型:ZSet

    • 作用:记录该实例已取走但尚未完成的任务,用于宕机恢复。

  • 心跳键 (instance:heartbeat:{instanceId})

    • 类型:String(带过期时间)

    • 作用:标识实例存活状态。


3. 详细工作流程

第一阶段:任务入库 (Producer)

  1. 业务系统创建订单,计算过期时间。

  2. 执行ZADD order:timeout:all <timestamp> <orderId>

第二阶段:预取并加载 (Loader)

  1. 每个服务实例启动一个定时线程(如每 1 分钟执行一次)。

  2. 通过Lua 脚本原子性地从“总池”中捞取未来 60s 内到期的任务,转移至“私有桶”。

  3. 将任务加载至本地内存的HashedWheelTimer(时间轮)。

第三阶段:精准触发 (Execution)

  1. 本地时间轮转动到预定刻度,触发回调函数。

  2. 执行业务逻辑:调用支付网关查询状态、修改订单状态、回滚库存。

  3. 确认完成:业务成功后,从 Redis “私有桶”中删除该任务。


4. 关键 Lua 脚本

4.1 预取脚本 (fetch_to_private.lua)

保证多个实例竞争时,任务只会被一个实例取走并转移。

Lua

-- KEYS[1]: 总池 (all), KEYS[2]: 私有桶 (processing) -- ARGV[1]: 当前时间, ARGV[2]: 预取截止时间 (now + 60s) local orders = redis.call('ZRANGEBYSCORE', KEYS[1], ARGV[1], ARGV[2]) if #orders > 0 then for i, order_id in ipairs(orders) do redis.call('ZREM', KEYS[1], order_id) redis.call('ZADD', KEYS[2], ARGV[2], order_id) end end return orders

4.2 确认删除脚本 (complete_task.lua)

Lua

-- KEYS[1]: 私有桶 -- ARGV[1]: 订单 ID return redis.call('ZREM', KEYS[1], ARGV[1])

5. 容错与恢复机制 (Fault Tolerance)

5.1 解决“易失性”

由于任务在执行前已进入 Redis “私有桶”,即使服务器内存的时间轮因宕机丢失,任务数据依然在 Redis 中。

5.2 故障清理 (Watchdog)

启动一个独立的监控任务(或利用现有实例的定时任务):

  1. 遍历所有私有桶order:timeout:processing:*

  2. 检查对应的实例心跳instance:heartbeat:{instanceId}

  3. 恢复逻辑:如果发现心跳消失,且私有桶中有残留任务,则说明该实例已宕机。将私有桶中的任务重新ZADD回总池。


6. 方案对比总结

维度纯 DB 轮询纯 Redis ZSet纯时间轮本方案 (ZSet+时间轮)
精度低 (分钟级)中 (秒级)极高 (毫秒级)极高 (毫秒级)
DB/Redis 压力极高低 (按需预取)
可靠性低 (重启即丢)高 (双重备份)
实现难度简单较高

7. 最佳实践建议

  • 实例 ID 选择:在 K8s 环境下建议使用HOSTNAME(Pod Name),在虚拟机环境下使用IP:Port

  • 任务幂等:取消订单逻辑必须实现幂等,防止在极端恢复场景下重复触发。

  • 时钟同步:分布式环境下,请确保所有实例节点的 NTP 时间同步,以防预取区间出现偏差。


希望这份文档能帮助你清晰地整理方案。如果你需要针对特定的开发框架(如 Spring Boot 或 Quarkus)提供更详细的代码脚手架,我可以继续为你提供支持。

http://www.jsqmd.com/news/736461/

相关文章:

  • 04_observer
  • 抖音无水印下载终极指南:如何一键保存高清视频、音乐和直播
  • DAC使用入门:核心参数与应用详解
  • DSP处理器选型与性能优化实战指南
  • 2026年3月环氧彩砂自流平厂商推荐,艺术涂料/防水涂料/涂料OEM/改色漆/臻瓷水釉,环氧彩砂自流平实力厂家找哪家 - 品牌推荐师
  • 立体视觉与StereoWorld模型:原理、应用与优化
  • Silvaco TonyPlot保姆级教程:从仿真log文件到精美数据图的完整导出与可视化流程
  • 魔兽争霸3兼容性问题终极解决方案:WarcraftHelper使用完全指南
  • EGPRS与8PSK调制技术:原理、挑战与工程实践
  • LTE-Advanced载波聚合技术原理与测试实践
  • 使用curl命令直接测试Taotoken聊天补全接口的连通性与响应
  • CUDA矩阵乘法优化:从基础实现到Triton高级技巧
  • SwiftData智能体模式:为数据模型注入可插拔的业务技能
  • 哔哩下载姬DownKyi:5步掌握B站视频下载的艺术
  • Java基本语法小白入门级
  • 别再插拔USB了!用Arduino IDE给ESP8266无线刷固件(OTA)的保姆级避坑指南
  • 嵌入式C语言扩展:DSP与嵌入式处理器的性能优化实践
  • AI写论文不用愁!4款AI论文写作神器,全方位提升论文质量!
  • 如何为3D打印文件快速生成高质量缩略图
  • 别再只盯着mAP了!用YOLOv8和pycocotools计算mAP时,这两个关键差异点你注意到了吗?
  • 怀民未寝,苦学HTML——关系选择器及表格表单中所涉及的属性
  • Windows 11安卓子系统终极指南:2025年免费在电脑运行Android应用的完整教程
  • 从AIB到UCIe:手把手拆解Chiplet互连的“心脏”与“血管”
  • 2026清香白酒贴牌工艺与合规指南:泸州酒贴牌代加工、浓香白酒贴牌、白酒 OEM 贴牌、白酒代理加盟、白酒加盟代理选择指南 - 优质品牌商家
  • 从GraspNet-1Billion数据集到真实场景:聊聊机器人抓取落地中的那些‘坑’(以桌面小物体为例)
  • D435i相机标定与VINS/ORB-SLAM3实战:如何正确配置IMU与相机外参(estimate_extrinsic=1详解)
  • 2026坦克军事模型定制厂家专业榜:军事模型坦克厂家/军事模型定做/军事模型租赁/动态坦克模型厂家/卫星模型租赁/选择指南 - 优质品牌商家
  • 026 PID控制器的调试技巧:示波器与串口绘图
  • Ultimaker Cura:3D打印新手必备的终极切片软件完全指南
  • 2026学校ERP:数字化校园管理平台、新生报到一站式解决方案、智慧校园一体化管理平台解决方案、智慧校园综合管理平台选择指南 - 优质品牌商家