面试知识库
进阶

延迟任务方案对比#

一句话答案#

四种方案按推荐度:延迟 MQ(可靠简单)> Redis ZSET > 时间轮(进程内)> DB 轮询(兜底)。

核心要点
方案精度可靠性适用
延迟MQ秒~分通用(推荐)
Redis ZSET秒级量不大
时间轮ms级进程内
DB轮询分钟兜底方案
面试回答(2分钟版)

延迟任务有四种主流方案,按推荐程度排序。首选是延迟消息队列,比如RocketMQ原生支持延迟消息,可靠性高、使用简单,精度在秒到分钟级,适合大多数业务场景比如订单超时取消。第二是Redis ZSet方案,把任务ID作为member、触发时间戳作为score存入ZSet,后台线程定时用ZRANGEBYSCORE取出到期任务执行,精度秒级,适合数据量不大的场景。第三是时间轮,比如Netty的HashedWheelTimer,精度可以到毫秒级,性能极高,但它是单机内存方案,进程挂了任务就丢了,适合进程内的超时管理比如连接超时检测。第四是数据库轮询,定时扫描DB中状态为待执行且到期的记录,精度分钟级,大表扫描开销大,但胜在可靠简单,适合作为兜底方案。实际项目中通常以延迟MQ为主,DB轮询做兜底补偿。

追问与易错

追问方向:

  • “Redis ZSET 延迟任务怎么实现?”→ 将任务 ID 作为 member、触发时间戳作为 score 存入 ZSet,后台线程定时用 ZRANGEBYSCORE 取出到期任务(score <= now)执行,执行后 ZREM 删除;注意多消费者时用 Lua 保证取出和删除的原子性
  • “时间轮优缺点?”→ 优点是 O(1) 插入和触发、精度可达毫秒级、内存紧凑;缺点是单机内存方案进程挂了任务全丢、大量空槽浪费遍历时间(层级时间轮可优化)
  • “为什么推荐 MQ?”→ RocketMQ/RabbitMQ 的延迟消息有持久化和重试保障不会丢消息,使用简单只需发消息时设延迟级别,天然支持分布式多消费者,可靠性远高于 Redis 和时间轮方案

易错点:

  • ❌ 定时扫描 DB 性能好——大表扫描开销大
  • ❌ 时间轮适合所有场景——单机内存方案