在线模式 Schema 变更

https://blueprints.launchpad.net/nova/+spec/online-schema-changes

使 schema 变更在服务运行期间在线执行(即,在安全且语义上可行的情况下)。这将允许操作员减少部署期间当前所需停机时间。

问题描述

  • 目前,所有数据库迁移都需要离线运行。

  • 数据库迁移在历史上一直是部署期间导致长时间停机的原因。

  • Schema 变更需要在两个地方重复:Nova 中定义的数据库模型和编写迁移脚本。

用例

  • 任何希望减少部署期间停机时间的操作员。

  • 希望减少编写迁移脚本时间的开发者。

  • 希望维护一组本地 schema 变更的操作员。

项目优先级

这符合 ‘Live Upgrades’ liberty 优先事项。

提议的变更

将添加一种新的 schema 变更应用替代工作流,该工作流将扩展 schema,然后收缩 schema(扩展/收缩工作流)。

新的扩展/收缩工作流将不使用任何迁移脚本,而是会动态地将正在运行的 schema 与 Nova 中定义的数据库模型进行比较。将生成 DDL 语句,并可选地执行,以使正在运行的 schema 与模型匹配。

现有的 schema 管理工作流是 ‘db sync’ 命令到 nova-manage。它由 sqlalchemy-migrate 管理,并使用单独的迁移脚本。此工作流将暂时保留,但预计在未来某个时间会被移除,留下扩展/收缩工作流作为管理数据库 schema 的方式。

在移除 sqlalchemy-migrate 工作流之前,所有 schema 变更仍然需要编写 sqlalchemy-migrate 迁移脚本。

将添加三个新的 nova-manage 命令

  1. expand。这将应用与旧的运行代码兼容的变更。

  2. migrate。这将应用需要离线运行的变更。

  3. contract。这将应用与新的运行代码兼容的变更。

那些可以在运行期间安全且语义上应用在线的 schema 变更将在扩展和收缩阶段应用。此外,只有那些不会在数据库中获取长时间运行锁定的 schema 变更才会被考虑用于在线阶段(扩展、收缩)。所有其他 schema 变更将在迁移阶段应用。

这三个新命令将通过动态执行 alembic 的 autogenerate 和 DDL 生成功能来构建。Alembic 将生成差异列表,然后使用 alembic 的单独功能生成 DDL 语句。

在每个阶段可以运行的 DDL 语句集将由使用的数据库软件(例如 MySQL、PostgreSQL 等)、数据库软件的版本(例如 MySQL 5.5、5.6 等)以及使用的存储引擎(例如 InnoDB、TokuDB 等)决定。

例如,索引添加可以在 MySQL 5.5 中在线执行,但在 5.1 中不行。索引添加将在 MySQL 5.5 或更高版本的扩展阶段运行,但在 MySQL 5.1 的迁移阶段运行。

最初将在线运行的集合将首先是保守的,并且是安全运行的可能性范围的子集。这可以在未来随时安全地扩展。

在扩展期间可能执行的 schema 变更:- 表创建 - 列添加 - 非唯一索引添加

在迁移期间可能执行的 schema 变更:- 唯一索引添加/删除 - 外键添加/删除

在收缩期间可能执行的 schema 变更:- 表删除 - 列删除 - 非唯一索引删除

有些当前未使用或难以自动化的 schema 变更最初将不允许。例如,列类型更改最初将不允许。这是因为并非所有列类型更改都可以自动化,因为存在复杂性和数据库限制。如果可以在所有数据库上自动化,则将来可能会实现列类型更改的子集。

迁移和收缩阶段将验证前一个阶段(迁移阶段的扩展,收缩阶段的扩展和迁移)不再需要在继续之前执行。

这将通过生成前一个阶段所需变更的列表并验证该列表为空来执行。这表明前一个阶段已经运行或是不必要的。

一个新的 ‘–dryrun’ 参数将打印而不是执行每个生成的 DDL 语句。数据库管理员可以使用它来查看特定阶段将执行的内容。如果需要,这些可以手动执行。Schema 同步器将不会生成该 DDL 语句,因为正在运行的 schema 不再具有该差异。

当最终运行 ‘db contract’ 并且已验证正在运行的 schema 与模型匹配时,migrate_version 表中的版本将被更新到最新的已发布的 sqlalchemy-migrate 迁移版本。这将保持与现有 sqlalchemy-migrate 工作流的兼容性。

这两个工作流之间的根本区别在于扩展/收缩工作流是声明性的(通过使用模型),而 sqlalchemy-migrate 工作流是命令式的(通过使用迁移脚本)。

