airflow

[TOC]

1. Airflow 是如何部署的?为什么日志在宿主机上?

我们的 Airflow 是直接安装在 Mac 宿主机上的 Python 进程,不是容器。

Mac 宿主机
├── Python 进程: airflow webserver  (PID=80064, 直接跑在 Mac 上)
├── Python 进程: airflow scheduler  (PID=79987)
└── /usr/local/install/mini-datalake/airflow/   ← 直接是宿主机目录
    ├── logs/      ← 日志直接写到宿主机文件系统
    ├── airflow.db
    └── dags/

所以日志在宿主机目录完全正常,因为进程本身就跑在宿主机上。

如果 Airflow 是容器部署的,日志有两种方案:

  • docker exec airflow-scheduler cat /opt/airflow/logs/...
  • 或者把日志目录 bind mount 到宿主机(像 MinIO 的 data 目录那样)

2. 任务业务逻辑跑在哪?是否支持分布式?

我们当前的架构:

Mac 宿主机
└── airflow scheduler (单进程,SequentialExecutor)
    └── fork 子进程执行 task(也在宿主机上)
        ├── generate_and_produce  ← 宿主机跑
        ├── consume_to_ods        ← 宿主机跑
        ├── etl_to_dws            ← 宿主机跑,但会 docker exec 到 K8s Spark Pod
        ├── index_to_elasticsearch ← 宿主机跑,HTTP 调用 K8s ES
        └── index_to_milvus       ← 宿主机跑,gRPC 调用 Docker Milvus

受限于单机,task 函数本身都在宿主机执行,资源受宿主机限制。

生产环境的分布式部署架构:

                    ┌─────────────────────────────┐
                    │      Airflow Metadata DB      │
                    │      (PostgreSQL/MySQL)        │
                    └──────────────┬──────────────-─┘
                                   │ 所有组件共享同一个 DB
          ┌────────────────────────┼────────────────────────┐
          ▼                        ▼                        ▼
   ┌─────────────┐         ┌─────────────┐         ┌─────────────┐
   │  Webserver  │         │  Scheduler  │         │   Worker    │
   │  (Web UI)   │         │  (调度决策)  │         │  Worker    │
   └─────────────┘         └──────┬──────┘         │  Worker    │
                                  │ 发任务          └──────┬──────┘
                            ┌─────▼──────┐                │ 实际执行 task
                            │   消息队列  │ ───────────────►│
                            │  (Redis/   │
                            │  RabbitMQ) │
                            └────────────┘
Executor 说明 我们现在
SequentialExecutor 单进程串行,仅用于本地测试 ✅ 当前
LocalExecutor 多进程并行,单机 需要 PostgreSQL
CeleryExecutor 多 Worker 节点,真正分布式 需要 Redis + 多台机器
KubernetesExecutor 每个 task 启动一个 K8s Pod 需要 K8s 集群

KubernetesExecutor 是最适合我们项目的生产方案——每个 task 动态创建一个 Pod,跑完销毁,天然分布式且资源隔离。我们项目后续可以升级到这个。


3. Airflow 为什么是离线数据处理调度的首选?

核心优势:

① DAG 即代码(Code as Configuration)

t1 >> t2 >> t3 >> [t4, t5] >> t6

依赖关系用 Python 代码描述,可版本控制、可 Code Review,比 cron + 脚本的依赖关系清晰得多。

② 丰富的重试/容错机制

default_args = {
    "retries": 3,
    "retry_delay": timedelta(minutes=5),
    "retry_exponential_backoff": True,
    "execution_timeout": timedelta(hours=1),
}

单个 task 失败自动重试,不影响其他 task,失败后从断点续跑(不用重跑整个流水线)。

③ 时间分区天然对齐数仓

# ds_nodash = '20260414',自动从上下文获取
batch_id = context["ds_nodash"]
# catchup=True 时会自动补跑历史分区

数仓按天/小时分区,Airflow 的调度周期和分区概念完美对齐,回填历史数据一个开关搞定。

④ 完整的可观测性

  • Web UI 直观看每个 task 的状态、日志、耗时、甘特图
  • 任务卡死 → heartbeat timeout 自动告警
  • 历史运行对比 → 发现数据量异常

⑤ 庞大的 Provider 生态

airflow-providers-amazon    → S3/EMR/Glue
airflow-providers-google    → BigQuery/GCS/Dataflow
airflow-providers-apache-spark → SparkSubmitOperator
airflow-providers-elasticsearch
airflow-providers-slack     → 失败通知

不用自己写对接代码,开箱即用。

⑥ 对比其他方案:

方案 缺点
Linux cron 无依赖管理,失败不告警,无 UI
自研调度 重复造轮子,缺重试/回填/监控
Spark Structured Streaming 流处理,不适合批处理分区逻辑
Flink 同上,学习曲线陡
Oozie/Azkaban 老旧,社区不活跃

