细粒度资源请求语法

https://blueprints.launchpad.net/nova/+spec/granular-resource-requests

随着 通用嵌套资源提供者 逐渐完善并得到应用,能够表达

  • 需求 1:请求分配特定资源类,并带有特定的一组特征;以及请求分配相同资源类,但带有不同的一组特征。

  • 需求 2:确保某些资源的请求从相同资源提供者分配(亲和性)。

  • 需求 3:确保某些资源的请求从不同资源提供者分配(反亲和性)。

  • 需求 4:在高度饱和的情况下,能够在多个资源提供者之间分散分配实际上是相同资源的分配(“任意匹配”)。

本规范尝试通过在 flavor extra_specs 和 GET /allocation_candidates Placement API 中的资源和特征键上使用编号语法来解决这些需求。

注意

本文档在全文中使用“RP”作为“资源提供者”的缩写。

问题描述

到目前为止,对于通用和嵌套资源提供者和特征,只能请求具有单个特征块的单个资源块。更具体地说

  • 资源只能表示为单个资源类的整数计数。没有办法表达第二个resource_class:count 与相同的资源类。

  • 所有指定的特征都适用于所有请求的资源。没有办法将某些特征应用于某些资源。

  • 给定资源类的所有资源都从同一个 RP 分配。

下面的 用例 举例说明了在这些限制下无法表达的场景。

用例

考虑以下硬件表示(“接线图”)

+-----------------------------------+
|                CN1                |
+-+--------------+-+--------------+-+
  |     NIC1     | |     NIC2     |
  +-+---+--+---+-+ +-+---+--+---+-+
    |PF1|  |PF2|     |PF3|  |PF4|
    +-+-+  +-+-+     +-+-+  +-+-+
       \      \__   __/      /
        \        \ /        /
        |         X         |
        |    ____/ \____    |
        |   /           \   |
      +-+--+-+         +-+--+-+
      | NET1 |         | NET2 |
      +------+         +------+

假设这在 Placement 中建模为

RP1 (represents PF1):
{
    SRIOV_NET_VF=16,
    NET_EGRESS_BYTES_SEC=1250000000,  # 10Gbps
    traits: [CUSTOM_NET1, HW_NIC_ACCEL_SSL]
}
RP2 (represents PF2):
{
    SRIOV_NET_VF=16,
    NET_EGRESS_BYTES_SEC=1250000000,  # 10Gbps
    traits: [CUSTOM_NET2, HW_NIC_ACCEL_SSL]
}
RP3 (represents PF3):
{
    SRIOV_NET_VF=16,
    NET_EGRESS_BYTES_SEC=125000000,  # 1Gbps
    traits: [CUSTOM_NET1]
}
RP4 (represents PF4):
{
    SRIOV_NET_VF=16,
    NET_EGRESS_BYTES_SEC=125000000,  # 1Gbps
    traits: [CUSTOM_NET2]
}

用例 1

作为 Operator,我需要能够表达一个实例的启动请求,该请求具有一个 SR-IOV VF 在物理网络 NET1 上,以及第二个 SR-IOV VF 在物理网络 NET2 上

我期望调度器接收到以下分配候选:

  • [RP1(SRIOV_NET_VF:1), RP2(SRIOV_NET_VF:1)]

  • [RP1(SRIOV_NET_VF:1), RP4(SRIOV_NET_VF:1)]

  • [RP3(SRIOV_NET_VF:1), RP2(SRIOV_NET_VF:1)]

  • [RP3(SRIOV_NET_VF:1), RP4(SRIOV_NET_VF:1)]

这展示了在单个请求中从不同提供者获取相同资源类的不同分配的能力(需求 1)。

用例 2

请求:一个 VF 带 10000 字节/秒的出站带宽。(不,我不关心我在哪个 physnet 上 - 如果这让你困扰,请在脑海中将 NET 替换为 SWITCH。)

期望:

  • [RP1(SRIOV_NET_VF:1), RP1(NET_EGRESS_BYTES_SEC:10000)]

  • [RP2(SRIOV_NET_VF:1), RP2(NET_EGRESS_BYTES_SEC:10000)]

  • [RP3(SRIOV_NET_VF:1), RP3(NET_EGRESS_BYTES_SEC:10000)]

  • [RP4(SRIOV_NET_VF:1), RP4(NET_EGRESS_BYTES_SEC:10000)]

