RPC 和 VersionedObject 兼容性¶
https://blueprints.launchpad.net/cinder/+spec/rpc-object-compatibility
以下提案旨在启用 Cinder 的滚动升级。更具体地说,它允许 Cinder 服务(cinder-api、cinder-scheduler、cinder-backup 和 cinder-volume)逐个更新,同时仍然保持运行状态(一次只关闭一个服务进行升级,而不是全部)。它遵循 Nova 中的滚动升级功能,使用 oslo_versionedobjects,但不同之处在于没有间接 API。相反,RPC 版本和对象将被固定到向后兼容的版本,并在所有服务升级后切换到最新版本。
问题描述¶
如今,当发布新里程碑时,将 OpenStack 云中的所有服务升级到最新版本可能需要相当长的时间。升级涉及:将数据库同步到最新模式,以及更新每个分布式 Cinder 服务。此过程可能会使云的部分服务停机几个小时,甚至更长时间。运营商理想情况下希望在升级到下一个版本时减少云的停机时间。
用例¶
作为运营商,我希望单独升级每个服务到最新版本,但不要使我的整个云在此过程中停机。
提议的变更¶
升级像 Cinder 这样的分布式服务存在一些问题:1. 通过 RPC 发送的内容可能会发生变化。 2. RPC 接口本身可能会发生变化,例如,新的关键字参数。
为了解决这些问题,可以使用 oslo_versionedobject 使内容向后兼容,并将 RPC 接口固定到特定版本,直到 Cinder 中的所有组件都升级为止。
实现方式如下:1. 服务启动时,它会注册它了解的 RPC 和对象版本,即最小版本和最新版本。
2. 在升级时,管理员逐个升级每个 Cinder 服务。当服务启动时,它知道存在较新版本,但继续以数据库中指示的当前/固定版本运行。数据库是服务应运行哪个版本的真实来源。
Cinder 服务的升级顺序没有特定要求。数据库跟踪服务应使用的 RPC 和对象版本。该服务将继续使用特定版本,直到管理员发出“一切正常”的信号(如下所示)。
3. 在其他 Cinder 服务正在升级时,该服务必须不断检查数据库以获取当前和可用的 RPC 和对象版本。由于不断访问数据库会严重影响性能,因此可以通过缓存跟踪版本的表的副本来最小化它。该副本将在几秒钟内有效(例如,5 秒),然后刷新。这至少减少了每次 RPC 调用对数据库的访问次数。
服务内部使用一个标志来跟踪它是否应以向后兼容模式运行(例如,BACKWARD_COMPAT_MODE),即应使 RPC 和对象版本向后兼容。如果当前版本低于可用版本,则将 BACKWARD_COMPAT_MODE 设置为 true。否则,将其设置为 false。在每个服务的 rpcapi.py 中都有逻辑来设置给定 RPC 版本的正确关键字参数。在通过 RPC 发送的对象中也有逻辑来设置给定目标版本的正确属性。更具体地说,应通过调用它自己的 obj_make_compatible() 使每个对象向后兼容,从而将对象转换为给定的目标版本。
4. 一旦所有 Cinder 服务都升级,管理员将执行“cinder-manage version upgrade”以将当前/固定版本切换到最新的可用版本。此命令基本上会更新 Cinder 数据库中的 service_versions 表。由于当前版本等于可用版本,BACKWARD_COMPAT_MODE 设置为 false,并且每个 RPC 调用不再需要检查数据库。
通过使用 BACKWARD_COMPAT_MODE 标志,每个 Cinder 服务只需要重启一次(即,一次用于升级)。一旦关闭该标志,每个 Cinder 服务就可以动态切换到使用新的 RPC 和对象版本。
一旦 Cinder 内部的大部分组件都切换到使用 oslo_versionedobject,并且添加了 RPC 兼容性层(此功能),就应该支持滚动升级(希望在 Liberty 版本及以后)。滚动升级应限制为两个旧版本。例如,版本 N 将与版本 L(Liberty)和 M 向后兼容,版本 O 将与版本 M 和 N 向后兼容。对于过旧的主机/服务,它应该在启动时引发异常,并且不允许启动。
备选方案¶
升级过程可以保持不变,其中必须同时关闭并升级所有组件。一些云运营商,例如 Rackspace,已经将其升级过程自动化到几分钟。但是,其他云运营商需要此功能。
数据模型影响¶
将创建一个名为 service_versions 的新表来跟踪 RPC 和对象版本。模式如下
service_versions = Table(
'service_versions', meta,
Column('created_at', DateTime(timezone=False)),
Column('updated_at', DateTime(timezone=False)),
Column('deleted_at', DateTime(timezone=False)),
Column('deleted', Boolean(create_constraint=True, name=None)),
Column('id', Integer, primary_key=True, nullable=False),
Column('service_id', String(length=255)),
Column('rpc_current_version', String(length=36)),
Column('rpc_available_version', String(length=36)),
Column('object_current_version', String(length=36)),
Column('object_available_version', String(length=36)),
mysql_engine='InnoDB'
)
service_id 是服务名称 + 主机。 *_current_version 是服务当前运行和固定的版本。 *_available_version 是服务了解的并且(如果较新)可以升级到的版本。
REST API 影响¶
无
安全影响¶
无
通知影响¶
无
其他最终用户影响¶
将引入一个新的命令,即“cinder-manage version upgrade”,以将 Cinder 服务切换到使用最新的 RPC 和对象版本。
性能影响¶
在升级期间,在发送 RPC 调用之前,它必须检查是否需要向后兼容。如果是,则需要调整 RPC 接口和对象以使其向后兼容。由于需要额外的数据库调用来查找当前和可用的 RPC 和对象版本,因此会产生性能成本。由于在每次 RPC 调用之前访问数据库会严重影响性能,因此可以通过缓存跟踪版本的表的副本来最小化它。该副本将在几秒钟内有效(例如,5 秒),然后刷新。这至少减少了每次 RPC 调用对数据库的访问次数。升级完成后,所有服务都升级到最新版本,则不再需要检查数据库。
其他部署者影响¶
无
开发人员影响¶
从合并此功能开始,Cinder-api、cinder-scheduler、cinder-volume 或 cinder-backup 中的任何对 RPC 接口的新更改都必须添加到向后兼容层中。此外,对对象(例如,卷、快照等)的任何新更改都必须在对象的 obj_make_compatible() 中使其向后兼容。
实现¶
负责人¶
- 主要负责人
thang-pham
- 其他贡献者
DuncanT(想出此功能的人)
工作项¶
创建 service_versions 表以跟踪 RPC 和对象版本。
在启动时注册每个 Cinder 服务的 RPC 和对象版本。
在每个 Cinder 组件的 rpcapi.py 中创建 RPC 兼容性层,以在通过 RPC 发送之前调整对象和 RPC 接口。
创建一个“cinder-manage version upgrade”CLI 以将每个 Cinder 服务切换到使用最新版本。
依赖项¶
需要合并 oslo_versionobjects 用于卷、备份、服务、一致性组、配额,以便可以使对象向后兼容。
测试¶
理想情况下,在 tempest(例如,grenade)中应该有一个滚动升级测试,以测试不同版本之间的基本 RPC 和对象固定。但是,这种测试仅适用于版本 M 及以后,因为大多数 oslo_versionedobject 和 RPC 兼容性层都不在以前的版本中。
文档影响¶
应该记录运营商可以单独升级 Cinder 组件,而无需关闭整个云。在流程结束时,必须执行“cinder-manage version upgrade”才能将服务切换到使用最新的 RPC 和对象版本。