服务质量 (QoS):保证最小带宽

大多数网络服务质量 (QoS) 功能完全由 OpenStack Neutron 实现,并且已经在网络指南的 QoS 配置章节中进行了记录。一些更复杂 QoS 功能必然涉及云服务器的调度,因此它们的实现由 OpenStack Nova、Neutron 和 Placement 共享。从 OpenStack Stein 版本开始,保证最小带宽功能就像后者一样。

本网络指南章节无意取代 Nova 或 Placement 文档,但仍然希望提供一个整体的 OpenStack 级别指南,以理解和配置部署以使用保证最小带宽功能。

可以强制执行两种级别的最小可用带宽保证

  • 在带宽可用的计算主机的计算节点上调度服务器。更确切地说:在计算主机的物理网络接口上调度服务器的一个或多个端口,这些接口上可用带宽。

  • 在物理网络接口上排队网络数据包,以提供保证的带宽。

简而言之,强制执行有两个级别

  • (服务器) 放置和

  • 数据平面。

由于数据平面强制执行已经在 QoS 章节中记录,因此我们仅记录放置级别强制执行。

限制

  • 启动服务器时,必须传递一个带有 minimum-bandwidth 规则的预创建端口 (openstack server create)。由于技术原因,不支持在启动时传递带有最小带宽规则的网络(在这种情况下,端口创建得太晚,Neutron 无法影响调度)。

  • 在 Stein 中,不支持带有多个 physnet 的网络。但是,一些更简单的多段网络仍然受支持

    • 所有段都具有相同 physnet 名称的网络。

    • 只有单个 physnet 段的网络(其他段是隧道段)。

  • 如果在同一个物理接口上混合使用带有和不带有带宽保证的端口,则没有保证的端口可能会被饿死。因此,不建议混合使用它们。相反,建议使用 Nova 主机聚合 将它们分开。

  • 仅当策略未生效时,才能更改 QoS 策略的保证(添加/删除 minimum_bandwidth 规则,或更改 min_kbps 字段的 minimum_bandwidth 规则)。也就是说,QoS 策略的端口尚未被 Nova 使用。拒绝更改正在使用的策略的保证请求。

  • 从 Wallaby 版本开始,更改带有新的 minimum_bandwidth 规则的端口的 QoS 策略会更改 Placement 的 allocations。如果 VM 是使用没有 QoS 策略和 minimum_bandwidth 规则的端口启动的,则端口更新成功,但 Placement 分配不会更改。如果端口没有 binding:profile,因此没有 Placement 分配记录,则情况也是如此。但是,如果 VM 是使用带有 QoS 策略和 minimum_bandwidth 规则的端口启动的,则更新是可能的,并且 Placement 中的分配也会更改。

注意

可以更新端口以删除 QoS 策略,然后将其更新为具有 minimum_bandwidth 规则,但不会导致 placement allocation 记录,只会发生数据平面强制执行。

注意

