调度平台核心架构:任务生命周期、状态流转模型、调度器与执行器交互流程

调度平台的核心在于将一次业务请求转化为可追踪、可恢复、可并行的任务执行单元。理解任务从创建到终结的完整生命周期、状态之间的合法转换路径,以及调度器与执行器之间的通信协议,是后续利用 Redis 缓存优化索引命中率的前提。

2.1 任务生命周期与状态定义

一个标准的调度任务通常经历以下五个阶段:创建 → 等待 → 调度 → 执行 → 终结。每个阶段对应一组明确的状态值,平台通过状态机保证状态流转的原子性与一致性。

阶段 状态值 说明 触发动作
创建 INIT 任务实例已持久化,尚未进入调度队列 API 请求 / 定时触发
等待 QUEUED 任务已入调度队列,等待分配执行器 调度器轮询或事件推送
调度 DISPATCHED 调度器已选定执行器,发送执行指令 调度器下发 RPC 或 MQ 消息
执行 RUNNING 执行器正在处理任务逻辑 执行器接收指令并启动线程
终结 SUCCESS / FAILED / TIMEOUT 任务执行完毕,结果已回写 执行器上报结果 / 超时检测
设计要点:状态值必须使用枚举或整型常量,禁止使用字符串硬编码。推荐在数据库与缓存中同时存储状态,缓存用于快速过滤,数据库用于最终一致性保证。

2.2 状态流转模型

状态流转必须遵循有向无环图(DAG)规则,不允许非法跳转。以下为调度平台的标准状态机模型:

调度平台任务状态机流转图 入队列 分配执行器 执行器确认 正常完成 业务异常 超时检测 INIT QUEUED DISPATCHED RUNNING SUCCESS FAILED TIMEOUT 状态机规则:不允许从 QUEUED 直接跳转到 RUNNING,必须经过 DISPATCHED 阶段
状态机校验规则:
  • 只有 QUEUED 状态的任务可以被调度器取出并置为 DISPATCHED。
  • 执行器收到指令后,必须将任务状态从 DISPATCHED 更新为 RUNNING,否则调度器会触发重试或超时回收。
  • 终结状态(SUCCESS / FAILED / TIMEOUT)为终态,不可再流转回任何中间状态。
  • 超时检测由调度器侧的心跳监控线程触发,执行器侧不主动产生 TIMEOUT 状态。

2.3 调度器与执行器交互流程

调度器(Scheduler)与执行器(Executor)是物理分离的组件,通过中间件(Redis / MQ / RPC)进行异步通信。一次完整的任务调度交互包含以下 6 个步骤:

  1. 任务提交:上游系统通过 API 将任务写入数据库,状态为 INIT,同时将任务 ID 推入调度队列(Redis List 或 Kafka Topic)。
  2. 调度器拉取:调度器轮询或监听队列,获取待调度任务 ID,查询数据库获取完整任务元数据。
  3. 执行器选择:调度器根据路由策略(轮询、一致性哈希、最小负载)选定目标执行器,将任务状态更新为 DISPATCHED。
  4. 指令下发:调度器将执行指令(任务 ID、参数、超时时间)写入执行器对应的待处理队列(Redis Stream 或 MQ Queue)。
  5. 执行器消费:执行器从队列中获取指令,更新任务状态为 RUNNING,启动工作线程执行任务逻辑。
  6. 结果回传:执行器完成任务后,将结果(SUCCESS / FAILED + 输出数据)写入回调队列,调度器消费后更新数据库状态。
调度器与执行器交互时序图 调度器 Redis/MQ 执行器 ① 推送任务ID到调度队列 ② 轮询/监听获取任务ID ③ 查询任务元数据 ④ 写入执行器待处理队列 ⑤ 消费指令,启动执行 ⑥ 写入回调结果队列 ⑦ 消费回调,更新DB状态 交互核心:调度器不直接调用执行器接口,全部通过中间件解耦,保证高可用与异步削峰

2.4 关键设计原则

原则 说明 对索引命中率的影响
状态驱动 所有调度行为由状态变化触发,而非定时扫描全表 减少无效查询,缓存只需索引活跃状态的任务
异步解耦 调度器与执行器通过队列通信,不共享内存 缓存层可独立优化,不受执行器负载波动影响
幂等回传 执行器结果回传支持重复消费,调度器侧做去重 缓存状态更新可批量合并,减少写放大
超时兜底 调度器维护独立超时检测线程,不依赖执行器主动上报 缓存中过期状态可被及时清理,避免脏数据占用索引
常见误区:很多团队在设计初期将调度器与执行器合并部署,或使用数据库轮询代替队列驱动。这种做法在任务量超过 1000 TPS 时会导致数据库连接池耗尽、索引频繁锁竞争,最终使 Redis 缓存层也因回源查询过多而命中率骤降。务必从架构层面将调度器与执行器物理分离。