为 Airflow 配置数据库后端

Airflow 通过 SQLAlchemy 与元数据交互。本文介绍数据库引擎的配置、为配合 Airflow 必须调整的数据库设置,以及 Airflow 连接这些数据库时所需的配置。

选择数据库后端

如果要认真试用 Airflow,应考虑将数据库后端设置为 PostgreSQL 或 MySQL。Airflow 默认使用 SQLite,它仅适合开发用途。

原文列出的受支持数据库版本如下。请确认实际使用的版本,因为旧版数据库可能不支持全部 SQL 语句。

  • PostgreSQL:13、14、15、16、17
  • MySQL:8.0、8.4、Innovation 版本
  • SQLite:3.15.0 及以上

运行多个调度器还需要满足额外要求,详见调度器高可用的数据库要求。

警告:虽然 MariaDB 与 MySQL 很相似,Airflow 不支持将 MariaDB 用作后端。两者在索引处理等方面存在已知差异,Airflow 项目不会在 MariaDB 上测试迁移脚本或应用运行情况。过去有用户尝试过这种配置,却遇到了大量运维问题,因此项目强烈不建议这样做。尝试这种组合的用户很少,也不能指望得到相应的社区支持。

数据库 URI

Airflow 使用 SQLAlchemy 连接数据库,因此需要配置数据库 URL。可以在 [database] 节的 sql_alchemy_conn 选项中设置,也经常通过环境变量 AIRFLOW__DATABASE__SQL_ALCHEMY_CONN 配置。设置方法详见设置配置选项。

要查看当前值,可执行 airflow config get-value database sql_alchemy_conn:

$ airflow config get-value database sql_alchemy_conn
sqlite:////tmp/airflow/airflow.db

准确的格式定义见 SQLAlchemy 文档中的数据库 URL。下文也会给出示例。

配置 SQLite 数据库

SQLite 不需要单独的数据库服务器,数据保存在本地文件中,因此适合运行开发用途的 Airflow。SQLite 有很多限制,绝不能用于生产环境。

Airflow 2.0 及以上要求 sqlite3 至少为 3.15.0。某些旧操作系统默认安装的版本低于这一要求,需要手动升级。这里要升级的是系统层面的 SQLite 应用程序,而不是 Python 库的版本。SQLite 的安装方式各有不同,可参考 SQLite 官方网站和所用操作系统发行版的文档。

排查 SQLite 版本问题

即使已经升级 SQLite,而且本地 Python 显示了较新的版本,启动 Airflow 的 Python 解释器仍可能从其 LD_LIBRARY_PATH 中找到旧版本。可在相同的解释器中运行以下命令,确认实际使用的版本:

[Breeze:3.10.19] root@b8a8e73caa2c:/opt/airflow# python
Python 3.8.10 (default, Mar 15 2022, 12:22:08)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sqlite3
>>> sqlite3.sqlite_version
'3.27.2'
>>>

为 Airflow 部署设置环境变量时,可能改变 SQLite 库的查找顺序。因此最好确保系统中仅安装满足版本要求的 SQLite。

SQLite 数据库 URI 示例:

sqlite:////home/airflow/airflow.db

在 AmazonLinux AMI 或容器镜像中升级 SQLite

按原文所述,AmazonLinux 的软件源只能将 SQLite 升至 3.7,而 Airflow 要求 3.15 或更新版本。可以按以下步骤在基础镜像或 AMI 中安装较新的 SQLite3。

首先准备升级所需的 wget、tar、gzip、gcc、make 和 expect:

yum -y install wget tar gzip gcc make expect

从 sqlite.org 下载源码,在本地编译并安装:

