Placement API 中的 QoS 最小带宽分配

https://bugs.launchpad.net/neutron/+bug/1578989

本规范描述了 Neutron 如何在 Placement API 中建模新的资源提供者,以描述带宽分配。

问题描述

目前,有几个参数(定量和定性)定义了 Nova 服务器,并用于选择正确的宿主机和网络后端设备来运行它。网络带宽尚未包含在这些参数中。这允许物理网络设备可能被过度订阅的情况。

本规范解决了管理第一个物理设备上的带宽问题,即最靠近 nova 服务器的物理接口。管理更远处的带宽,例如在机架顶端交换机的背板或端到端,超出了本文档的范围。

保证带宽通常涉及在两个层面执行约束。

  • placement:在放置(调度)nova 服务器及其端口时避免过度订阅。

  • 数据平面:在物理网络设备上强制保证。

本规范仅解决 placement 强制执行。 (数据平面强制执行在 [4] 中涵盖。)但是,设计必须尊重用户对这些强制执行的联合使用的兴趣。

由于 placement 强制执行本身是 Nova-Neutron 跨项目功能,因此本规范旨在与 Nova 的对应规范一起阅读、评论和维护:网络带宽资源提供者 [2]

本规范基于已批准的 Neutron 规范 添加严格最小带宽支持的规范 [3]。 本规范的目的不是重新定义 [3] 中已批准的内容,而是指定如何在 Neutron 中实现它。

用例

最直接的用例是,用户为保证最小网络带宽的优质服务付费,希望启动 Nova 服务器。 调度器需要知道每个计算宿主机中的每个物理网络设备上已经使用了多少带宽,以及用户请求了多少带宽。

仅数据平面强制执行已合并到 Newton 中,用于 SR-IOV 出站 (参见 Newton Release Notes [6])。

仅 placement 强制执行对于能够控制所有流量的用户来说可能是一个可行的功能(例如,在单个租户私有云中)。 这种仅 placement 强制执行也可以与带宽限制规则一起使用。 管理员可以在 QoS 策略中设置两个规则,两者都具有相同的带宽值,然后该计算宿主机上的每个服务器都能够使用最多其保证的带宽。

提议的变更

  1. 用户必须能够表达端口的资源需求。

    1. 扩展 qos_minimum_bandwidth_rule 以支持入站方向。

      与数据平面中的强制执行不同,Placement 可以以相同的努力处理两个方向。

    2. qos_minimum_bandwidth_rule 标记为每个现有 QoS 驱动程序支持的 QoS 策略规则。

      Placement 强制执行与后端机制无关。 用户可以使用尚未具有数据平面强制执行(但可能很快会具有)的驱动程序进行 placement 强制执行。

    由于我们已经向最终用户公开了(并且可能希望进一步公开)此开发工作的部分结果,因此 qos_minimum_bandwidth_rule 的含义取决于 OpenStack 版本、Neutron 后端驱动程序和规则的方向。 规则可能由 placement 和/或数据平面强制执行。 因此,我们必须记录,除了 QoS devref [10] 中已有的支持矩阵之外,哪些版本的组合、驱动程序、规则方向以及(placement 和/或数据平面)强制执行是受支持的。

    由于 Neutron 对后端的选择对云用户隐藏,部署者还必须清楚地记录适用于特定部署中云用户的上述支持矩阵的子集。

  2. Neutron 必须将端口的资源需求传达给 Nova。

    扩展端口以包含属性 resource_request,如以下“如何对 Neutron 端口建模所需的带宽”部分所述。 此属性是计算得出的、只读的且仅供管理员访问的。

    在端口创建时(即在端口绑定之前)可用的信息必须足以生成 resource_request 属性。

    端口扩展必须与 ML2 解耦,并保留在 QoS 服务插件中。 一种方法是像 trunk_details 使用它一样使用 neutron.db._resource_extend

  3. Neutron 必须用可用的资源填充 Placement DB。

    使用 Placement API [1] 向 Placement 服务报告有关可用资源的信息。 即有关物理网络设备、其 physnets、可用带宽和受支持的 VNIC 类型的信息。

    云管理员必须能够通过配置控制向 Placement 报告的内容。 为了简化配置工作,可以使用自动发现网络设备,但管理员必须能够覆盖其结果。

