从 placement 统计配额使用情况

https://blueprints.launchpad.net/nova/+spec/count-quota-usage-from-placement

在 Pike 版本中,我们重新设计了配额系统,以统计实际资源使用情况,而不是使用预留并跟踪配额使用情况的单独数据库表。我们通过查询每个 cell 数据库并按项目和用户汇总结果来统计实例、CPU 和 RAM 等资源。这种方法在“处理 cell 宕机”的背景下存在问题。如果某个 cell 变得不可用,其数据库中的资源将无法被统计,并且在 cell 恢复之前不会包含在资源使用情况中。Cell 可能会因为操作员正在对其进行维护,或者 cell 数据库遇到问题而无法连接而变得不可用。

我们可以通过查询 placement 和 API 数据库来获取资源使用情况,而不是读取单独的 cell 数据库,从而使配额的资源使用情况统计对临时的 cell 宕机具有弹性。

问题描述

当我们统计 CPU 和 RAM 的配额资源使用情况时,我们通过读取单独的 cell 数据库并汇总结果来执行此操作。每个实例的 CPU 和 RAM 量都来自 flavor,并存储在数据库中作为 instances 表中的列。因此,每次我们检查配额使用情况是否超过限制时,我们都会查询每个 cell 数据库中的实例 ID 计数以及每个 cell 的 CPU 和 RAM 总和,并将它们汇总以计算资源使用情况。

这种方法对临时的 cell 宕机很敏感,这些宕机可能发生在操作员维护期间,或者如果 cell 数据库遇到问题而我们无法连接到它。当 cell 不可用时,我们无法统计驻留在该 cell 数据库中的资源使用情况,并且行为就像有比应该更多的配额可用一样。也就是说,如果有人用完了他们的配额,并且其中的一部分在 cell A 中,而 cell A 暂时离线,那么那个人突然能够分配比其限制更多的资源(假设 cell A 恢复,那个人将分配比其允许的配额更多的资源)。

我们可以采取不同的方法,通过查询 placement API 和 API 数据库来获取资源使用情况计数。由于 placement 正在管理资源分配,因此它拥有我们需要统计 CPU 和 RAM 配额的资源使用情况的信息。通过查询 placement 和 API 数据库,我们可以避免读取单独的 cell 数据库来获取资源使用情况。

用例

从 placement 统计配额资源使用情况将使配额行为在临时的 cell 数据库中断时保持一致。如果需要进行维护,操作员可以更轻松地使 cell 离线,而不必担心可能超过配额限制。它可以省去操作员修复维护期间或无法建立 cell 数据库连接时配额被超过的情况的麻烦。

提议的变更

我们将添加一种新的方法来统计实例,该方法查询 API 数据库中的 instance_mappings 表,并为实例数量进行单独的限制检查。

新方法将包含

  • 一个查询 API 数据库以获取实例资源使用情况。如果我们在 nova_api.instance_mappings 表中添加一个新列 user_id,我们可以获取项目和用户的实例数量。该表已经有一个 project_id 列。这将允许我们统计项目和用户的实例映射以表示实例计数。

我们将把 _instances_cores_ram_count 方法重命名为 _instances_cores_ram_count_legacy,该方法从 cell 数据库中统计核心和 RAM,并且仅在 [quota]count_usage_from_placement 为 False 或数据迁移尚未完成时使用。

由于 placement 尚未提供资源提供者分区功能,为了支持多个 Nova 部署共享同一 placement 服务的情况,例如在 Edge 场景中,我们将添加一个 [quota]count_usage_from_placement 配置选项,默认值为 False。如果为 False,我们将使用实例、核心和 RAM 的传统配额统计方法。如果为 True,我们将使用调用 placement 的配额统计方法。这是一种保持“传统”配额统计方法可用的方法,用于多个 Nova 部署共享一个 placement 服务的情况。该配置选项将简单地控制可插拔配额系统调用哪种统计方法。例如(伪代码)

if CONF.quota.count_usage_from_placement:
    return _instances_cores_ram_count_api_db_placement(...)
else:
    return _instances_cores_ram_count_legacy(...)

我们将添加一种新的方法来从 placement 统计核心和 RAM,该方法在 [quota]count_usage_from_placement 为 True 时使用。该方法可以命名为 _cores_ram_count_placement

新方法将包含

  • 最多向 placement 发起两次调用以获取 CPU 和 RAM 的资源使用情况。一次调用将统计整个项目的使用情况。然后,如果找到资源的基于用户的配额限制,第二次调用将统计整个项目和用户的使用情况。我们可以通过查询 /usages 资源来获取项目和用户的 CPU 和 RAM 使用情况

    GET /usages?project_id=<project id>
    GET /usages?project_id=<project id>&user_id=<user id>
    

备选方案

另一种选择是等到 placement 具有分配分区支持后再开始从 placement 统计任何配额使用情况。该问题的在于,在此期间,我们处理 cell 宕机的唯一解决方案是实现 基于策略的行为,其中操作员必须在项目在宕机的 cell 中具有实例的情况下选择失败服务器创建请求,或者允许服务器创建请求可能超过配额限制。

另一种讨论过的选择是使用 placement 聚合来包围整个 Nova 部署,并将其用作分割 placement 使用情况的一种方式。在这种情况下,我们需要向 placement /usages API 添加一个 aggregate= 查询参数。这种方法还需要 Nova 或操作员的一些工作,以保持 placement 聚合同步。

