Sunday面试指南

延迟队列怎么实现?定时扫描、时间轮和延迟消息怎么选?

🧑‍💻 面试官:延迟队列是不是设个定时器,到点执行就行?

🙋‍♂️ 我:任务少的时候可以,大一点就用时间轮或延迟消息。

🧑‍💻 面试官:进程重启以后,定时器里的任务还在吗?

🙋‍♂️ 我:那需要把任务保存下来。

🧑‍💻 面试官:到期事件发出时,用户刚好已经完成操作,你还会直接执行取消吗?

延迟队列负责「到期提醒」,业务负责「此刻还能不能做」。持久化与执行条件不能省略。

面试速答(60 秒版)

延迟队列让任务在指定时间以后变成可处理,常见方案有数据库定时扫描、内存时间轮和中间件延迟消息。

扫描易于结合持久化与查询,代价是周期和扫描负载;时间轮按时间槽组织大量定时任务,适合近似调度,但内存定时器本身不解决重启恢复;延迟消息把等待交给中间件,但要核对版本、精度、最长延迟和故障语义。

到期不等于业务一定马上完成,也不等于一定只执行一次。消费者还要检查当前状态,以幂等或条件更新处理重复与竞争,并监控到期后的实际等待时间。任务取消、改期和大量任务同时到期,也要提前设计。

延迟任务到期后仍需验证当前状态,再决定业务操作

知识点详解:到期、可消费和业务完成不是同一时刻

先把时间触发与业务决定拆开

假设一个预约需要在 15 分钟未确认后释放名额。延迟任务可以携带预约 ID,在到期后提醒处理程序检查。

但用户可能在第 14 分 59 秒完成确认;处理程序也可能因为积压到第 16 分钟才运行。因此不能收到事件就无条件释放。应读取当前状态,通过受保护的条件修改决定是否仍需处理。

重复事件也应得到同样的安全结果。延迟队列提供时机,不负责证明这个时刻的业务条件。

扫描、时间轮和延迟消息怎么选

数据库扫描可以用到期时间和状态建立合适索引,按批获取已到期任务。多实例需要明确认领或锁定,失败后能恢复,不能每个实例都对整表重复执行。

时间轮把任务按时间槽分组,指针随 tick 移动,到槽后检查。它用精度与组织方式换取大量定时任务的管理效率,但执行可能晚于计划时间,长耗时处理也不应堵住调度线程。

中间件延迟消息由 Broker 管等待,应用在可见后消费。它的时间范围、配置与消息类型依赖产品版本。不能把某个版本的固定延迟等级推广到所有 RocketMQ 版本。

TTL 加死信,不是万能精确定时

RabbitMQ 可以通过消息 TTL 和死信路由组合出延迟处理模式,但逐消息 TTL 会受到队头处理等边界影响。短 TTL 消息放在未到期长消息后面,不一定按它自己的到期时间立即进入死信路径。

因此混合延迟时,要检查所选队列类型与过期行为,而不是把 expiration 当作通用定时调度器。死信转发的可靠性也应按实际配置验证。

对精度较宽松、时间桶固定的任务,可以评估相应设计;需要更精细调度时,选择契合的方案,不靠缩短一个数字宣称解决。

重启、改期和集中到期怎样收场

任务要有稳定 ID、计划时间、当前版本和处理状态。改期后,旧事件仍可能到达,可以根据版本或状态识别并忽略,而不必假设旧消息已经物理撤回。

内存时间轮需要持久化来源与重建策略。多节点负责调度时,要设计认领、租约或分片,避免全部节点重复恢复相同任务。

最后监控从计划时间到可见、到开始、到完成的延迟。假设十万任务都定在整点,Broker 和业务端也需要逐个处理;调度不是一条绝对准时的魔法承诺。

本题机制参考:Netty HashedWheelTimer、RocketMQ Delay Message、RabbitMQ TTL、RabbitMQ Dead Letter Exchanges。

时间轮按时间槽和 tick 检查任务,持久化恢复另行设计

面试官继续追问

延迟消息能保证毫秒级业务完成吗?

不能。可见时间、网络、消费积压与处理耗时都会影响结果,精度必须按实际产品与负载验证。

取消任务必须删除延迟消息吗?

不一定。可将业务状态或任务版本标记为已取消,消费时验证后无操作;是否提供消息撤回能力则按实际版本核对。

时间轮任务不会丢吗?

内存结构本身不提供持久性。需保存任务并安排重启重建与重复处理防护。

面试速记卡

  • 到期提醒,不等于当前业务条件成立。
  • 扫描重持久化认领;时间轮重近似调度;延迟消息看产品限制。
  • TTL+死信需检查队头与转发行为。
  • 重复、取消、改期用状态或版本保护。
  • 分别测可见、开始与完成时间。

公司面试真题

这道题暂未收录可核验的公司真题来源。你可以先阅读本文解析,或浏览已收录的公司面试真题。

浏览公司面试真题 →
简历汪永久免费在线制作简历,模板直接套用、导出无水印,永久免费、下载免费,不需要付费解锁任何功能。去写简历