将跟踪哪些设备和参数

即使在计算宿主机内部,也可能存在许多网络拓扑。 例如

  1. OVS 代理:物理网络 - OVS 桥接 - 单个物理 NIC(或绑定):物理网络和物理接口之间的 1:1 映射

  2. SR-IOV 代理:物理网络 - 一个或多个 PF:物理网络和物理接口之间的 1:n 映射(参见 Networking Guide: SR-IOV [7]。)

每个 Neutron 代理(Open vSwitch、Linux Bridge、SR-IOV)都有一个配置参数,用于将物理网络映射到一个或多个提供者接口(SR-IOV)或连接到提供者接口的桥接(Open vSwitch 或 Linux Bridge)。

OVS 代理配置

[ovs]
# bridge_mappings as it exists already.
bridge_mappings = physnet0:br0,physnet1:br1

# Each right hand side value in bridge_mappings:
#   * will have a corresponding resource provider created in Placement
#   * must be listed as a key in resource_provider_bandwidths

resource_provider_bandwidths = br0:EGRESS:INGRESS,br1:EGRESS:INGRESS

# Examples:

# Resource provider created, no inventory reported.
resource_provider_bandwidths = br0
resource_provider_bandwidths = br0::

# Report only egress inventory in kbps (same unit as in the QoS rule API).
resource_provider_bandwidths = br0:1000000:

# Report egress and ingress inventories in kbps.
resource_provider_bandwidths = br0:1000000:1000000

# Later we may introduce auto-discovery (for example via ethtool).
# We reserve the option to make auto-discovery the default behavior
# when it is implemented.
resource_provider_bandwidths = br0:auto:auto

SR-IOV 代理配置

[sriov_nic]
physical_device_mappings = physnet0:eth0,physnet0:eth1,physnet1:eth2

resource_provider_bandwidths = eth0:EGRESS:INGRESS,eth1:EGRESS:INGRESS

如何对 Neutron 端口建模所需的带宽

所需的端口网络带宽通过定义 QoS 策略以及一个或多个 QoS 最小带宽规则 [4] 进行建模。 但是,Nova 或 Placement 都不知道任何 QoS 策略规则。 Neutron 将端口的资源需求转换为描述所需资源类、数量和特征的标准端口属性。

在本规范中,我们假设单个端口从单个 RP 请求资源。 稍后,我们可能会允许端口从多个 RP 请求资源。

端口所需资源通过扩展端口的以下新属性 resource_request 表达。

图:端口中的 resource_request

{"port": {
    "status": "ACTIVE",
    "name": "port0",
    ...
    "device_id": "5e3898d7-11be-483e-9732-b2f5eccd2b2e",
    "resource_request": {
        "resources": {
            "NET_BW_IGR_KILOBIT_PER_SEC": 1000,
            "NET_BW_EGR_KILOBIT_PER_SEC": 1000 },
        "required": ["CUSTOM_PHYSNET_NET0", "CUSTOM_VNIC_TYPE_NORMAL"]}
}}

端口 resource_request 属性将通过名为 port-resource-request 的新 API 扩展来实现。

如果 nova 服务器启动请求定义了端口,并且该端口具有 resource_request 属性,则 Placement 服务必须强制执行最小带宽要求。

如果宿主机具有以下属性,则将满足要求。 首先,对新的 NET_BANDWIDTH_* 资源类进行盘点,并且如“网络 RP 模型”部分所示,有足够的带宽可用。 如果宿主机没有请求的网络带宽资源类别的盘点,它将不会成为调度器的候选对象。 其次,物理网络接口 RP 必须具有与 resource_request 属性的 required 字段中列出的所有特征相关联。

我们建议使用两种自定义特征。 首先,表达和请求对某些 vnic_types 的支持。 此特征使用前缀 CUSTOM_VNIC_TYPE_。 然后将 vnic_type 以大写形式附加。 例如

  • CUSTOM_VNIC_TYPE_NORMAL

  • CUSTOM_VNIC_TYPE_DIRECT

