使用统一限制

本文档包含有关 OpenStack 项目使用 Keystone 的统一限制功能的指南和规则。此处列出的项目基于现有的实际实施,旨在帮助确保其他迁移到此模型的项目之间的一致性。虽然本文档假定读者了解 keystone 统一限制 文档的内容,但为了保持一致性,此处会再次介绍一些概念。

概述

Keystone 提供了一种“限制”功能,它实际上是项目关联的命名数值资源最大值的集中存储库。每个资源限制都“注册”到 Keystone,并赋予一个默认值,该值可以被项目级别的不同值覆盖。

现有的项目内配额 API 通常在从 Keystone 中删除项目时没有清理过程。此外,一些 API 在记录新限制时也不会验证项目标识符,这会导致进一步的混乱。实施任何类型的复杂层次结构或继承需要大量关于项目关系的信息,而这些信息是 Keystone 的责任。

为什么要将这些存储在 Keystone 中?

Keystone 拥有“项目”的定义,因此项目是在 Keystone 中创建和销毁的。由于限制(即配额)与项目相关联,因此对于其他服务(例如 Nova、Glance、Cinder、Neutron)来说,避免在其数据库中积累过时的限制信息可能很困难,因为它们不会在项目删除时收到通知。

将限制信息存储在 Keystone 中意味着可以与项目一起清理限制,还可以将关于层次结构的丰富信息应用于动态限制的计算。它将资源限制放置在所限制内容的主要键附近。

所以 Keystone 实现了配额?

Keystone 不实现配额,而是实现限制。对于本文档而言,可以将配额视为“资源上的限制”和“当前正在使用的资源量”的元组。配额是通过在尝试进行新的资源分配时将当前使用量与允许量进行比较来执行的。例如,像 Cinder 这样的服务在请求新的分配时,通过将当前分配与限制进行比较来实施磁盘使用量的配额,然后决定是否应授予该请求。

Keystone 不存储或关心当前分配的资源量,它只存储限制:允许的最大量。由拥有资源的的服务来决定是否允许资源分配,通过将消耗量与限制进行检查来决定。Oslo 库接口为此提供了一种简便的方法。

这是否仅与可分配或可配额的资源相关?

关于配额的重要一点是,所有配额都涉及限制,但并非所有限制都意味着配额。限制可用于非配额用途,例如“每个实例的最大元数据项数”或“最大并行上传请求数”。这些情况通常使用适用于所有服务用户静态配置值来实现。通过通过 Keystone 实现这些限制,可以覆盖每个项目的特定限制。

涉及的参与者

为了在 Keystone 中实现限制,提供了 oslo.limit 库,并且消费者应使用它。该库提供了一个接口,可以有效地从 Keystone 查询限制,通常提供一种驱动配额的工作流程,在大多数情况下可以直接应用。通过限制库查询的限制在使用前必须注册,因此大多数项目需要 devstack 更改以确保注册发生。

指南

缓存

由于查找 Keystone 中的限制涉及发出网络请求,因此可能会增加 Keystone 服务器和网络的负载。这有利于缓存结果,但此类工作应限制在范围内。最好避免将单个结果缓存超过单个请求的范围,以避免破坏管理员降低或提高限制并立即看到结果的能力。

一个仍然限制在单个请求中的较长寿命结果缓存示例是 Glance 镜像上传场景。在消耗无界镜像流时,我们需要查找一次限制并将其应用于流(或结果),而无需每读取一个块或任何类似频率地命中 Keystone。

使用 Enforcer

oslo.limit 库提供了一个 Enforcer 类,用于类似配额的行为,应尽可能使用它。该类允许批量驱动的方法,其中提供多个命名资源以及计算当前使用量的函数,然后将其与限制进行比较以确定是否应允许资源分配操作。虽然可能只想查找限制并以不同的方式执行强制执行(并且在某些情况下可能没有替代方案),但应尽可能使用标准强制执行例程。这有助于确保一致地应用“当前 + 请求 >= 限制”行为,以及标准化的错误消息。