仍然无法更改附加到绑定到 VM 的端口的 QoS 策略的 minimum_bandwidth 规则。

  • 首次仅数据平面保证最小带宽实现(用于 SR-IOV 出站流量)是在 Neutron 的 Newton 版本中发布的。由于已知缺乏放置级别强制执行,它被标记为“尽力而为”(第五个要点)。由于未实现放置级别强制执行,带宽可能会被过度分配,并且系统级资源清单可能会变得不一致。因此,对于仅数据平面实现的用户,必须进行迁移/修复过程(参见 修复分配 部分),以使系统级资源清单达到一致状态。现在以不兼容的方式拒绝了会重新引入不一致性的进一步操作(例如,迁移带有 minimum_bandwidth QoS 规则但 Placement 中没有资源分配的服务器)。

  • 保证最小带宽功能在 Stein 版本中并不完整。并非所有 Nova 服务器生命周期操作都可以在具有带宽保证的服务器上执行。从 Stein(Nova API 微版本 2.72+)开始,您可以启动和删除具有保证的服务器,并分离具有保证的端口。从 Train 开始,您还可以迁移和调整具有保证的服务器的大小。稍后将实现对进一步服务器移动操作的支持(例如,撤离、实时迁移和卸载后恢复)。有关权威文档,请参阅 OpenStack Compute API 指南的带有资源请求的端口章节

  • 如果为 neutron-openvswitch-agent 配置了 SR-IOV 物理函数,并且相同的物理函数的虚拟函数为 neutron-sriov-agent 配置,则必须通过管理选择静态地在相应的资源提供程序之间拆分可用带宽。例如,一个 10 Gbps SR-IOV 功能物理 NIC 可以被视为两个独立的 NIC - 一个 5 Gbps NIC(技术上是 NIC 的物理函数)添加到 Open vSwitch 桥接,以及另一个 5 Gbps NIC,其虚拟函数可以由 neutron-sriov-agent 发送给服务器。

  • Neutron 允许 physnet 名称区分大小写。因此,physnet0 和 Physnet0 被视为不同的 physnet。Physnet 映射到 Placement 中的特征以进行调度。但是,Placement 特征不区分大小写并标准化为全大写。因此,调度将 physnet0 和 Physnet0 视为相同的 physnet。建议不要使用仅在大小写上不同的 physnet 名称。

  • 有些硬件平台(例如:Cavium ThunderX)可能存在虚拟函数,这些虚拟函数是与物理函数无关的网络设备。由于带宽资源是按物理函数跟踪的,因此对于此类硬件,无法支持 QoS 最小带宽规则的放置强制执行。使用此类 QoS 策略定位此类硬件后端的服务器创建将导致调度期间出现 NoValidHost 错误。

  • 当 QoS 与 trunk 一起使用时,Placement 强制执行仅应用于 trunk 的父端口。子端口将不会有 Placement 分配。作为解决方法,父端口的 QoS 策略应考虑子端口的需求并请求足够的最小带宽资源以适应 trunk 中的每个端口。

Placement 先决条件

Placement 必须支持 微版本 1.29。这首次在 Rocky 中发布。

Nova 先决条件

Nova 必须支持 微版本 2.72。这首次在 Stein 中发布。

并非所有 Nova virt 驱动程序都受支持,请参阅 Nova 管理指南的 Virt 驱动程序支持章节

Neutron 先决条件

Neutron 必须支持以下 API 扩展

  • agent-resources-synced

  • port-resource-request

  • qos-bw-minimum-ingress

这些都首次在 Stein 中发布。

支持的驱动程序和代理

在 Stein 版本中,以下基于代理的 ML2 机制驱动程序受支持

  • Open vSwitch (openvswitch) vnic_types: normal, direct

  • SR-IOV (sriovnicswitch) vnic_types: direct, macvtap, direct-physical

  • OVN (ovn) vnic_types: normal

注意

SR-IOV (sriovnicswitch) 代理不处理 direct-physical 端口。但是,该代理可以报告将由 direct-physical 端口使用的网络设备的带宽容量。

从 2023.1(Antelope)开始,Open vSwitch 和 OVN 机制驱动程序可以指定隧道网络的可用带宽(SR-IOV 目前不支持这些网络类型)。使用“rp_tunnelled”键来模拟这些不由物理网络支持的网络。该带宽模拟用于发送隧道流量(VXLAN、Geneve)的 VTEP/TEP 接口的限制。

neutron-server 配置

Placement 服务插件将代理的资源提供程序信息从 neutron-server 同步到 Placement。

由于 neutron-server 与 Placement 通信,因此需要配置 neutron-server 如何查找 Placement 并对其进行身份验证。

/etc/neutron/neutron.conf(在控制器节点上)

[DEFAULT]
service_plugins = placement,...
auth_strategy = keystone

[placement]
auth_type = password
auth_url = https://controller/identity
password = secret
project_domain_name = Default
project_name = service
user_domain_name = Default
username = placement