这展示了确保不同资源类的分配可以从相同资源提供者进行的能力(需求 2)。

用例 3

请求

  • NET1 上的一个 VF,带宽为 10000 字节/秒

  • NET2 上的一个 VF,带宽为 20000 字节/秒,在具有 SSL 加速的 NIC 上(这个应该始终落在 RP2 上)。

期望:

* [RP1(SRIOV_NET_VF:1, NET_EGRESS_BYTES_SEC:10000),
RP2(SRIOV_NET_VF:1, NET_EGRESS_BYTES_SEC:20000)]
* [RP3(SRIOV_NET_VF:1, NET_EGRESS_BYTES_SEC:10000),
RP2(SRIOV_NET_VF:1, NET_EGRESS_BYTES_SEC:20000)]

这展示了同时满足 需求 1需求 2

用例 4

在高可用性场景中,请求在 NET1 上有两个 VF,来自不同的 PF。

期望:

  • [RP1(SRIOV_NET_VF:1), RP3(SRIOV_NET_VF:1)]

是以下任何一个:

  • [RP1(SRIOV_NET_VF:2)]

  • [RP3(SRIOV_NET_VF:2)]

这展示了 需求 3

用例 5

作为 Operator,我需要能够表达一个请求,请求超过一个 VF,并且即使我的 PF 几乎饱和,请求也能成功。对于此用例,假设每个 PF 资源提供者只有两个未分配的 VF。我需要能够表达一个请求,请求NET1 上的四个 VF

期望:[RP1(SRIOV_NET_VF:2), RP3(SRIOV_NET_VF:2)]

这展示了 需求 4

提议的变更

编号请求组

使用现有的语法(一旦 依赖项 落地),资源请求可以逻辑地表示为

resources = { resource_classA: rcA_count,
              resource_classB: rcB_count,
              ... },
required = [ TRAIT_C, TRAIT_D, ... ]

语义上,每个生成的分配候选将由 resource_classN: rcN_count 资源任意地分布在同一树(即单个分配候选中的所有资源提供者将具有相同的 root_provider_uuid)内的资源提供者之间。每个分配候选中的每个资源提供者都将拥有列出的所有 required 特征。

注意

当共享资源提供者完全实现时,上述内容将变为,“... 任意地分布在同一树或聚合内的资源提供者之间”。

此外,不支持重复资源类或特征。

提出的更改是通过以下方式增强上述内容,以包含编号的资源分组

逻辑表示

resources = { resource_classA: rcA_count,
              resource_classB: rcB_count,
              ... },
required = [ TRAIT_C, TRAIT_D, ... ],

resources1 = { resource_class1A: rc1A_count,
               resource_class1B: rc1B_count,
               ... },
required1 = [ TRAIT_1C, TRAIT_1D, ... ],

resources2 = { resource_class2A: rc2A_count,
               resource_class2B: rc2B_count,
               ... },
required2 = [ TRAIT_2C, TRAIT_2D, ... ],

...,

resourcesX = { resource_classXA: rcXA_count,
               resource_classXB: rcXB_count,
               ... },
requiredX = [ TRAIT_XC, TRAIT_XD, ... ],

group_policy = "none"|"isolate"

语义

