Airflow调度器不支持双活,必须主备+外部协调;多实例并发写数据库会导致任务重复、状态冲突或死锁,官方要求同一时刻仅一个活跃实例。

Composer 并非标准中间件或调度系统名称——当前主流技术栈中,没有广泛使用的、名为 Composer 的调度中心。你实际想问的,极大概率是以下三者之一:
-
Apache Airflow 的调度器(
airflow-scheduler):常被误称为“Composer”,因 Google Cloud Composer 是托管版 Airflow - 阿里云 DataWorks 调度中心(旧称“调度系统”或“DataStudio 调度”):部分用户口语化简称为“Composer”
- 自研或私有调度平台,内部代号为 Composer:需依赖其具体架构判断
结论先行:Airflow 调度器本身不支持多活,高可用必须靠主备 + 外部协调;所谓“双活”是伪命题,强行双写调度状态会导致元数据冲突、任务重复触发或漏执行。
airflow-scheduler 为什么不能双活?
airflow-scheduler 不是无状态服务,它持续扫描 DAG 文件、解析依赖、生成任务实例(TaskInstance),并写入数据库(PostgreSQL/MySQL)中的 task_instance、dag_run 等表。多个 scheduler 实例同时写同一张表且无分布式锁协调,会引发:
- 同一任务被多次触发(
state=queued写入两次) - DAG 解析结果不一致(如不同 scheduler 加载了不同版本的 DAG 文件)
- 数据库死锁或唯一键冲突(例如
dag_run.dag_id + dag_run.execution_date唯一索引报错)
官方文档明确要求:scheduler 实例必须通过外部机制保证「同一时刻仅一个活跃」,其余为 standby。
如何真正实现 airflow-scheduler 容灾备份?
核心思路:单主运行 + 快速故障检测 + 自动接管,而非双活。
- 使用
airflow内置的standby_scheduler模式(v2.2+)或配合外部进程管理器(如 systemd、supervisord) - 所有 scheduler 实例共享同一数据库和存储(DAGs 存于 Git 或 S3/NFS,确保一致性)
- 用心跳表(
slot_pool或自建scheduler_heartbeat表)+ 定时健康检查(airflow db check+ps aux | grep scheduler)判定主节点存活 - 故障时,standby 进程通过脚本或 Operator 触发
airflow scheduler --do-not-pause-dags-on-failure启动,并清理前主残留锁(如dag_run.state = 'running'卡住的记录)
常见错误配置:
- 直接起两个
airflow scheduler进程,没做任何互斥控制 → 任务爆炸式重复 - DAG 文件用本地路径,各 scheduler 加载不同内容 → 调度逻辑分裂
- 数据库连接池未调大(默认 5),高并发下 scheduler 抢不到连接 → 假死误判
Google Cloud Composer 的容灾怎么做?
Cloud Composer 是托管服务,你无法直接操作 scheduler 进程,但可通过平台能力实现容灾:
- 启用高可用环境(HA Environment):底层自动部署 2+ 个 scheduler 实例,GCP 内部用 leader election(基于 Cloud SQL + etcd-like 协调)确保单主
-
跨区域部署两个独立 Composer 环境(主/备):用
gcloud composer environments create分别建在 us-central1 和 asia-east1,再通过外部工具(如 Cloud Scheduler + Pub/Sub)同步 DAG 变更、手动触发 failover -
关键限制:两个环境间 DAG 状态、
task_instance数据完全不互通,failover 后需人工确认断点、重跑或跳过已执行任务
容易被忽略的一点:Cloud Composer 的 “HA mode” 仅保障 scheduler 进程级可用,不保证 DAG 执行状态连续性。比如主 scheduler 在发送 task 到 Celery/K8s worker 的瞬间宕机,该 task 可能已入队但无记录,备 scheduler 无法感知,导致丢失或重复——这必须靠业务层幂等设计兜底,不是调度器能解决的。
复杂点始终在状态协同:调度器不是纯计算单元,它本质是带状态的协调器。所有“双活”幻想,都绕不开对元数据一致性的暴力妥协。真要降低 RTO,与其纠结双活,不如压测 scheduler 启动耗时、优化 DAG 解析性能、提前预热 worker 队列——这些实打实的优化,比强行堆 scheduler 实例更有效。


