如果多个 ML2 机制驱动程序默认支持 vnic_type(例如,vnic_type=directopenvswitchsriovnicswitch 同时支持),并且多个代理的资源也打算由 Placement 跟踪,则管理员必须决定通过禁止不受欢迎的驱动程序的 vnic_type 来获取该 vnic_type 的端口。在这种情况下,使用 ovs_driver.vnic_type_prohibit_list。有效值是 各自机制驱动程序的 所有 supported_vnic_types

/etc/neutron/plugins/ml2/ml2_conf.ini(在控制器节点上)

[ovs_driver]
vnic_type_prohibit_list = direct

[sriov_driver]
#vnic_type_prohibit_list = direct

neutron-openvswitch-agent 配置

将代理配置设置为资源的真实来源,通过 ovs.resource_provider_bandwidths 按桥接设置配置。格式为:bridge:egress:ingress,... 您可以仅设置一个方向并省略另一个方向。

注意

egress / ingress 是从云服务器的角度来看的。也就是说,egress = 云服务器上传,ingress = 下载。

Egress 和 ingress 可用带宽值以 千比特/秒 (kbps) 为单位。

如果需要,可以通过设置 ovs.resource_provider_inventory_defaults 来调整每个代理的资源提供程序库存字段。有效值是 更新资源提供程序库存调用的可选参数

/etc/neutron/plugins/ml2/ovs_agent.ini(在计算和网络节点上)

[ovs]
bridge_mappings = physnet0:br-physnet0,...
resource_provider_bandwidths = br-physnet0:10000000:10000000,rp_tunnelled:20000000:20000000,...
#resource_provider_inventory_defaults = step_size:1000,...

注意

“rp_tunnelled”不是主机中存在的桥接或接口。ML2/OVS 代理将读取主机本地的“resource_provider_bandwidths”,并默认将“rp_tunnelled”资源提供程序分配给运行它的本地主机。换句话说,不需要将主机分配给此特定资源提供程序。

neutron-sriov-agent 配置

neutron-sriov-agent 的配置与 neutron-openvswitch-agent 类似。但是请注意

  • 如下所示的不同 .ini 部分名称。

  • neutron-sriov-agent 允许 physnet 由多个物理设备支持。

  • 当然,请在 sriov_nic.resource_provider_bandwidths 中引用 SR-IOV 物理函数而不是桥接。

/etc/neutron/plugins/ml2/sriov_agent.ini(在计算节点上)

[sriov_nic]
physical_device_mappings = physnet0:ens5,physnet0:ens6,...
resource_provider_bandwidths = ens5:40000000:40000000,ens6:40000000:40000000,...
#resource_provider_inventory_defaults = step_size:1000,...

OVN chassis 配置

带宽配置值存储在每个 SB chassis 注册中,位于“external_ids:ovn-cms-options”中。配置选项与 SR-IOV 和 OVS 代理中的选项相同。这是注册值的过程

$ root@dev20:~# ovs-vsctl list Open_vSwitch
  ...
  external_ids        : {hostname=dev20.fistro.com, \
                         ovn-cms-options="resource_provider_bandwidths=br-ex:1001:2000;br-ex2:3000:4000;rp_tunnelled:5000:6000, \
                                          resource_provider_inventory_defaults=allocation_ratio:1.0;min_unit:10, \
                                          resource_provider_hypervisors=br-ex:dev20.fistro.com;br-ex2:dev20.fistro.com;rp_tunnelled:dev20.fistro.com", \
                         rundir="/var/run/openvswitch", \
                         system-id="029e7d3d-d2ab-4f2c-bc92-ec58c94a8fc1"}
  ...

“external_ids:ovn-cms-options”中定义的每个配置选项都用逗号分隔。

此信息在 Neutron 服务器初始化期间以及当“Chassis”注册更新时从 OVN SB 数据库中检索。

Placement 配置的初始信息是在 Neutron API 接收到“Chassis”创建事件时检索的,该事件发生在 IDL 连接到数据库服务器时。收到创建事件后,Neutron API 读取配置,构建 PlacementState 实例并将其发送到 Placement API。