适合 Airflow 的典型场景(正好是我们的项目):

  • 每日定时从 Kafka 读取数据写入 MinIO ODS
  • dt=YYYYMMDD 分区跑 Spark ETL
  • 清洗完写入 ES/Milvus 索引
  • 导出训练集

不适合 Airflow 的场景:

  • 秒级实时流处理(用 Flink/Spark Streaming)
  • 简单的单步定时任务(直接 cron)
  • 纯 API 服务编排(用 Temporal/Conductor)

airflow分布式部署代码如何同步

好问题,这两个问题触及了 Airflow 生产部署的核心设计。


1. 分布式部署时代码如何同步?在哪里写代码?

你只在一个地方写代码——DAGs 目录,所有节点共享同一份。

生产上有三种同步方案:

方案 A:Git Sync(最主流)

开发者本地
    │ git push
    ▼
Git 仓库 (GitHub/GitLab)
    │
    ├── Worker 节点 1: git-sync sidecar 容器每 30s pull
    ├── Worker 节点 2: git-sync sidecar 容器每 30s pull
    ├── Worker 节点 3: git-sync sidecar 容器每 30s pull
    └── Scheduler:     git-sync sidecar 容器每 30s pull

每个节点跑一个 git-sync 的 sidecar 容器,定时从 Git 仓库拉取 DAG 文件到本地 /dags 目录。你只需要 push 到 Git,所有节点自动同步。

K8s 部署时的 Pod 配置长这样:

containers:
  - name: airflow-scheduler
    image: apache/airflow:2.10
    volumeMounts:
      - name: dags
        mountPath: /opt/airflow/dags

  - name: git-sync                    # sidecar
    image: registry.k8s.io/git-sync
    env:
      - name: GITSYNC_REPO
        value: "https://github.com/yourorg/dags.git"
      - name: GITSYNC_PERIOD
        value: "30s"
    volumeMounts:
      - name: dags
        mountPath: /git               # 写到同一个共享 volume
volumes:
  - name: dags
    emptyDir: {}                      # scheduler 和 git-sync 共享

方案 B:共享文件系统(NFS / EFS)

所有节点挂载同一个 NFS/EFS 目录
/mnt/airflow/dags/ ← 你在这里写文件,所有节点实时看到

简单粗暴,延迟低,但 NFS 有单点故障风险。

方案 C:KubernetesExecutor(每个 task 是独立 Pod)

Scheduler (有 DAG 代码)
    │ 触发 task
    ▼
动态创建 Pod (从镜像启动,DAG 代码已打包进镜像)
    │ 跑完销毁

DAG 代码直接打包进 Docker 镜像,没有同步问题,但每次改代码需要重新 build 镜像。

实际工作流(Git Sync 方案):

1. 本地开发: vim dags/my_pipeline.py
2. 测试:     airflow dags test my_pipeline
3. 提交:     git commit && git push
4. 生效:     30 秒内所有节点自动同步

2. 本机为什么不用容器部署?

原因有三,但本质是:本地学习环境,容器部署 Airflow 的收益不抵成本。

原因 1:安装时 Airflow 已经在宿主机上了

pip3 install apache-airflow  # 你最初装的时候就直接装宿主机了

当时我们看到已安装就直接用了,再容器化是额外工作量。

原因 2:容器化 Airflow 在本机有额外复杂度

如果用容器部署,需要解决:

问题 1: DAG 目录挂载
  OrbStack 不支持单文件 bind mount(我们已踩过这个坑)
  需要把整个 dags/ 目录 bind mount 进容器

问题 2: submit_etl.sh 需要在容器内 docker exec 进 Spark 容器
  Airflow 容器内 → docker exec → Spark 容器
  需要把 /var/run/docker.sock 挂载进 Airflow 容器(Docker in Docker)
  这在 OrbStack 上路径不标准

问题 3: 网络互通
  Airflow 容器需要访问 datalake bridge network(MinIO/Milvus)
  又需要访问 K8s NodePort(ES/Spark)
  需要额外的 network 配置

原因 3:宿主机部署在本地学习上反而更透明

宿主机进程 容器
日志查看 直接 tail -f logs/ docker logs 或挂载
调试 直接 python3 dags/xxx.py 需进入容器
文件编辑 直接编辑 bind mount 或 docker cp
fork 问题排查 ps aux 直接看 docker exec ps
学习成本 高(还没到学这个的时候)

生产环境一定要容器化,标准的生产 Airflow K8s 部署是:

# Helm chart: apache-airflow/airflow
helm install airflow apache-airflow/airflow \
  --set executor=KubernetesExecutor \
  --set dags.gitSync.enabled=true \
  --set dags.gitSync.repo=https://github.com/yourorg/dags

一条命令部署好 Scheduler + Webserver + GitSync + PostgreSQL,所有组件都是 K8s Pod,这才是生产标准。我们这个项目后续可以作为 Phase 5 来实践。

posted @ 2026-04-14 08:39  向着朝阳  阅读(8)  评论(0)    收藏  举报