下面“结果”一词指的是 GET /allocation_candidates 响应中的 allocation_requests 列表中的一个项目的内容。

  • (单个)未编号分组的语义未更改。也就是说,它仍然可以从同一树(或者,当“共享”完全实现时,同一聚合)中的不同 RP 返回结果。

  • 但是,编号组将始终从相同 RP 返回结果。这是为了满足 需求 2

  • 使用 group_policy=none 时,单独的组(编号或未编号)可以从不同的 RP相同的 RP 返回结果(假设隔离性没有通过特征或库存/使用限制强制执行)。

  • 使用 group_policy=isolate 时,保证编号请求组由不同的 RP 满足。这仅适用于编号请求组。也就是说,未编号组中的资源仍然可以由树(或聚合)中的任何 RP 提供;并且未编号组和编号组之间没有限制。

  • 当指定多个编号组时,需要 group_policy 选项;省略它将导致 400 错误。

  • 仍然不支持在给定的(编号或未编号)resources 分组中重复资源类,但从一个分组到另一个分组重复资源类没有限制。特征也是如此。这是为了满足 需求 1

  • 给定的 requiredN 列表仅应用于其匹配的 resourcesN 列表。这同样适用于未编号的 required/resources

  • 数字后缀是任意的。除了将 resourcesN 绑定到 requiredN 之外,它们没有隐含的含义。特别是,它们不需要是顺序的;并且它们的顺序没有语义意义。

  • 对于编号和未编号的 resources,单个resource_class:count 将永远不会拆分到多个 RP 上。虽然对于例如 VF 来说,这种拆分可能是合理的,但对于例如 DISK_GB 来说,显然是无效的。如果您想能够拆分,请使用单独的编号组。这满足 需求 4

  • 指定 resources(编号或未编号)而不提供相应的 required 会返回未经过滤的特征的结果。

  • 指定 required(编号或未编号)而不提供相应的 resources 是一个错误。

Flavor 中的语法

参考 逻辑表示,现有(一旦 依赖项 落地)实现是在 flavor extra_specs 中指定 resourcesrequired 特征如下

  • resources 的每个成员都指定为单独的 extra_specs 条目,格式为

resources:resource_classA=rcA_count
  • required 的每个成员都指定为单独的 extra_specs 条目,格式为

trait:TRAIT_B=required

例如

resources:VCPU=2
resources:MEMORY_MB=2048
trait:HW_CPU_X86_AVX=required
trait:CUSTOM_MAGIC=required

提议: 允许通过将编号附加到 resourcestrait 关键字来使用相同的语法进行编号的资源和特征分组

resourcesN:resource_classC=rcC_count
traitN:TRAIT_D=required

可以在相同的分组(编号或未编号)中重复给定的编号 resourcestrait 键,就像使用未编号的语法一样。

通过 group_policy 键指定组间亲和性策略,该键可以具有以下值:

  • isolate:不同的编号请求组将由不同的提供者满足。

  • none:不同的编号请求组可以由不同的提供者公共提供者满足。

例如

resources:VCPU=2
resources:MEMORY_MB=2048
trait:HW_CPU_X86_AVX=required
trait:CUSTOM_MAGIC=required
resources1:SRIOV_NET_VF=1
resources1:NET_EGRESS_BYTES_SEC=10000
trait1:CUSTOM_PHYSNET_NET1=required
resources2:SRIOV_NET_VF=1
resources2:NET_EGRESS_BYTES_SEC:20000
trait2:CUSTOM_PHYSNET_NET2=required
trait2:HW_NIC_ACCEL_SSL=required
group_policy=isolate

Placement API 中的语法

参考 逻辑表示,现有(一旦 依赖项 落地)Placement API 实现是通过 GET /allocation_candidates 查询字符串如下

  • resources 分组在一个名为 resources 的单个键下,其值为以逗号分隔的 resource_classN:rcN_count 列表。

  • 特征分组在一个名为 required 的单个键下,其值为以逗号分隔的TRAIT_Y 列表。

例如

GET /allocation_candidates?resources=VCPU:2,MEMORY_MB:2048
    &required=HW_CPU_X86_AVX,CUSTOM_MAGIC

提议: 允许通过将编号附加到 resourcesrequired 关键字来使用相同的语法进行编号的资源和特征分组,并要求在给出多个编号分组时指定 group_policy。在以下示例中,组 1 和 2 表示 用例 3

GET /allocation_candidates?resources=VCPU:2,MEMORY_MB:2048
    &required=HW_CPU_X86_AVX,CUSTOM_MAGIC
    &resources1=SRIOV_NET_VF:1,NET_EGRESS_BYTES_SEC:10000
    &required1=CUSTOM_PHYSNET_NET1
    &resources2=SRIOV_NET_VF:1,NET_EGRESS_BYTES_SEC:20000
    &required2=CUSTOM_PHYSNET_NET2,HW_NIC_ACCEL_SSL
    &group_policy=none