更新 Placement 信息第二种方法是当“Chassis”注册更新时。 OVNClientPlacementExtension 扩展程序注册一个事件处理程序,该处理程序会关注 OVN SB “Chassis”带宽配置更改。此事件处理程序构建一个 PlacementState 实例并将其发送到 Placement API。如果添加了新的 chassis 或现有 chassis 更改了其资源提供程序配置,则此事件会在 Placement 数据库中对其进行更新。

资源信息传播

信息的流程对于可用资源和已用资源是不同的。

可用资源的真实来源是 neutron 代理配置 - 资源实际存在的位置,如上述代理配置部分所述。此信息在以下链中传播:neutron-l2-agent -> neutron-server -> Placement

从 neutron 代理到服务器的信息包含在定期通过消息队列发送的代理心跳消息的 configurations 字段中。

# as admin
$ openstack network agent list --agent-type open-vswitch --host devstack0
+--------------------------------------+--------------------+-----------+-------------------+-------+-------+---------------------------+
| ID                                   | Agent Type         | Host      | Availability Zone | Alive | State | Binary                    |
+--------------------------------------+--------------------+-----------+-------------------+-------+-------+---------------------------+
| 5e57b85f-b017-419a-8745-9c406e149f9e | Open vSwitch agent | devstack0 | None              | :-)   | UP    | neutron-openvswitch-agent |
+--------------------------------------+--------------------+-----------+-------------------+-------+-------+---------------------------+

# output shortened and pretty printed
# note: 'configurations' on the wire, but 'configuration' in the cli
$ openstack network agent show -f value -c configuration 5e57b85f-b017-419a-8745-9c406e149f9e
{'bridge_mappings': {'physnet0': 'br-physnet0'},
 'resource_provider_bandwidths': {'br-physnet0': {'egress': 10000000,
                                                  'ingress': 10000000}
                                  'rp_tunnelled': {'egress': 20000000,
                                                   'ingress': 20000000}},
 'resource_provider_inventory_defaults': {'allocation_ratio': 1.0,
                                          'min_unit': 1,
                                          'reserved': 0,
                                          'step_size': 1},
 ...
}

重新读取与配置相关的资源子集在 SIGHUP 上未实现。必须重启代理才能获取并发送更改后的配置。

Neutron-server 通过 Placement 的 HTTP REST API 将信息进一步传播到 Placement,以获取每个代理的资源。为了避免 Placement 过载,这种同步通常不会在每次接收到心跳消息时发生。相反,一个代理的资源重新同步由以下情况触发:

  • 创建网络代理记录(如 openstack network agent list 查询所示)。请注意,删除代理记录并让下一个心跳重新创建它可用于触发同步,而无需重启代理。

  • 该代理的重启(技术上是指心跳消息中存在 start_flag)。

管理员可以使用这两种方法来强制重新同步(如果需要)。

从 neutron-server 到 Placement 的同步尝试的成功与否会持久化到相关代理的 resources_synced 属性中。例如

# as admin
$ openstack network agent show -f value -c resources_synced 5e57b85f-b017-419a-8745-9c406e149f9e
True

resources_synced 可能会取值为 True、False 和 None

  • None:未尝试同步(对于未报告 Placement 支持资源的代理来说是正常的)。

  • True:上次同步尝试完全成功。

  • False:上次同步尝试部分或完全不成功。

如果某个代理的 resources_synced 不是 True,neutron-server 会在收到该代理的每个心跳消息时尝试重新同步。因此,它应该能够从 Neutron-Placement 通信的瞬态错误中恢复(例如,Placement 在 Neutron 之后启动)。

重要的是要注意,重启 neutron-server 不会触发任何类型的重新同步到 Placement(为了避免更新风暴)。

如前所述,请求的资源和(如果正确)分配的资源的信息流是不同的。它涉及 Nova、Neutron 和 Placement 之间的对话。

  1. Neutron 以资源类和特征的形式公开端口的资源需求,作为该端口的仅管理员可用的 resource_request 属性。

  2. Nova 读取此信息,并将其作为编号请求组 incorporates 纳入云服务器的整体分配候选请求中,发送给 Placement。

  3. Nova 选择(调度)并分配 Placement 返回的一个候选者。

  4. Nova 在绑定端口时告知 Neutron,哪个物理网络接口资源提供商已被选择以满足端口的资源请求,位于该端口的 binding:profile.allocation 子属性中。

