并发控制要分层做
调度并发需要分层控制:集群层面的总并行度、单个 DAG 的并发上限、任务池(pool)的槽位数,以及 worker 上的执行槽。这几层缺一不可:只限 DAG 而不限资源池,多个 DAG 仍会把下游数据库同时压垮;只管资源池而不看 DAG 并发,一个 DAG 自己就能占满全部槽位。
基本信息
| DAG 级 | max_active_runs 控制同时运行的 DagRun 数,max_active_tasks 控制任务并行 |
|---|---|
| 任务池 | pool 加 slots,限制同类任务同时运行的数量 |
| 执行侧 | executor 的并发槽位决定同时执行的上限 |
| 实践要点 | 写库、调接口这类有限资源单独建池,保护下游 |
典型使用场景
- 数仓写入任务:单独建池,避免批量作业同时打满数据库连接
- 外部接口调用:限制并发,防止触发对方限流与封禁
- 大内存任务:限制同机并发数,防止内存告急
- 多团队共享调度器:按团队配额分池,避免互相抢占
- 大促补数:临时调整池大小,但要同步评估下游容量
池与并发配置
池与并发配置
# 建池并设置槽位:dw_etl 池最多 4 个并发槽
airflow pools set dw_etl 4 "数仓写入任务池"
airflow pools list
# 在任务里指定池与占用槽位数
# PythonOperator(task_id='load_dwd', python_callable=load_dwd,
# pool='dw_etl', pool_slots=1, dag=dag)
# DAG 级并发:限制同时运行的任务数与 DagRun 数
# DAG('daily_orders', max_active_tasks=8, max_active_runs=1)并发层次与失控后果
| 层次 | 控制参数 | 不控制的后果 |
|---|---|---|
| DAG 任务并行 | max_active_tasks | 单个 DAG 抢占全部执行槽位 |
| DAG 批次并行 | max_active_runs | 补数时多个 DagRun 同时跑,重复写数 |
| 资源池 | pool 与 slots | 下游数据库连接被打满 |
| 执行器 | executor 并发槽位 | worker 资源耗尽,任务排队或内存告急 |
池的价值在于保护下游:数据库写入、外部接口调用这类有限资源都应该建独立池并限制并发,用「排队但稳定」换掉「同时冲上去然后全部失败」。
池槽位不足时任务会停留在排队状态,界面上看起来像「任务卡住」,实际是在等资源;排查前先看池的占用情况,不要直接重启调度器。