需求场景:订单 30 分钟未支付自动关闭、定时提醒、重试退避。方案谱系:1)DB 轮询——扫表 SELECT WHERE execute_at <= now(),简单但时效差、压力大,只适合低频;2)JDK DelayQueue / ScheduledExecutor——单机内存方案,重启即失;3)Redis ZSet——score 存执行时间戳,轮询 zrangebyscore 取到期任务,轻量可用,精度和可靠性取决于轮询频率与消费确认设计;4)MQ 原生——RocketMQ 支持 18 个固定延迟级别(非任意时间,先存 SCHEDULE_TOPIC 再到期投递),RabbitMQ 靠 TTL + 死信队列或延迟插件;5)时间轮(HashedWheelTimer)——Netty/Kafka 内部方案。

时间轮原理:环形数组(一圈 tickDuration × wheelSize 覆盖一个时间跨度),每个槽挂任务链表,指针每 tick 前进一格,到期槽内任务执行或降级到下一层轮(层级时间轮类似钟表秒针分针)。插入和到期处理都接近 O(1),单机每秒可调度百万级任务。工程闭环:时间轮只解决内存调度,生产系统要加持久化(任务先落 DB/RocksDB,调度器只装近期任务)与高可用(多实例抢主或分片)。追问方向:为什么 Kafka 的延迟操作(延时拉取、事务超时)用时间轮而非每请求一个定时器、固定延迟级别 vs 任意延迟的取舍、海量定时任务(如亿级提醒)的分片调度架构。

(约 470 字)