有关详细信息,请参阅 2018 年 11 月柏林峰会上展示的(预发布)演示文稿的第 13-15 页:slides 13-15

自 Yoga 以来,端口的 resource_request 属性已更改。借助 port-resource-request-groups 扩展,Neutron 会告知 Nova 传递的 blob 可以包含多个带宽请求。请检查 resource_request sanitization

示例用法

Physnets 和 QoS 策略(及其规则)通常由云管理员预先创建

# as admin

$ openstack network create net0 \
    --provider-network-type vlan \
    --provider-physical-network physnet0 \
    --provider-segment 100

$ openstack subnet create subnet0 \
    --network net0 \
    --subnet-range 10.0.4.0/24

$ openstack network qos policy create policy0

$ openstack network qos rule create policy0 \
    --type minimum-bandwidth \
    --min-kbps 1000000 \
    --egress

$ openstack network qos rule create policy0 \
    --type minimum-bandwidth \
    --min-kbps 1000000 \
    --ingress

然后,普通用户可以使用预创建的策略来创建端口并启动使用这些端口的服务器

# as an unprivileged user

# an ordinary soft-switched port: ``--vnic-type normal`` is the default
$ openstack port create port-normal-qos \
    --network net0 \
    --qos-policy policy0

# alternatively an SR-IOV port, unused in this example
$ openstack port create port-direct-qos \
    --network net0 \
    --vnic-type direct \
    --qos-policy policy0

$ openstack server create server0 \
    --flavor cirros256 \
    --image cirros-0.5.1-x86_64-disk \
    --port port-normal-qos

关于分配的修复

由于 Placement 携带云部署资源的全局视图(可用资源、已用资源),在某些情况下,它可能会与现实不同步。

一个重要的情况是,在 Stein 之前(首次发布于 Newton),仅数据平面最小保证带宽功能被使用。由于在 Stein 之前未在服务器放置期间强制执行保证,可用资源可能会在不知情的情况下被过度分配。在这种情况下,应该在升级到 Stein 期间/之后使 Placement 的视图与资源使用的现实保持一致。

另一个情况源于 OpenStack 没有分布式事务来分配由多个 OpenStack 组件(此处为 Nova 和 Neutron)提供的资源。存在已知的竞态条件,Placement 的视图可能会与现实不同步。设计有意地将竞态条件窗口降至最低,但存在已知问题

  • 如果在 Nova 读取端口的 resource_request 之后,但在端口绑定之前修改了 QoS 策略,则将应用修改之前的状态。

  • 如果删除了具有资源分配的已绑定端口,则端口的分配会泄漏。https://bugs.launchpad.net/nova/+bug/1820588

注意

删除已绑定的端口没有已知用例。请考虑先使用 openstack server remove port 分离接口。

可以通过以下方式修复不正确的分配:

  • 移动服务器,这将删除错误的分配并在实施移动操作后创建正确的分配(不幸的是,在 Stein 中不可用)。移动服务器可以修复本地过度分配。

  • 升级助手分配修复工具的需求正在 bug 1819923 中跟踪。

  • 手动使用 openstack resource provider allocation set /delete

调试

  • 所有组件是否都在运行至少 Stein 版本?

  • neutron-server 中是否启用了 placement 服务插件?

  • 相关 neutron 代理是否配置了 resource_provider_bandwidths

  • resource_provider_bandwidths 是否与 bridge_mappingsphysical_device_mappings 对齐?

  • 更改配置文件后是否已重启代理?

  • resource_provider_bandwidths 是否到达 neutron-server?

# as admin
$ openstack network agent show ... | grep configurations

请在 资源信息传播 部分查找示例。

  • neutron-server 是否已成功与 Placement 同步?