其次,我们将使用特征来确定网络的一个段(由其 physnet 名称标识)是否连接到所考虑的调度中的计算宿主机。 此特征使用前缀 CUSTOM_PHYSNET_。 然后将 physnet 名称以大写形式附加,任何禁止在特征中使用的字符都必须替换为下划线。

例如

  • CUSTOM_PHYSNET_PUBLIC

  • CUSTOM_PHYSNET_NET1

如果 nova 服务器启动请求定义了网络,并且该网络具有 qos_minimum_bandwidth_rule,则该启动请求将失败,如 [2] 的“范围”部分所述,直到 Nova 被重构为提前创建端口(即在调度之前)。 参见 SPEC: Prep work for Network aware scheduling (Pike) [11]

对于多段 Neutron 网络,每个静态段的 physnet 特征必须以我们可以仅在 Placement 支持 any(traits) 请求匹配逻辑后才能指定的格式包含在端口的 resource_request 属性中。 参见 any-traits-in-allocation_candidates-query [9]

报告可用资源

以下部分中描述了一些细节 [2]

  • Neutron 代理首次启动

  • Neutron 代理重启

  • 查找计算 RP

Neutron 内部的细节如下

网络 RP 模型

我们做出了以下假设

  • Neutron 支持 multi-provider 扩展,因此单个逻辑网络可能映射到多个 physnet。 非动态段的 physnets 在端口绑定之前是已知的。 为了本规范的简单起见,我们假设直接连接到具有最小带宽保证的物理接口的每个段都是非动态段。 因此,这些 physnets 可以包含在端口的 resource_request 属性中作为特征。

  • 多个 SRIOV 物理函数 (PF) 可以访问给定计算上的相同 physnet,但这些 PF 始终实现相同的 vnic_type。 这意味着仅使用 Placement 和端口资源请求中的 physnet 特征并不能明确选择一个 PF,但这不是一个问题,因为这两个 PF 从资源分配的角度来看是等效的。

  • 两个不同的后端(例如 SRIOV 和 OVS)可以访问同一计算宿主机上的相同 physnet。 在这种情况下,Neutron 根据用户在端口创建期间指定的 Neutron 端口的 vnic_type 选择后端。 因此,在调度期间的物理设备选择应考虑端口的 vnic_type。 这可以通过先前描述的基于 vnic_type 的特征来完成。

  • 两个不同的后端(例如 OVS 和 LinuxBridge)可以访问同一计算宿主机上的相同 physnet,同时它们也实现相同的 vnic_type(例如 normal)。 在这种情况下,Neutron 中的后端选择是根据管理员在 neutron.conf 中配置的 mechanism_drivers 的顺序完成的。 因此,在调度期间的物理设备选择应考虑相同的首选项顺序。 由于后端顺序只是一个偏好而不是硬性规则,因此支持此行为在本规范中超出范围,但理论上可以通过 nova-scheduler 中的新的 weigher 来实现。

基于这些假设,Neutron 将在 Placement 中构建一个 RP 树,如下所示

图:网络 RP 模型