wget https://www.sqlite.org/src/tarball/sqlite.tar.gz
tar xzf sqlite.tar.gz
cd sqlite/
export CFLAGS="-DSQLITE_ENABLE_FTS3 \
    -DSQLITE_ENABLE_FTS3_PARENTHESIS \
    -DSQLITE_ENABLE_FTS4 \
    -DSQLITE_ENABLE_FTS5 \
    -DSQLITE_ENABLE_JSON1 \
    -DSQLITE_ENABLE_LOAD_EXTENSION \
    -DSQLITE_ENABLE_RTREE \
    -DSQLITE_ENABLE_STAT4 \
    -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT \
    -DSQLITE_SOUNDEX \
    -DSQLITE_TEMP_STORE=3 \
    -DSQLITE_USE_URI \
    -O2 \
    -fPIC"
export PREFIX="/usr/local"
LIBS="-lm" ./configure --disable-tcl --enable-shared --enable-tempstore=always --prefix="$PREFIX"
make
make install

安装后,将 /usr/local/lib 加入库搜索路径:

export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH

配置 PostgreSQL 数据库

先创建 Airflow 使用的数据库和访问用户。下面创建名为 airflow_db 的数据库,以及用户名为 airflow_user、密码为 airflow_pass 的用户:

CREATE DATABASE airflow_db;
CREATE USER airflow_user WITH PASSWORD 'airflow_pass';
GRANT ALL PRIVILEGES ON DATABASE airflow_db TO airflow_user;

-- PostgreSQL 15 requires additional privileges:
-- Note: Connect to the airflow_db database before running the following GRANT statement
-- You can do this in psql with: \c airflow_db
GRANT ALL ON SCHEMA public TO airflow_user;

注意:数据库必须使用 UTF-8 字符集。

可能还需要修改 PostgreSQL 的 pg_hba.conf,将 Airflow 用户加入数据库访问控制列表,并重新加载数据库配置,使修改生效。详见 PostgreSQL 文档中的 pg_hba.conf 文件。

警告:使用 SQLAlchemy 1.4.0 及以上版本时,sql_alchemy_conn 的数据库 URL 必须采用 postgresql:// 前缀。早期版本允许使用 postgres://,但在 SQLAlchemy 1.4.0 及以上版本中会产生以下错误:

>       raise exc.NoSuchModuleError(
            "Can't load plugin: %s:%s" % (self.group, name)
        )
E       sqlalchemy.exc.NoSuchModuleError: Can't load plugin: sqlalchemy.dialects:postgres

如果暂时无法修改 URL 前缀,原文指出 Airflow 仍可配合 SQLAlchemy 1.3 运行,因此可以降级 SQLAlchemy;不过推荐的解决方式是更新前缀。详情见 SQLAlchemy 变更日志。

推荐使用 psycopg2 驱动,并在 SQLAlchemy 连接字符串中明确指定:

postgresql+psycopg2://<user>:<password>@<host>/<db>

另外,由于 SQLAlchemy 没有在数据库 URI 中直接指定特定模式的接口,需要确保 PostgreSQL 用户的 search_path 包含 public 模式。

  • 如果为 Airflow 新建了 PostgreSQL 用户,其默认 search_path 为 "$user", public,无需修改。
  • 如果复用已有用户,而且它设置了自定义 search_path,可用下面的命令修改:
ALTER USER airflow_user SET search_path = public;

有关 PostgreSQL 连接的更多配置说明,见 SQLAlchemy 文档中的 PostgreSQL 方言。

使用 PgBouncer 管理连接

Airflow 尤其在高性能部署中,可能打开大量元数据库连接。PostgreSQL 每建立一个连接就创建一个进程,连接数较多时会占用大量资源。因此,原文建议所有采用 PostgreSQL 的生产环境都使用 PgBouncer 作为数据库代理。

PgBouncer 能够汇集多个组件的连接;如果数据库位于远端、网络偶尔不稳定,它也可以提高连接对临时网络故障的容忍度。Apache Airflow Helm Chart 提供了部署示例,只需切换一个布尔配置即可启用预配置的 PgBouncer 实例。即使不用官方 Helm Chart,也可以参考其实现方式设计自己的部署。另见 Helm Chart 生产环境指南。

托管 PostgreSQL 的连接保活

