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 小时排查时间。
你想想看,一个任务跑半年,配置只改一两次。但如果一开始配错了,每次出问题都要查半天。值不值?
嗯,这一节就到这里。记住我说的:任务定义要清晰、参数要灵活、资源要合理、依赖要准确、优先级要区分、超时要留余量。把这六点做到位,你的调度系统就稳了一半。