Compute RP (name=hostname)
 +
 |
 +-------+Network agent RP (for OVS agent), uuid = agent_uuid
 |          inventory: # later, model number of OVS ports here
 |             +
 |             |
 |             +------+Physical network interface RP,
 |             |       uuid = uuid5(hostname:br0)
 |             |         traits: CUSTOM_PHYSNET_1, CUSTOM_VNIC_TYPE_NORMAL
 |             |         inventory:
 |             |         {NET_BW_IGR_KILOBIT_PER_SEC: 10000,
 |             |          NET_BW_EGR_KILOBIT_PER_SEC: 10000}
 |             |
 |             +------+Physical network interface RP,
 |                     uuid = uuid5(hostname:br1)
 |                       traits: CUSTOM_PHYSNET_2, CUSTOM_VNIC_TYPE_NORMAL
 |                       inventory:
 |                       {NET_BW_IGR_KILOBIT_PER_SEC: 10000,
 |                        NET_BW_EGR_KILOBIT_PER_SEC: 10000}
 |
 +-------+Network agent RP (for LinuxBridge agent), uuid = agent_uuid
 |             +
 |             |
 |             +------+Physical network interface RP,
 |                     uuid = uuid5(hostname:virbr0)
 |                       traits: CUSTOM_PHYSNET_1, CUSTOM_VNIC_TYPE_NORMAL
 |                       inventory:
 |                       {NET_BW_IGR_KILOBIT_PER_SEC: 10000,
 |                        NET_BW_EGR_KILOBIT_PER_SEC: 10000}
 |
 +-------+Network agent RP (for SRIOV agent), uuid = agent_uuid
               +
               |
               +------+Physical network interface RP,
               |       uuid = uuid5(hostname:eth0)
               |         traits: CUSTOM_PHYSNET_2, CUSTOM_VNIC_TYPE_DIRECT
               |         inventory:
               |         {VF: 8, # VF resource is out of scope
               |          NET_BW_IGR_KILOBIT_PER_SEC: 10000,
               |          NET_BW_EGR_KILOBIT_PER_SEC: 10000}
               |
               +------+Physical network interface RP,
               |       uuid = uuid5(hostname:eth1)
               |         traits: CUSTOM_PHYSNET_2, CUSTOM_VNIC_TYPE_DIRECT
               |         inventory:
               |         {VF: 8, # VF resource is out of scope
               |          NET_BW_IGR_KILOBIT_PER_SEC: 10000,
               |          NET_BW_EGR_KILOBIT_PER_SEC: 10000}
               |
               +------+Physical network interface RP,
                       uuid = uuid5(hostname:eth2)
                         traits: CUSTOM_PHYSNET_3, CUSTOM_VNIC_TYPE_DIRECT
                         inventory:
                         {VF: 8, # VF resource is out of scope
                          NET_BW_IGR_KILOBIT_PER_SEC: 10000,
                          NET_BW_EGR_KILOBIT_PER_SEC: 10000}

将使用自定义特征来指示给定的物理网络接口 RP 连接到哪个物理网络,如前所述。

将使用自定义特征来指示后端支持哪个 vnic_type,以便区分不同的后端技术,如前所述。

代理RP的当前目的是允许我们检测RP的删除。 稍后我们可能还会开始建模代理级别的资源和能力。

直接或间接报告

仅考虑基于代理的MechanismDrivers,我们有两种选择

  • 直接:代理直接向Placement API报告资源提供者、特性和库存。

  • 间接:代理将资源提供者、特性和库存报告给Neutron-server,后者再将信息报告给Placement API。

两者都有优点和缺点。 直接报告涉及的组件更少,因此效率更高、可靠性更高。 另一方面,资源信息的时效性本身可能很重要。 Nova具有计算心跳机制,以确保调度器仅考虑实时的Placement记录。 如果需要Neutron资源信息的时效性,唯一的实际方法是建立在Neutron-agent心跳机制之上。 否则,报告和心跳机制将采用不同的路径。 如果资源信息通过代理心跳机制报告,则Neutron-server和其他组件(例如nova调度器过滤器)可以从Neutron-server查询资源信息的时效性。

当Placement和nova-scheduler选择在特定的网络资源提供者(代表物理网络接口)上分配请求的带宽时,这种选择会对以下方面产生影响

  • Neutron-server为端口选择Neutron后端。(vif_type, vif_details)

  • Neutron-agent选择物理网络接口。(仅在某些情况下,例如当多个SR-IOV PF支持一个physnet时)

后期的选择(neutron-server和neutron-agent)必须尊重先前的选择(在分配中),否则资源可能会被用于分配之外的地方。

如果知道Neutron-server和Neutron-agent都知道所选网络资源提供者的UUID,则可以使用所选网络资源提供者的UUID将分配中的选择轻松地传达给Neutron。 如果可用资源直接从Neutron-agent报告给Placement,则Neutron-server可能不知道资源提供者UUID。 因此,建议采用间接报告。

即使是间接报告,我们必须尽可能直接地将(Neutron报告的部分)Placement DB的内容置于Neutron代理的控制之下。 最好将Neutron-server保持在基本上是代理的角色中。

