资源跟踪器允许 virt 驱动程序更新提供者树

https://blueprints.launchpad.net/nova/+spec/update-provider-tree

在转向使用 placement 进行调度和资源管理的过程中,virt 驱动程序方法 get_available_resource 最初被 get_inventory 取代,从而驱动程序可以以 placement 能够理解的术语指定其库存。在 Queens 版本中,添加了一个 get_traits 驱动程序方法。但是 get_inventory 仅限于表达库存(而非特性或聚合)。并且这两种方法都仅限于与计算节点对应的资源提供者。

最近的开发,例如 嵌套资源提供者,需要 virt 驱动程序能够更深入地控制资源跟踪器代表计算节点在 placement 中配置的内容。此蓝图提出了一种新的 virt 驱动程序方法,update_provider_tree,以及资源跟踪器对其使用方法,从而可以完全控制 placement 对计算节点及其相关提供者和元数据的表示。

问题描述

现有的 virt 驱动程序方法在表达资源提供者信息的能力方面受到限制。

用例

作为 virt 驱动程序开发人员,我希望能够将我的计算节点和相关实体建模为提供者树和共享提供者的任意组合,以及与这些提供者相关的库存、特性和聚合关联。

提议的变更

ComputeDriver.update_provider_tree

ComputeDriver.update_provider_tree 被引入。它接受两个参数

  • 一个 nova.compute.provider_tree.ProviderTree 对象,代表与计算节点关联的树中的所有提供者,以及任何共享提供者(那些具有 MISC_SHARES_VIA_AGGREGATE 特性的提供者)通过聚合与这些提供者中的任何一个关联(但不是它们的树或聚合关联提供者),如 placement 当前所知。此对象完全由 update_provider_tree 方法拥有,因此可以在不考虑锁定/并发的情况下对其进行修改。但是,请注意,它可能包含不由计算主机直接拥有/控制的提供者。必须小心不要无意中删除或修改此类提供者。此外,提供者可能与由外部代理维护的特性和/或聚合相关联。update_provider_tree 因此也必须小心仅添加/删除它明确控制的特性/聚合。

  • 用于更新提供者和库存的计算节点的字符串名称(即 ComputeNode.hypervisor_hostname)。驱动程序可以使用它来帮助识别 ProviderTree 中的计算节点提供者。管理多个节点的驱动程序(例如 ironic)也可以将其用作指示正在更新哪个节点的线索。

预计 virt 驱动程序将使用当前资源提供者和库存信息更新 ProviderTree 对象。当该方法返回时,ProviderTree 应该代表与此计算节点关联的嵌套资源提供者的正确层次结构,以及与这些资源提供者关联的库存、聚合和特性。

注意

尽管名为 ProviderTree,但 ProviderTree 实例实际上可能包含多个树。为了本规范的目的,传递给 update_provider_tree 的 ProviderTree 将包含

  • 与计算节点关联的整个树;以及

  • 任何共享提供者(那些具有 MISC_SHARES_VIA_AGGREGATE 特性的提供者),这些提供者通过聚合与计算节点树中的任何提供者关联。即使它们本身也是树的一部分,共享提供者也会在 ProviderTree 中呈现为单独的根。

考虑以下示例。 SSP 是一个共享存储提供者,BW1BW2 是共享带宽提供者;所有三个都具有 MISC_SHARES_VIA_AGGREGATE 特性

         CN1                 SHR_ROOT               CN2
        /   \       agg1    /   /\     agg1        /   \
   NUMA1     NUMA2--------SSP--/--\-----------NUMA1     NUMA2
  /     \   /    \            /    \         /     \   /    \
PF1    PF2 PF3   PF4--------BW1   BW2------PF1    PF2 PF3   PF4
                     agg2             agg3

当为 CN1 调用 update_provider_tree 时,传递给它的 ProviderTree 包含

         CN1 (root)
        /   \       agg1
   NUMA1     NUMA2-------SSP (root)
  /     \   /    \
PF1    PF2 PF3   PF4------BW1 (root)
                     agg2

此方法取代了 get_inventoryget_traits:如果实现了此方法,则不使用 get_inventoryget_traits

驱动程序对 update_provider_tree 的实现预计将使用公共 ProviderTree 方法来对传递的提供者树进行更改。以下是一些可能有用的方法

  • new_root:将新的根提供者添加到树中。

  • new_child:在现有提供者下添加新的子项。

  • data:访问树中提供者的信息(名称、UUID、父项、库存、特性、聚合)。

  • remove:从树中删除提供者及其后代。在多所有权场景中使用时要小心。

  • update_inventory:设置提供者的库存。

  • add_traitsremove_traits:设置/取消设置提供者的 virt 拥有的特性(参见 ProviderTree.add_traits 和 .remove_traits)。

  • add_aggregatesremove_aggregates:设置/取消设置提供者的 virt 拥有的聚合关联(参见 ProviderTree.add_aggregates 和 .remove_aggregates)。

注意

不支持 update_provider_tree 影响分配的机制。这是故意的:在 Nova 中,分配完全由 virt 之外的机制管理。(通常由调度器管理;有时 - 例如对于迁移 - 由 conductor 管理。)

从 get_inventory 移植

希望从 get_inventory 迁移到 update_provider_tree 的 virt 驱动程序开发人员应使用 ProviderTree.update_inventory 方法,将计算节点指定为提供者,并指定与 get_inventory 返回的库存相同。例如

def get_inventory(self, nodename):
    inv_data = {
        'VCPU': { ... },
        'MEMORY_MB': { ... },
        'DISK_GB': { ... },
    }
    return inv_data

将变为