通过声明性,它将变更限制在一个地方(数据库模型),并允许进行更智能的决策(通过考虑数据库软件、引擎、版本等)。

备选方案

将现有的单个迁移流拆分为三个单独的迁移流。这将允许某些 schema 变更在线执行。

这将限制可以安全地在线执行的 schema 变更到 Nova 支持的数据库的最低公分母。

这还需要更改 sqlalchemy-migrate 才能管理单独的迁移流。

另一种选择是完全删除对 sqlalchemy-migrate 的 schema 变更的使用。nova-manage 的 ‘db sync’ 命令将通过有效地调用 ‘db expand’、‘db migrate’ 和 ‘db contract’ 来实现。

数据模型影响

REST API 影响

安全影响

通知影响

其他最终用户影响

性能影响

运行在线 DDL 变更会影响正在运行的系统性能。这是可选的,仅在部署者明确请求时才执行。

部署者可以通过在活动低谷期安排扩展和收缩阶段来缓解此问题。扩展阶段可以在迁移阶段之前运行任意时间。同样,迁移阶段运行后不需要立即运行收缩阶段。

其他部署者影响

使用新的扩展/收缩工作流是可选的。如果部署者不想在线执行数据库 schema 变更,则可以继续使用 nova-manage 的 ‘db sync’ 命令。

希望利用在线 schema 变更的部署者需要在其部署过程的适当步骤中运行 ‘db expand’、‘db migrate’ 和 ‘db contract’ 命令。

从 sqlalchemy-migrate 工作流切换到扩展/收缩工作流可以在任何时候发生。反之只能在运行最终的 ‘db contract’ 之后发生(以确保应用所有 schema 变更并更新 migrate_version 表)。

如果使用扩展/收缩工作流,则需要为 Nova 的每个正式发布执行 ‘db contract’。这是为了确保将来可以重用 SQL 命名空间(表、列等)。

对本地 schema 变更(额外的索引、列、表等)进行更改的部署者需要更新模型,以确保在收缩阶段不会删除这些添加。

如果使用扩展/收缩工作流,则部署者可以在停止或重新启动任何服务之前运行 ‘db expand’。‘db migrate’ 可能会获取数据库中的锁,并可能影响正在运行的服务。可以在所有 Nova 服务运行新代码后运行 ‘db contract’。

开发人员影响

最终不再需要编写更多的 sqlalchemy-migrate 迁移,从而减少开发人员的工作量。

不再进行迁移压缩。数据库的初始表创建完全由 schema 同步器处理。

某些 schema 变更将不再允许。通常,这限制为无法合理自动化的 schema 变更,但这些 schema 变更通常是导致停机时间最多的。

命名空间(表、列、索引等)在正式发布周期中不可重用。收缩阶段只需要为每个正式发布执行一次,直到下一个正式发布,从而固定旧名称。

实现

负责人

主要负责人

johannes.erdfelt

其他贡献者

工作项

  • 使用 alembic.autogenerate 实现 schema 同步器

  • 实现新的 ‘expand’、‘migrate’ 和 ‘contract’ 命令到 ‘nova-manage db’

  • 确保 grenade 和 turbo-hipster 测试已更新

依赖项

这建立在 validate-migrations-and-model 规范之上。现有的 alembic.autogenerate 的使用现在也将用于生成使 schema 与模型匹配所需的变更列表。

这也取决于放弃对 sqlalchemy-migrate 的数据迁移的使用。

测试

将不会添加任何 tempest 测试,因为 tempest 不会进行任何升级测试。

将添加一个 Nova 单元测试来测试从空数据库开始。

Grenade 当前测试从 Nova 的旧版本进行升级。需要一个新的测试来使用新的 ‘db expand’、‘db migrate’ 和 ‘db contract’ 命令。这将与 ‘db sync’ 的结果进行比较,以确保从过去的提交进行升级在语义上是相同的。

turbo-hipster 测试使用生产数据库快照进行升级。它当前使用 ‘db sync’ 命令到 nova-manage。新的扩展/收缩工作流也将进行测试,以确保两种工作流都能正常运行。

文档影响

需要更新文档,以包含 ‘nova-manage db’ 的新 ‘expand’、‘migrate’ 和 ‘contract’ 命令。

需要更新发布说明,以警告模型需要使用本地 schema 变更进行更新。

实例类型需要手动创建,因为 216 迁移不一定还会运行。

参考资料

https://etherpad.openstack.org/p/kilo-nova-zero-downtime-upgrades