报告的资源信息的内容和格式(从代理到服务器)

我们建议扩展代理心跳RPC消息的configurations字段。

除了代理硬编码的支持的vnic_types集合之外,以下代理配置选项是扩展心跳消息的输入

  • bridge_mappingsphysical_device_mappings

  • resource_provider_bandwidths

  • 如果需要,可以进一步控制库存属性的选项,例如:allocation_ratiomin_unitmax_unitstep_sizereserved

基于以上输入,心跳消息的configurations字典应扩展以下键

  • (自定义)traits

  • resource_providers

  • resource_provider_inventories

  • resource_provider_traits

这些值必须在代理配置(重新)读取后(重新)评估。 每个心跳消息应包含代理在该时间点已知的所有项目。 configurations字段的扩展有意镜像Placement API的结构(并且不直接镜像代理配置格式,尽管可以从中派生)。 这些字段的值应格式化为可以直接粘贴到发送到Placement API的请求中。

代理资源提供者应由其已有的Neutron代理UUID标识,如上文“网络RP模型”部分所示。

Neutron-agent应为物理网络接口资源提供者生成UUID。 对于ovs-agent,应使用版本5(基于名称)UUID,通过哈希名称,如HOSTNAME:OVS-BRIDGE-NAME,对于sriov-agent,应使用HOSTNAME:PF-NAME,这样UUID在代理重新启动时将保持稳定。

请注意,代理心跳消息包含特性及其与资源提供者的关联,但代理配置中没有直接列出特性。 这是可能的,因为我们将使用的physnet和vnic_type特性都可以从已知的信息中推断出来。

报告的资源信息同步

理想情况下,Neutron-agent、Neutron-server和Placement必须对资源有相同的视图。 我们建议以下Neutron-server和Placement之间的同步机制

每次Neutron-server了解到新的代理时,它都会将心跳消息(对于特性、提供者、库存和特性关联)与在代理RP下找到的Placement中的所有对象进行差异比较。 它创建Placement中缺少的对象。 它删除心跳中缺少的对象。 它更新Placement和心跳中属性不同的对象。

在接收到后续心跳时,Neutron-server比较新的和前一个心跳。 如果没有变化,则不发送Placement请求。 如果检测到心跳中的变化,Neutron会根据心跳的差异使用上次看到的Placement生成号发送适当的Placement请求。 如果Placement请求成功,Neutron会存储新的生成号。 如果请求因生成冲突而失败,Neutron会退回到Placement和心跳之间的差异比较。

在创建计算主机RP之前,进展或阻塞

Neutron-server在相关Nova-compute主机RP创建之前,无法继续报告资源信息。(原因是Nova-compute主机RP UUID对Neutron来说是不可预测的。) 我们认为,在等待Nova-compute主机RP时,Neutron-server可以继续执行其其他功能。

端口绑定更改

相关操作的顺序如下

  1. Placement DB填充了计算和网络资源信息。

  2. 由nova服务器启动,Placement选择候选列表。

  3. 调度器选择一个候选,并在单个事务中分配它。(在一些复杂的nova服务器移动情况下,conductor可能会分配,但这在这里不重要。)

  4. Neutron绑定端口。

在步骤(2)和(3)中,选择包括代表网络后端对象的RP(除了显而易见的计算主机选择)。 这自然与Neutron当前的端口绑定机制冲突。

