3. 调度任务元数据模型:核心表结构设计

调度平台的核心是围绕任务的生命周期构建元数据模型。一个健壮的模型需要覆盖任务定义、任务实例、执行历史与依赖关系四个维度。本节从关系型数据库视角给出表结构设计,并解释每个字段在索引选择与缓存策略中的角色。

3.1 任务定义表(task_definition)

任务定义是用户提交的“蓝图”,包含调度规则、执行命令、超时与重试策略。该表是查询最频繁的静态元数据,适合全量缓存。

字段名类型说明索引建议
idBIGINT PK自增主键聚簇索引
nameVARCHAR(128)任务名称,业务唯一唯一索引
cron_exprVARCHAR(64)Cron 表达式—
timezoneVARCHAR(32)时区,默认 UTC—
executor_typeTINYINTShell / HTTP / Docker—
executor_configTEXTJSON 格式的执行参数—
timeout_secINT超时秒数,0 表示不限制—
retry_timesTINYINT失败重试次数—
retry_intervalINT重试间隔(秒)—
statusTINYINT0=禁用, 1=启用普通索引
created_atDATETIME创建时间—
updated_atDATETIME最后修改时间—
缓存策略: 任务定义表数据量通常小于 10 万行,变化频率低。推荐使用 Redis Hash 全量缓存,key 为 task:def:{id},TTL 设为 3600 秒。当 updated_at 变更时主动失效缓存。

3.2 任务实例表(task_instance)

每次调度触发生成一条实例记录。实例表是写入与查询压力最大的表,也是索引设计的关键战场。

字段名类型说明索引建议
idBIGINT PK自增主键聚簇索引
task_def_idBIGINT关联 task_definition.id联合索引 (task_def_id, scheduled_time)
scheduled_timeDATETIME计划执行时间同上
actual_timeDATETIME实际开始时间—
statusTINYINT0=等待, 1=运行, 2=成功, 3=失败, 4=超时普通索引
node_idVARCHAR(64)执行节点标识普通索引
trigger_typeTINYINT0=定时, 1=手动, 2=依赖触发—
retry_countTINYINT当前已重试次数—
created_atDATETIME实例创建时间—
索引选择避坑: 不要单独对 scheduled_time 建索引。调度平台最常见的查询是“某任务在时间范围内的实例”,联合索引 (task_def_id, scheduled_time) 能同时过滤任务和时间,避免回表。单独对 status 建索引在数据量超过 500 万行时效果急剧下降,建议配合分区表使用。

3.3 执行历史表(execution_history)

执行历史记录每次运行的详细日志、退出码与资源消耗。该表只追加、不更新,适合按时间分区存储。

字段名类型说明索引建议
idBIGINT PK自增主键聚簇索引
instance_idBIGINT关联 task_instance.id唯一索引
exit_codeINT进程退出码—
stdout_logMEDIUMTEXT标准输出—
stderr_logMEDIUMTEXT错误输出—
cpu_usageDECIMAL(5,2)CPU 使用率百分比—
mem_mbINT内存使用 MB—
duration_msINT执行耗时(毫秒)—
recorded_atDATETIME记录时间普通索引(用于清理)
缓存策略: 执行历史不缓存全量数据。仅对最近 100 条实例的 duration_ms 做聚合缓存,用于实时监控面板。历史日志建议直接走对象存储(S3/MinIO),数据库只保留元数据指针。

3.4 依赖关系表(task_dependency)

DAG 调度场景下,任务之间的上下游依赖通过该表表达。依赖关系是调度引擎计算可执行性的核心输入。

字段名类型说明索引建议
idBIGINT PK自增主键聚簇索引
upstream_def_idBIGINT上游任务定义 ID联合索引 (upstream_def_id, downstream_def_id)
downstream_def_idBIGINT下游任务定义 ID同上
dependency_typeTINYINT0=成功依赖, 1=完成依赖, 2=输出匹配—
output_matchVARCHAR(256)输出匹配正则(仅 type=2 时有效)—
created_atDATETIME创建时间—
缓存策略: 依赖关系在任务定义发布后极少变更。使用 Redis Set 缓存每个上游的下游列表,key 为 task:deps:down:{upstream_def_id}。调度引擎在触发上游完成事件时,直接读取缓存中的下游列表,避免每次查询数据库。

3.5 核心表关系与数据流

下图展示四张表之间的关联关系以及数据在调度周期中的流转路径。

调度任务元数据模型关系图 调度任务元数据模型关系图 task_definition 任务定义(蓝图) task_instance 任务实例(每次调度) execution_history 执行历史(日志+指标) task_dependency 依赖关系(DAG 边) 1:N 1:1 上游 下游 说明: task_definition 与 task_instance 是 1:N 关系;task_instance 与 execution_history 是 1:1 关系; task_dependency 通过 upstream_def_id / downstream_def_id 关联 task_definition,构成 DAG 有向边。

3.6 索引选择与缓存策略总结

基于上述表结构,下表汇总索引与缓存的推荐配置,供架构设计时直接参考。

表核心查询模式推荐索引缓存策略
task_definition按 name 查询;按 status 列表name 唯一索引;status 普通索引Redis Hash 全量缓存,TTL 3600s
task_instance按 task_def_id + 时间范围查询;按 status 过滤待执行实例(task_def_id, scheduled_time) 联合索引;status 普通索引仅缓存最近 1000 条活跃实例,使用 ZSET 按 scheduled_time 排序
execution_history按 instance_id 查询详情;按 recorded_at 清理过期数据instance_id 唯一索引;recorded_at 普通索引不缓存全量;仅聚合 duration_ms 到 Redis 计数器
task_dependency按上游 ID 查询所有下游;按下游 ID 查询所有上游(upstream_def_id, downstream_def_id) 联合索引Redis Set 缓存下游列表,key 为 task:deps:down:{upstream_def_id}
架构决策要点:
  • 任务定义与依赖关系属于“读多写极少”数据,优先使用本地缓存 + Redis 二级缓存,减少数据库读压力。
  • 任务实例表是写入瓶颈,建议按 scheduled_time 做月度分区,避免单表过大导致索引深度增加。
  • 执行历史表超过 1000 万行后,将日志字段迁移到对象存储,数据库只保留元数据与指针。
  • 依赖关系缓存必须在任务定义发布或更新时主动失效,避免调度引擎读到脏数据导致 DAG 死锁。