此外,Enforcer 尝试强制用户采用面向批处理的方法以节省与 Keystone 的往返次数。库的消费者应尽可能遵守此行为。

计算当前使用量

在一些 OpenStack 项目中,早期的配额实现侧重于配额限制和当前使用量的单独的会计记录。这些表旨在准确跟踪实际使用量,以及临时预留以提供严格的配额执行。在实践中,它们通常与现实脱节,需要手动清理和调整。许多项目已经转向以一种可以轻松有效地计算运行时确定当前使用量的方式来组织数据结构。在配额执行中偏离一个,与潜在的与实际消耗严重不同之间,通常更倾向于前者。事实上,oslo.limit 中的 Enforcer 模式接收函数,这些函数用于计算当前使用量,建议这些函数的实现实时进行计算,而不是仅仅查找会计表。

保留标准化的错误消息

oslo.limit 库提供了一个 Enforcer 类和标准化的错误消息,用于超出限制的情况。这些采用一种常见的形式,解释哪个(命名的)限制将被超出,限制是什么,以及当前使用量和尝试分配的量。当前实现配额的项目可能会倾向于保留自己的错误消息以实现兼容性,但建议改为转向使用标准化的消息。这将有助于跨项目的保持一致性,并帮助用户和操作员更好地理解错误。

全部或无

建议如果应用任何统一限制,则应应用所有限制。这意味着,允许启用或禁用配额/限制检查是没问题的,或者为正在过渡的项目启用“内部限制”与“Keystone 中的限制”。但是,建议如果使用 Keystone 中的任何限制,则使用所有限制。禁用单个配额,或者允许某些配额由 Keystone 中的限制强制执行,而其他配额由内部/遗留来源强制执行,这会让人困惑。Keystone 中的资源限制可以设置为“无限制”,建议使用这种限制而不是单个项目启用/禁用标志。

使用 API

具有现有配额系统的项目可能已经为他们的用户公开了 API,以检查资源的限制和使用情况。这些 API 应该维护为暴露使用量和限制信息,但如果使用统一限制,则从 Keystone 中提取限制信息。他们不应该尝试通过代理回 Keystone 来维护与配额(限制)管理完全兼容。当使用统一限制时,这些 API 在大多数情况下应变为只读(至少在限制方面)。对于那些没有为此目的的遗留 API 的项目,应该在必要时实现它们以实现适当的用户行为。

Keystone 不了解资源消耗,因此无法向用户提供有关它的信息。此外,资源限制信息不一定是用户通过直接与 Keystone 交互而被允许查看的内容。即使他们可以,要求他们在某个地方查找他们的限制,并在另一个地方查找他们的消耗量也不是很友好。因此,建议项目实现配额/使用 API,以便在一个地方提供限制和消耗信息。

有关非常简单的使用 API 的示例,请查看 Glance 实现。在没有现有 API 或有理由做不同的事情的情况下,此 API 应该作为新使用 API 的模板,以保持一致性。

迁移到统一限制

具有现有内部配额系统的项目在迁移时应提供一个配置标志,以在“内部”和“统一”限制之间切换。对于仅从头开始使用统一限制的新配额功能增长的项目,也可能需要一个配置标志来启用或禁用配额检查,以提供一个优雅的入门坡道。

以下通用步骤集可能有助于规划工作

  1. 添加一个配置控件,以允许在现有的配额系统和统一限制之间切换(或如果不存在则启用统一限制)。

  2. 重构现有的或实现新的配额检查代码,以便在资源分配请求期间启用时从 Keystone 通过 oslo.limit 提取限制。

  3. 重构现有的或实现新的配额使用 API,以暴露有关当前资源消耗和限制的信息。

  4. 扩展 devstack 以支持定义资源限制和为项目的测试作业定义合理的默认值。

  5. 添加或扩展现有的 tempest 测试以验证配额执行

  6. 记录您的用户的此功能,包括有关何时删除现有配额功能的信息,以及有关将现有限制迁移到 Keystone 的说明。