使用 Azure PostgreSQL、Cloud SQL、Amazon RDS 等托管 PostgreSQL 服务时,应在连接参数中设置 keepalives_idle,并让它小于服务的空闲连接超时时间。这类服务通常在连接空闲一段时间后关闭连接,常见阈值为 300 秒,随后可能出现 psycopg2.operationalerror: SSL SYSCALL error: EOF detected。

可通过 [database] 节的 sql_alchemy_connect_args 修改保活参数,详见配置参考。例如在本地设置模块中定义一个参数字典,再把 sql_alchemy_connect_args 设置为该字典的完整导入路径。PostgreSQL 连接参数文档介绍了这些保活选项。原文提供了下面这组曾用于解决该问题的设置:

keepalive_kwargs = {
    "keepalives": 1,
    "keepalives_idle": 30,
    "keepalives_interval": 5,
    "keepalives_count": 5,
}

若将其放入 airflow_local_settings.py,配置中的导入路径为:

sql_alchemy_connect_args = airflow_local_settings.keepalive_kwargs

本地设置的配置方法见配置本地设置。

配置 MySQL 数据库

同样先创建 Airflow 使用的数据库与用户。以下示例创建 airflow_db 数据库,以及密码为 airflow_pass 的 airflow_user:

CREATE DATABASE airflow_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'airflow_user' IDENTIFIED BY 'airflow_pass';
GRANT ALL PRIVILEGES ON airflow_db.* TO 'airflow_user';

数据库必须使用 UTF-8 字符集。不过需要留意,新版 MySQL 中的 UTF-8 实际涉及 utf8mb4,可能使 Airflow 索引过大,具体见相关讨论。因此,自 Airflow 2.2 起,除非手动覆盖,MySQL 数据库的 sql_engine_collation_for_ids 会自动设为 utf8mb3_bin。这可能使元数据库中 ID 字段的排序规则出现混合,但 Airflow 中这些 ID 仅使用 ASCII 字符,不会因此产生负面影响。

为了获得合理的默认行为,Airflow 依赖 MySQL 较严格的 ANSI SQL 设置。请在 my.cnf 的 [mysqld] 节中指定 explicit_defaults_for_timestamp=1,也可以给 mysqld 可执行文件传入 --explicit-defaults-for-timestamp 开关。

推荐使用 mysqlclient 驱动,并在 SQLAlchemy 连接字符串中明确指定:

mysql+mysqldb://<user>:<password>@<host>[:<port>]/<dbname>

重要:Apache Airflow 的持续集成流程仅使用 mysqlclient 驱动验证 MySQL 后端集成。

如需其他驱动,下载和连接配置说明见 SQLAlchemy 的 MySQL 方言文档。

还要特别留意 MySQL 编码。utf8mb4 越来越常见,并已成为 MySQL 8.0 的默认字符集,但在 Airflow 2 及以上版本中使用它仍涉及额外设置,详见 #7570。若字符集使用 utf8mb4,也应设置 sql_engine_collation_for_ids=utf8mb3_bin。

注意:在严格模式下,MySQL 不允许将 0000-00-00 视为有效日期。部分 Airflow 表曾将 0000-00-00 00:00:00 作为时间戳字段默认值,因此某些情况下会出现 Invalid default value for 'end_date'。原文给出的处理方式是禁用 MySQL 的 NO_ZERO_DATE 模式。可参考相关问题说明以及 SQL Mode – NO_ZERO_DATE 文档。

Microsoft SQL Server 数据库

经过讨论和投票,Airflow PMC 成员和提交者决定不再将 Microsoft SQL Server 作为受支持的数据库后端维护。

自 Airflow 2.9.0 起,元数据库后端已移除 MsSQL 支持。这不影响现有 provider 中的 operator 和 hook,DAG 仍可访问和处理 MsSQL 中的数据。但是继续把 MsSQL 用作 Airflow 数据库后端可能产生错误,导致 Airflow 核心功能不可用。

从 MsSQL 迁移

由于 Airflow 2.9.0 终止了 MSSQL 支持,使用 Airflow 2.7.x 或 2.8.x 的部署可借助迁移脚本迁出 SQL Server。脚本位于 GitHub 的 airflow-mssql-migration 仓库。该脚本不提供支持或担保。