以下示例演示了 group_policy=isolate 的使用,并通过确保两个 VF 来自不同的提供者来代表 用例 4,即使它们在其他方面是相同的

GET /allocation_candidates
    ?resources1=SRIOV_NET_VF:1
    &required1=CUSTOM_PHYSNET_NET1
    &resources2=SRIOV_NET_VF:1
    &required2=CUSTOM_PHYSNET_NET1
    &group_policy=isolate

响应负载的语法没有变化。

备选方案

  • 需求 2 也可以通过聚合来表达,通过将每个 RP 与唯一的聚合关联起来,一旦共享资源提供者完全实现。

  • 我们可以允许“number”后缀为任何任意字符串。但是,使用整数易于理解和验证,并且消除了对转义/编码特殊字符的担忧等问题。

  • 随着时间的推移,人们一直在讨论是否需要基于 JSON 负载的 API 来实现更丰富的表达式,以请求分配候选对象。虽然这仍然是未来的可能性,但考虑到当前需求可以通过对现有 GET /allocation_candidates API 的查询字符串语法进行相对简单的增强来满足,因此在本例中认为没有必要。

  • 关于如何满足反亲和性(需求 3)和“任意匹配”(需求 4)进行了大量讨论。有关详细信息,请参阅 separate_providers 提案can_split 提案邮件列表主题

数据模型影响

无。

REST API 影响

请参阅 Placement API 中的语法。 总结一下,GET /allocation_candidates Placement API 被修改为接受格式为 resourcesNrequiredN 的任意查询参数键,其中 N 可以是任何整数。这些查询参数的值的格式与 resourcesrequired 的格式相同。

否则,REST API 没有影响。

安全影响

通知影响

其他最终用户影响

操作员需要理解 Flavor 中的语法 和更改的 语义,以便创建利用新功能的 flavor。请参阅 文档影响

nova 或 openstack CLI 没有影响。现有的 CLI 语法足以表达新支持的 extra_specs 键。

性能影响

使用新语法会导致 GET /allocation_candidates Placement API 实际上对每个请求执行多次查找。这可能会通过一个因子 N+1 影响数据库性能,其中 N 是给定请求中指定的编号资源分组的数量。巧妙的 SQL 表达式可以减少或消除这种影响。

由于此功能不应导致 GET /allocation_candidates API 返回的记录数量显著增加(如果任何情况,增加的特异性将减少结果数量),因此对数据库之外没有影响。

其他部署者影响

开发人员影响

提供资源提供者表示的模块的开发人员需要了解此功能,以便适当地建模他们的 RP。

升级影响

实现

负责人

  • efried

工作项

实现工作始于 Queens。已经合并了几个补丁;其余补丁已经开始,但正在等待依赖项。

https://review.openstack.org/#/q/project:openstack/nova+branch:master+topic:bp/granular-resource-requests

调度器

  • Placement API 协商微版本功能。

  • 识别并解析新的 Flavor 中的语法

  • 如果识别了新的 flavor extra_specs 语法,并且 Placement API 不具备适当的微版本,则报错。

  • 根据 flavor extra_specs 构建 GET /allocation_candidates 查询字符串。

  • GET /allocation_candidates 请求发送到 Placement,如果正在使用新语法,则指定适当的微版本。

Placement

  • 发布一个新的微版本。

  • 如果以新的微版本调用,则识别并解析新的 GET /allocation_candidates 查询字符串键格式。

  • 构建适当的数据库查询/查询。

  • 其他一切保持不变。

依赖项

这项工作建立在重新批准和完成 嵌套资源提供者 工作的基础上。

测试

将添加功能测试,包括 gabbits,以测试新的语法。可能需要新的 fixtures 来表达一些更复杂的配置,特别是涉及嵌套资源提供者的配置。将设计测试用例来证明 语义 中列出的项目各种组合和排列。例如,使用编号和未编号分组的 GET /allocation_candidates 请求,针对包含多个嵌套资源提供者树(具有三级或更多级)且涉及 trait 传播的 placement 服务。

文档影响

参考资料

历史

修订版

发布名称

描述

Queens

引入,批准,实施开始

Rocky

重新提出