为了解决冲突,我们必须确保

  • Placement产生的候选端口稍后可以被Neutron绑定。(至少以与调度器今天能够相同概率。)

  • Placement和Neutron端口绑定所做的选择必须相同。 因此,必须协调选择。

    如果多个Neutron后端可以满足端口的资源要求,并且位于同一主机上,则Placement选择一个,但Neutron绑定另一个的情况不能发生。

    一种方法是让Neutron-server从Placement读取当前正在绑定的端口的分配,并让它影响绑定。 但是,这会在端口绑定的中间引入一个缓慢的远程调用,因此不建议这样做。

    另一种方法是在导致端口绑定PUT请求的调用/消息链中传递分配记录的一部分。 在端口绑定PUT请求中使用binding_profile属性。 这样我们就不需要新的远程调用,只需将参数/有效负载添加到现有的调用/消息中即可。

    Nova规范([2])提出,端口请求的资源包含在编号的请求组中(参见Granular Resource Request Syntax [8])。编号的请求组始终与单个资源匹配。 通常,Neutron需要知道与端口的编号请求组匹配的资源提供者。

    为了表达Placement和nova-scheduler所做的选择,我们建议将allocation条目添加到binding_profile

    {
      "name": "port with minimum bw being bound",
      "id": ...,
      "network_id": ...,
      "binding_profile": { "allocation": RP_UUID }
    }
    

    如果端口具有resource_request属性,则必须提供binding_profile.allocation进行绑定。 否则,不应存在binding_profile.allocation

    通常,ML2端口绑定会按照其配置顺序尝试机制驱动程序,直到一个成功设置绑定。 但是,如果正在绑定的端口具有binding_profile.allocation,则只能尝试单个机制驱动程序 - 隐式由RP_UUID标识的那个。

    在分层端口绑定的情况下,binding_profile.allocation旨在驱动最接近nova服务器的物理接口的绑定级别上的绑定。

超出范围

最小带宽规则更新:当最小带宽规则更新时,ML2插件将列出绑定到此QoS策略和规则的端口,并将更新Allocation值。 consumer_id是每个Allocation的device_id。 这不在本规范的范围内,应在与os-vif迁移任务 [5]相关的工作中完成。

Trunk端口:Trunk端口的子端口对Nova是未知的。 分配子端口的资源是Neutron的任务。 这也超出范围。

测试

  • 单元测试。

  • 功能测试。

    • 代理-服务器交互。

  • 全栈。

    • 处理代理故障情况。

  • Tempest API测试。

    • 扩展带有resource_request的端口API。

    • 扩展binding_profile

  • Tempest场景测试。

    • 端到端功能测试。

在无法依赖Nova的测试框架中,我们可以通过以下方式模拟它

  • 创建并绑定端口,就像Nova会做的那样,包括。

    • 设置其binding_profile

    • 设置其binding_host_id,就像Placement和Scheduler会选择主机一样。

升级

  • 当将具有minimum_bandwidth规则的系统升级以支持数据平面和Placement强制执行时,我们看到两种选择

    1. 管理员有责任为所有使用minimum_bandwidth规则的端口在Placement中创建分配。 请注意:这假设在升级时带宽没有超额分配。

    2. 添加工具,如[2]的“升级影响”部分中所述。

  • 组件的期望升级顺序如下:Placement、Nova、Neutron

    如果出于某种原因,希望采用反向的Neutron-Nova顺序,则在两个组件都升级之前,不应启用Neutron端口API的resource_request扩展。

  • Neutron-server必须能够处理带有和不带有configurations中资源信息的代理心跳。

工作项

这些工作项目旨在使Neutron端到端行为可以独立于Nova相关工作的进度进行原型设计和测试。 但其中一部分依赖于已经可用的Placement功能。

  • 使用资源提供者信息扩展代理心跳配置。

  • (我们已经有了它):通过心跳报告扩展的代理配置持久化。

  • (我们已经有了它):neutron-server的neutron-lib中的Placement客户端。

  • Neutron-server最初将代理报告的资源信息与Placement进行差异比较。

  • Neutron-server比较连续的代理心跳配置。

  • Neutron-server将差异转换为Placement请求(具有生成处理)。

  • 扩展规则 qos_minimum_bandwidth_rule,增加方向 ingress

  • 基于 QoS 规则 mimimum-bandwidth-placement,使用 resource_request 扩展端口。

  • 使报告的 agent 配置可查询,以便 neutron-server 可以推断 RP 分配中隐含的后端(如 binding_profile.allocation)。

  • 在绑定具有 binding_profile.allocation 的端口时,将尝试的机制驱动程序列表替换为推断后端的单元素列表。

  • (我们已经具备):将 binding_profile 发送到所有 agent。

  • 在 sriov-agent 中强制选择 RP 分配所隐含的 PF。

对于以上所有

  • 测试。

  • 文档:api-ref, devref, 网络指南。

  • 发布说明。

参考资料