其他配置选项

SQLAlchemy 的行为还可以通过更多选项调整,详见配置参考中 [database] 节的 sqlalchemy_* 相关选项。

例如,可以指定 Airflow 创建表所用的数据库模式。若希望将表建在 PostgreSQL 数据库的 airflow 模式中,设置下面的环境变量:

export AIRFLOW__DATABASE__SQL_ALCHEMY_CONN="postgresql://postgres@localhost:5432/my_database?options=-csearch_path%3Dairflow"
export AIRFLOW__DATABASE__SQL_ALCHEMY_SCHEMA="airflow"

注意 SQL_ALCHEMY_CONN 数据库 URL 末尾的 search_path。

初始化数据库

完成数据库配置,并在 Airflow 中设置连接后,创建数据库结构:

airflow db migrate

Airflow 数据库的监控与维护

Airflow 广泛依赖关系型元数据库进行任务调度与执行。正确配置并持续监控该数据库,对于保持 Airflow 性能非常重要。

重点问题

  1. 性能影响:耗时过长或数量过多的查询可能显著影响 Airflow 功能,其原因可能是工作流本身、缺少优化或代码缺陷。
  2. 数据库统计信息:统计数据过时等因素会让数据库引擎做出不合适的优化决策,进而降低性能。

职责划分

数据库监控与维护的责任,取决于数据库和 Airflow 是自行管理还是使用托管服务。

在数据库与 Airflow 都自行管理的环境中,部署负责人需要负责数据库的安装、配置和维护,包括监控性能、管理备份、定期清理,以及确保数据库与 Airflow 配合运行良好。

对于托管服务:

  • 托管数据库:备份、补丁和基础监控等维护任务通常由服务商处理,但部署负责人仍需监督 Airflow 配置,针对工作流优化性能参数,管理定期清理,并监控数据库运行状况。
  • 托管 Airflow:服务商负责 Airflow 及其数据库的配置与维护;部署负责人仍需协调服务配置,确保资源规模、工作流需求与托管服务的规格和设置相匹配。

监控内容

定期监控至少应包括:

  • CPU、I/O 与内存使用量
  • 查询频率与查询数量
  • 慢查询和长时间运行查询的识别及记录
  • 低效查询执行计划的发现
  • 磁盘交换与内存使用情况,以及缓存换入换出的频率

工具与策略

Airflow 本身不直接提供数据库监控工具。应使用数据库服务器端的监控和日志获取指标,按定义的阈值跟踪长时间运行的查询,并定期执行维护任务,例如 SQL 的 ANALYZE 命令。

数据库清理可以使用 airflow db clean 命令。airflow.utils.db_cleanup 模块还提供了额外的 Python 方法,便于按具体需求进行更细致的控制和定制。

建议在生产环境主动部署监控与日志,同时避免显著影响性能。具体设置应参考所选数据库的文档;使用托管数据库时,也应了解服务商是否提供自动维护任务。

SQLAlchemy 日志

如需详细分析查询,可以开启 SQLAlchemy 客户端日志,即在引擎配置中设置 echo=True。这种方式干预程度更高,会影响 Airflow 客户端性能;繁忙环境下还会产生大量日志,因此更适合预发布等非生产环境。

实现方法见 SQLAlchemy 日志文档。可通过 sql_alchemy_engine_args 配置参数将 echo 设为 True。

启用大量日志前,需要考虑对 Airflow 性能和系统资源的影响。生产环境应优先选择服务器端监控,以尽量减少客户端日志对运行性能的干扰。

下一步

Airflow 默认使用 LocalExecutor。可以考虑配置其他执行器,以获得更合适的性能。

原文来源:Set up a Database Backend。本文依据留存原文译为中文,代码示例按原文保留。

© The Apache Software Foundation. Apache Airflow、Apache、Airflow 及相关标志是 Apache Software Foundation 的注册商标或商标,其他产品及品牌归各自所有者所有。原文许可:License;Apache 许可证。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容