数据模型影响

需要对 nova_api 数据库模式进行更改,以便将类型为 String 的 user_id 列添加到 nova_api.instance_mappings 表中。

REST API 影响

无。

安全影响

无。

通知影响

无。

其他最终用户影响

即使在 cell 数据库不可用时,最终用户也会看到一致的配额行为。

性能影响

在检查是否需要迁移数据时,将存在性能影响。可以通过缓存指示数据迁移已完成的项目的结果来减少影响,并避免对已迁移的项目进行不必要的检查。

该更改涉及向 placement 发出外部 REST API 调用,而不是并行地将请求分散到所有 cell。如果所有 cell 响应迅速,则发出外部 REST API 调用可能较慢。如果任何 cell 响应缓慢,则发出外部 REST API 调用可能更快。

其他部署者影响

无。

开发人员影响

无。

升级影响

user_id 列添加到 nova_api.instance_mappings 表中需要对所有现有的实例映射进行数据迁移,以填充 user_id 字段。迁移例程将查找 user_id 为 None 的映射,并按映射中的相应 cell_id 查询 cell。该查询可以按实例 UUID 过滤,找到要在映射中填充的 user_id 值。这将实现使用 nova-manage db online_data_migrations 进行批量迁移的方式。

我们将还在访问服务器 GET 请求时动态地修复/填充实例映射。这将提供在尚未运行 nova-manage db online_data_migrations 的情况下进行数据迁移的情况。

为了处理正在进行的实时升级,如果 nova_api.instance_mappings 尚未填充 user_id(如果操作员尚未运行数据迁移),我们需要能够回退到实例、核心和 RAM 的传统计数方法。我们需要一种检测数据迁移尚未运行的方法,以便回退到传统计数方法。我们可以进行如下检查:if exists(InstanceMapping.id) where project_id=<project id> and user_id=None,然后回退到传统计数方法来查询 cell 数据库。我们应该缓存每个 project_id 的迁移完成情况检查的结果,以便避免对已迁移的 project_id 进行不必要的检查。

我们将填充 user_id 字段,即使对于 queued_for_delete=True 的实例映射也是如此,因为这些实例映射包括 SOFT_DELETED 的实例,并且这些实例可以在未来随时恢复。如果我们不迁移具有 queued_for_delete=TrueSOFT_DELETED 实例,并且它们在未来被恢复,那么它们的实例映射将未迁移,并且将阻止我们最终删除相关的数据迁移代码。

数据迁移和回退到传统计数方法将在 Train 版本中是临时的,将在 U 或 V 版本中通过一个阻止性迁移删除。也就是说,如果 nova_api.instance_mappings 中存在任何 user_id=None 的实例映射,则无法通过 nova-manage 运行 nova-manage api_db sync,以强制使用 nova-manage 进行批量迁移。

实现

负责人

主要负责人

melwitt

其他贡献者

工作项

  • nova_api.instance_mappings 表中添加 user_id 列。

  • 实施在线数据迁移以填充 user_id 字段。

  • 更新 _server_group_count_members_by_user 配额计数方法,以仅使用 nova_api.instance_mappings 表,而不是查询 cell 数据库。

  • 添加配置选项 [quota]count_usage_from_placement,默认值为 False。当 placement 中资源提供者的分区可用,并且 Nova 中的 placement 资源分配的其它问题得到解决时(例如:调整大小期间的“加倍”分配),可以弃用此选项。

  • 添加一种新的方法来统计实例,该方法通过过滤 project_id=<project_id>user_id=<user_id> 以及 queued_for_delete=False 来统计 nova_api.instance_mappings 的数量。

  • 添加一种新的计数方法,该方法查询 placement API 以获取 CPU 和 RAM 使用情况。在新计数方法中,添加一个检查,以查看是否已运行在线数据迁移,如果未运行,则回退到传统计数方法。

  • _instances_cores_ram_count 方法重命名为 _instances_cores_ram_count_legacy,并让它仅以传统方式统计核心和 RAM,用于 [quota]count_usage_from_placement 为 False 或数据迁移尚未完成的情况。

  • 调整 nova-next CI 作业,使其以 [quota]count_usage_from_placement=True 运行。

依赖项

无。

测试

将包含单元测试和功能测试,以测试新功能。我们还将调整一个 CI 作业(nova-next),使其以 [quota]count_usage_from_placement=True 运行,以确保我们对该路径具有集成测试覆盖率。

文档影响

将更新 Cells v2 警告 的文档,以更新有关在一个或多个 cell 不可访问时无法正确计算配额使用情况的段落。我们将记录从 Train 开始,有新的部署选项。

参考资料

这建立在 Pike 版本中重新设计配额以统计资源所做的工作之上。

这可能还会无意中修复一个我们遇到的错误,即如果在 conductor 检查期间“重新检查”配额检查失败,并且请求是多创建请求,那么所有服务器都会进入 ERROR 状态,等待用户清理。由于此更改将统计实例映射以进行实例计数,而实例映射的生命周期几乎与构建请求相同[*],因此如果它们在 conductor 中失败了配额“重新检查”,我们不应该看到多创建服务器进入 ERROR 状态的行为。

历史

修订

发布名称

描述

Stein

引入

Train

重新提出