使用无 API 停机时间的升级控制器

https://blueprints.launchpad.net/neutron/+spec/online-upgrades

问题描述

目前,新主要 Neutron 版本的数据库迁移意味着在应用 contract alembic 迁移脚本之前,必须完全关闭所有 neutron-server 实例。

在运行流行的云服务时,在应用所有 contract alembic 迁移脚本(可能需要一段时间,特别是对于具有大量数据的数据库)之前,关闭所有 neutron-server 实例通常很困难或不切实际。 这种关闭需要更精细的计划,试图将升级过程压缩到维护窗口中,以减少对 API 用户的干扰。 对于具有高 SLA 的云服务,可能无法一次关闭所有 Neutron API 端点,导致用户在较长时间内无法使用 Networking API。 由于其他服务(例如 Nova)对 Neutron API 可用性的依赖,升级的影响更大,因为 Neutron 是任何 Openstack 安装中的核心服务。

本规范描述了一种允许非影响性 neutron-server 升级的方法,使集群中的实例保持运行。 与完全关闭不同,操作员将能够以滚动模式升级服务,升级运行该服务的每个节点,而不会干扰其他此类节点。 如果 Networking API 由隐藏在负载均衡器后面的多个节点提供,则这种方法应该可以实现无停机升级体验。 理想情况下,用户在整个升级过程中不应注意到任何访问 Neutron API 服务的问题。

注意

在云中运行不同主要版本的 neutron-server 会引发如何缓解这些版本之间细微的 API 行为差异的问题。 例如,在 Newton 中,所有资源都收到一个新的 project_id 字段。 如果我们在轮询负载均衡器后面运行混合的 Mitaka/Newton 版本的 neutron-server,那么对同一资源的连续 GET 调用将导致不同的响应负载,具体取决于 API 请求击中的特定 neutron-server。

为混合版本环境强制执行一致的 API 行为,或将 API 行为固定到描述先前主要版本行为的版本,超出本提案的范围。 后续蓝图可以阐明最佳实践,或提出严格 API 行为控制的机制。

提议的变更

由于 neutron-server 停机时间完全源于在 neutron-server 运行时执行不安全的 contract 升级迁移,因此解决方案是使这些迁移对在线执行安全,或消除它们。 这通过两个主要更改来实现

  1. 耗时的数据库迁移更改从 neutron-db-manage 阶段移动到 neutron-server 本身,以便在服务启动并处理请求时迁移数据,而不是在完全关闭时迁移数据。 数据迁移过程将是 lazy,在插件代码访问资源时发生。 也就是说,用户在完成所有剩余资源的迁移之前,不应切换到下一个主要版本。 我们将提供一个工具来触发待处理的迁移(最好是分块),它将成为下一个升级准备过程的一部分。 该工具将类似于 Cinder 中找到的 online-data-migrations 命令。

  2. 剩余的模式收缩更改将推迟到

    • 所有数据都从旧表/列迁移,并且

    • 集群中没有 neutron-server 实例能够访问过时的表/列时进行。

注意

这个想法并不新鲜,其他项目已经摆脱了需要离线执行的不安全迁移脚本。 其中包括 Nova 和 Cinder。

在 neutron-server 运行时实现的多个表/列之间的数据迁移可能容易出错,需要特定的审查员关注。 期望对任何需要读取或更新数据库模型的补丁进行适当的关注是不切实际的。 因此,第一步是将访问数据库模型的层隔离在特殊的 facade 后面。 该 facade 的基础是 oslo.versionedobjects 和相应的 NeutronObject 框架,该框架已经存在于树中,并已成功用于多个功能(qos、vlan-aware-vms)。 将所有使用 SQLAlchemy 模型访问数据库的插件代码切换到对象 facade 的工作正在进行中,并作为 单独的蓝图 进行跟踪。

一旦插件代码切换到使用对象进行资源持久化,我们就可以在相应对象类中的单个位置实现任何所需的数据迁移规则,从而将消耗代码与所有迁移/转换过程的复杂性隔离开来。

由于对象中的数据转换是延迟的,在下一次主要升级时,某些资源的数据库记录可能仍未转换为新格式。 为了便于下一次主要升级,将实现一个新的 neutron-db-manage CLI 命令 (migrate-data),操作员可以在继续升级之前执行该命令。 该命令将迁移任何剩余的数据模型到新格式。 该命令将运行通过 stevedore 命名空间公开的数据迁移脚本,以便外部子项目可以使用它。

即使使用持久化 facade,预计仍需要对迁移机制和技术进行一些工作。 首先,将需要模式/数据迁移更改的 Pike 功能将被识别并用作探索该提案可行性的 guinea pig

在撰写本文时,port bindings rework 可能是尝试新方法的最佳候选者。

对于不安全的模式更改,如果在发布 X 中我们想要引入 contract 迁移,我们只能在发布 X+2 中以破坏性方式执行它(即,在 X 和 X+1 使用的旧模式中的所有数据都迁移后),这保证了当部署者从 X+1 升级到 X+2 时,运行背后的服务器实例不会遇到受模式迁移影响的数据/代码。 在这一点上,即使是看似不安全的诸如删除表或列之类的操作也可以在 neutron-server 实例在线时安全地执行。 对于 Ocata 及更高版本,不应再有新的 contract alembic 脚本。 它们可能在以后的版本中出现。

为了实现 Newton 到 Ocata 及更高版本的升级目标,我们应该保证所有补丁在 Ocata 及更高版本期间都将遵循既定的路径。 这将通过自动化和社会手段来实现。

对于前者,我们引入了一个 功能测试,该测试在尝试执行已知不安全的操作时会失败。

我们可能无法以编程方式捕获所有内容,因此我们仍然需要确保核心审查团队了解新要求,并主动跟踪所有提出的 alembic 迁移至少在最初的几个周期,直到平均审查员养成发现和 -1 不安全补丁的习惯。

为了确保新的升级模式有效,将实现一个新的 gating grenade 作业,该作业将运行不同主要版本的多个 neutron-server 实例。 对 Networking API 的访问将通过轻量级负载均衡器 (haproxy) 实现,该负载均衡器将多个 neutron-server 实例隐藏在其后。 我们还可以考虑将 Neutron API 的已知使用者(例如 Nova)移动到“旧”子节点,以确保它可以与较新和较旧的 Neutron 在同一设置中通信。 grenade 作业将仅使用两个相邻的主要版本 neutron-server,以符合 assert:supports-upgrade 标签要求

行动项目

(该功能假定完成了 adopt-oslo-versioned-objects-for-db 蓝图,但并不严格依赖于它。)

  1. 在 Ocata 的开始时阻止不安全的 contract 迁移(完成)。

  2. 探索针对新功能的数据迁移的提案可行性。

  3. 添加运行不同主要版本 neutron-server 的投票 grenade 作业。

  4. 在 ops 升级指南中记录新的升级路径及其限制。

  5. 向 devref 和更广泛的受众通报新要求。

参考资料

无。