# as admin
$ openstack network agent show ... | grep resources_synced

请在 资源信息传播 部分查找示例。

  • 资源提供程序树是否正确?根是否是计算主机?下一层是代理?再下一层是物理网络接口?

$ openstack --os-placement-api-version 1.17 resource provider list
+--------------------------------------+------------------------------------------+------------+--------------------------------------+--------------------------------------+
| uuid                                 | name                                     | generation | root_provider_uuid                   | parent_provider_uuid                 |
+--------------------------------------+------------------------------------------+------------+--------------------------------------+--------------------------------------+
| 3b36d91e-bf60-460f-b1f8-3322dee5cdfd | devstack0                                |          2 | 3b36d91e-bf60-460f-b1f8-3322dee5cdfd | None                                 |
| 4a8a819d-61f9-5822-8c5c-3e9c7cb942d6 | devstack0:NIC Switch agent               |          0 | 3b36d91e-bf60-460f-b1f8-3322dee5cdfd | 3b36d91e-bf60-460f-b1f8-3322dee5cdfd |
| 1c7e83f0-108d-5c35-ada7-7ebebbe43aad | devstack0:NIC Switch agent:ens5          |          2 | 3b36d91e-bf60-460f-b1f8-3322dee5cdfd | 4a8a819d-61f9-5822-8c5c-3e9c7cb942d6 |
| 89ca1421-5117-5348-acab-6d0e2054239c | devstack0:Open vSwitch agent             |          0 | 3b36d91e-bf60-460f-b1f8-3322dee5cdfd | 3b36d91e-bf60-460f-b1f8-3322dee5cdfd |
| f9c9ce07-679d-5d72-ac5f-31720811629a | devstack0:Open vSwitch agent:br-physnet0 |          2 | 3b36d91e-bf60-460f-b1f8-3322dee5cdfd | 89ca1421-5117-5348-acab-6d0e2054239c |
| 521f53a6-c8c0-583c-98da-7a47f39ff887 | devstack0:Open vSwitch agent:rp_tunnelled|          2 | 3b36d91e-bf60-460f-b1f8-3322dee5cdfd | 89ca1421-5117-5348-acab-6d0e2054239c |
+--------------------------------------+------------------------------------------+------------+--------------------------------------+--------------------------------------+
  • Placement 是否具有预期的特征?

# as admin
$ openstack --os-placement-api-version 1.17 trait list | awk '/CUSTOM_/ { print $2 }' | sort
CUSTOM_PHYSNET_PHYSNET0
CUSTOM_TUNNELLED_NETWORKS
CUSTOM_VNIC_TYPE_DIRECT
CUSTOM_VNIC_TYPE_DIRECT_PHYSICAL
CUSTOM_VNIC_TYPE_MACVTAP
CUSTOM_VNIC_TYPE_NORMAL
  • 物理网络接口资源提供程序是否具有正确的特征关联和库存?

# as admin
$ openstack --os-placement-api-version 1.17 resource provider trait list RP-UUID
$ openstack --os-placement-api-version 1.17 resource provider inventory list RP-UUID
  • QoS 策略是否具有 minimum-bandwidth 规则?

  • 端口是否具有正确的策略?

  • 端口是否具有 resource_request

# as admin
$ openstack port show port-normal-qos | grep resource_request
  • 服务器是否使用端口启动(而不是网络)?

  • Nova 是否已为服务器在 Placement 中分配资源?

# as admin
$ openstack --os-placement-api-version 1.17 resource provider allocation show SERVER-UUID
  • 分配是否在预期的物理网络接口资源提供程序上?

# as admin
$ openstack --os-placement-api-version 1.17 resource provider show --allocations RP-UUID
  • Placement 是否设法在调度期间为 nova 生成分配候选列表?

  • Nova 是否成功调度服务器?

  • Nova 是否告知 Neutron 哪个物理网络接口资源提供商被分配以满足带宽请求?

# as admin
$ openstack port show port-normal-qos | grep binding.profile.*allocation
  • Neutron 是否成功绑定端口?