def update_provider_tree(self, provider_tree, nodename):
    inv_data = {
        'VCPU': { ... },
        'MEMORY_MB': { ... },
        'DISK_GB': { ... },
    }
    provider_tree.update_inventory(nodename, inv_data)

从 get_traits 移植

要替换 get_traits,开发人员应使用 ProviderTree.add_traits 方法,将计算节点指定为提供者,并指定与 get_traits 返回的特性相同。例如

def get_traits(self, nodename):
    traits = ['HW_CPU_X86_AVX', 'HW_CPU_X86_AVX2', 'CUSTOM_GOLD']
    return traits

将变为

def update_provider_tree(self, provider_tree, nodename):
    provider_tree.add_traits(
        nodename, 'HW_CPU_X86_AVX', 'HW_CPU_X86_AVX2', 'CUSTOM_GOLD')

SchedulerReportClient.update_from_provider_tree

这是负责接受 virt 驱动程序通过 update_provider_tree 修改的 ProviderTree 并进行必要的 placement API 调用以确保 placement 服务中的表示与其匹配的报告客户端方法。特别是

  • 通过 update_provider_tree 删除的提供者从 placement 中删除。

  • 通过 update_provider_tree 添加的提供者在 placement 中创建。

  • 如果通过 update_provider_tree 更改了任何提供者的库存、特性或聚合,则将这些更改刷新回 placement。

注意

在多所有权场景中,virt 驱动程序应小心不要删除或修改不由计算主机拥有的提供者。

ResourceTracker._update

这是要求 virt 驱动程序报告计算资源的地方。例如,如果实现了 get_inventory,则添加了对 get_available_resource 返回的数据的覆盖。在这里,我们添加了另一个级别,以允许 update_provider_tree 覆盖 get_inventory。逻辑从

try:
    ComputeDriver.get_inventory()
except NotImplementedError:
    SchedulerReportClient.update_compute_node()

try:
    ComputeDriver.get_traits()
except NotImplementedError:
    pass

变为

try:
    ComputeDriver.update_provider_tree()
    SchedulerReportClient.update_from_provider_tree()
except NotImplementedError:
    try:
        ComputeDriver.get_inventory()
    except NotImplementedError:
        SchedulerReportClient.update_compute_node()

    try:
        ComputeDriver.get_traits()
    except NotImplementedError:
        pass

ProviderTree.add_traits 和 .remove_traits

由于外部代理(例如运营商)需要能够设置和取消设置超出 virt 驱动程序范围的特性,因此 ComputeDriver.update_provider_tree 需要能够显式地添加和删除特性,而不是简单地覆盖给定提供者的整个特性集。为了便于此,我们将向 ProviderTree 添加以下方法

def add_traits(self, name_or_uuid, \*traits)
def remove_traits(self, name_or_uuid, \*traits)

参数

  • name_or_uuid:要影响其特性的资源提供者的名称或 UUID。

  • traits:要添加或删除的特性的字符串名称。与提供者关联的任何其他特性不受影响。

ProviderTree.add_aggregates 和 .remove_aggregates

由于外部代理(例如运营商)需要能够设置和取消设置超出 virt 驱动程序范围的聚合关联,因此 ComputeDriver.update_provider_tree 需要能够显式地添加和删除聚合关联,而不是简单地覆盖给定提供者的整个聚合关联集。为了便于此,我们将向 ProviderTree 添加以下方法

def add_aggregates(self, name_or_uuid, \*aggregates)
def remove_aggregates(self, name_or_uuid, \*aggregates)

参数

  • name_or_uuid:要影响其聚合的资源提供者的名称或 UUID。

  • aggregates:要添加或删除的聚合的字符串 UUID。与提供者关联的任何其他聚合不受影响。

备选方案

  • 继续提供与 get_inventoryget_traits 一致的逐步方法。所提出的解决方案可以涵盖这两种方法的全部功能,甚至更多,但它也可以随着 placement 和 Nova 的使用而发展。

  • 允许 virt 驱动程序直接控制 placement。虽然我们无法阻止树外驱动程序执行此操作,但已经讨论并决定树内驱动程序应通过 SchedulerReportClient 的阻塞点进行实际的 placement API 通信。

数据模型影响

REST API 影响

安全影响

通知影响

其他最终用户影响

没有直接影响。此更改,以及 virt 驱动程序实现 update_provider_tree,以及 virt 驱动程序扩展其资源提供者模型,最终将允许运营商对调度操作施加更多控制。

性能影响

此更改增加了对 placement 服务的流量,这可能会影响性能。但是,目前尚无证据表明大量的 placement 调用相对于这些代码路径中发生的其他处理而言是“昂贵的”。如果证明有问题,则有意减轻这种影响。

一种缓解策略,已经很大程度上实施,是通过 SchedulerReportClient 中维护的单独 ProviderTree 实例在本地缓存 placement 表示。具体内容超出本文档的范围。但是,该区域的现有代码不一致,需要在一份单独的规范中进行规范化,以便我们可以朝着一致性努力。

其他部署者影响

开发人员影响

见上文。

升级影响

实现

负责人

主要负责人

efried

工作项

此代码已完成。其中一些已合并到 Queens 中,包括

这些更改是在 嵌套资源提供者 蓝图下开发的。

依赖项

无(所有依赖项已合并到 Queens 中)。

继续开发诸如 嵌套资源提供者细粒度资源请求和共享资源提供者等功能将扩展驱动程序开发人员通过其 update_provider_tree 实现可以执行的操作范围。

测试

除了单元测试之外,还包括广泛的功能测试。

文档影响

参考资料

历史

修订版

发布名称

描述

Queens

代码已完成并大部分合并。

Rocky

觉得我们真的应该写点东西下来,所以提出了一份实际的蓝图和这份规范。