3. 任务创建与配置:把调度需求翻译成机器能懂的语言

说实话,任务创建这一步,看着简单,其实坑最多。我见过太多团队,代码写得漂亮,结果在任务配置上翻车——依赖写错导致死循环、超时设得太短半夜告警轰炸、资源声明不足任务跑着跑着就 OOM 了。

这一节,我就把这些年踩过的坑、总结的经验,掰开了跟你聊聊。

3.1 任务定义:给任务一个「身份证」

每个调度任务,首先得有个唯一标识。我习惯用 任务名称 + 命名空间 的组合。比如 ods.order_daily_sync,一看就知道是 ODS 层、订单日增量同步。

核心字段清单

  • task_id:全局唯一,建议用 UUID 或 雪花ID
  • task_name:人类可读,体现业务含义
  • namespace:环境隔离(dev/staging/prod)
  • owner:负责人,告警直接找人
  • description:一句话说清楚这个任务干嘛的

我曾经接手过一个项目,任务名全是 task_001、task_002 这种。你想想看,出问题的时候,光查这个任务是什么就得花半小时。后来我强制要求:任务名必须包含数据层级 + 表名 + 操作类型。

3.2 参数配置:灵活,但别滥用

参数配置是任务灵活性的关键。我一般把参数分成三类:

参数类型 示例 说明
静态参数 db_url=jdbc:mysql://... 任务创建时固定,几乎不改
动态参数 dt={{ds}} 运行时由调度系统注入,比如日期
运行时参数 --repartition=10 每次触发可覆盖,用于调优

我的习惯:动态参数用 {{ }} 模板语法,调度系统自动替换。比如 dt={{ds_nodash}} 会变成 20250321。这样重跑历史数据时,改个日期就行,不用改任务定义。

嗯,这里要注意:不要把敏感信息写在参数里。密码、密钥这些,应该走专门的密钥管理服务,任务里只引用变量名。

3.3 资源声明:别让任务「饿死」或「撑死」

资源声明,说白了就是告诉调度系统:我这个任务需要多少 CPU、内存、磁盘。

我见过最典型的翻车案例:一个 Spark 任务,默认配了 2G 内存,结果数据量一涨就 OOM。运维半夜爬起来加资源,第二天又被老板骂。

避坑指南:我曾经在某个金融项目里,把所有任务都配了「最大资源」。结果集群资源被占满,小任务排队等半天。后来改成按数据量级动态申请资源,才解决问题。

资源声明的几个关键点:

  • CPU:计算密集型给多核,IO 密集型给少核
  • 内存:留 20% 余量给 JVM 或系统开销
  • 磁盘:临时数据、日志、shuffle 都要考虑
  • GPU:如果有,单独声明,别跟 CPU 任务混跑
# 一个合理的资源声明示例
resources:
  cpu: 4
  memory: 8Gi
  disk: 20Gi
  gpu: 0
  priority: medium

3.4 依赖声明:画清楚任务的「上下游关系图」

依赖声明是调度系统最核心的能力之一。你想想看,一个数据 pipeline 可能有几十个任务,A 跑完才能跑 B,B 和 C 都跑完才能跑 D。依赖写错了,整个链路就乱了。

我一般把依赖分成两种:

  • 硬依赖:上游失败,下游必须等待或跳过
  • 软依赖:上游失败,下游可以继续,但数据可能不完整

依赖声明示例

dependencies:
  - task: ods.order_raw_ingest
    type: hard
    timeout: 30m
  - task: dim.date_dim
    type: soft
    timeout: 10m

我曾经踩过一个坑:两个任务互相依赖,形成了环。调度系统直接死锁,所有任务卡住不动。后来我加了个 依赖环检测,创建任务时就校验,有环直接拒绝。

3.5 优先级设置:给任务排个「插队顺序」

资源有限的时候,谁先跑谁后跑,就得靠优先级了。我习惯用 1-10 的数值:

优先级 适用场景 说明
1-3 离线报表、历史数据回刷 可以等,不着急
4-6 日常 ETL、数据同步 正常优先级
7-9 实时看板、核心业务 优先分配资源
10 故障恢复、紧急修复 插队,其他任务让路

我的建议:别把所有任务都设成高优先级。那样等于没有优先级。我一般默认 5,只有真正紧急的任务才调高。

3.6 超时策略:给任务上个「闹钟」

任务跑太久,要么是数据量异常,要么是代码有 bug。超时策略就是防止任务「死循环」把集群拖垮。

我一般设三个超时层级:

  • task_timeout:整个任务最长执行时间
  • retry_timeout:单次重试的最长时间
  • dag_timeout:整个 DAG 的最长执行时间
# 超时策略配置
timeout:
  task_timeout: 60m
  retry_timeout: 30m
  dag_timeout: 240m
  on_timeout: kill  # kill | alert | skip

避坑指南:我曾经设过一个 5 分钟的超时,结果某个任务正常情况就要跑 6 分钟。每次都被 kill,然后重试,再 kill,循环了 3 次才失败。后来我改成 超时时间 = 历史平均执行时间 × 2,才稳定下来。

3.7 知识体系总览

下面这张图,把任务创建与配置的核心要素串起来了。你可以把它当成一个检查清单,每次创建任务时对照着看。

任务创建与配置核心要素 任务定义 参数配置 资源声明 依赖声明 优先级设置 超时策略 命名规范 创建任务时的检查清单 ✅ 任务名是否遵循命名规范? ✅ 参数是否区分静态/动态/运行时? ✅ 资源声明是否留有余量? ✅ 依赖关系是否有环? ✅ 优先级是否合理? ✅ 超时时间是否基于历史数据? ✅ 敏感信息是否已脱敏? ✅ 负责人是否填写正确?

3.8 小结

任务创建与配置,看着是体力活,其实每个字段背后都有门道。我个人习惯是:创建时多花 10 分钟想清楚,后面能省 10 小时排查时间。

你想想看,一个任务跑半年,配置只改一两次。但如果一开始配错了,每次出问题都要查半天。值不值?

嗯,这一节就到这里。记住我说的:任务定义要清晰、参数要灵活、资源要合理、依赖要准确、优先级要区分、超时要留余量。把这六点做到位,你的调度系统就稳了一半。