Shard Key Introduction

https://storyboard.openstack.org/#!/story/2010378

经过大量的讨论和尝试来解决 nova-compute 在大规模部署中与其与 Ironic 的连接的可扩展性问题,并且在发现 networking-baremetal 也存在类似的可扩展性问题后,社区已经开始达成共识,确定前进的道路。具体来说,就是引入分片模型,允许 API 消费者映射并锁定到特定的裸机节点集合,无论这种关系是半永久性的还是完全临时的。只有执行处理的信息消费者才能做出这种决定,而 Ironic 必须尝试提供子平台能力,以便有效地操作其 API。

问题描述

现实情况是,Ironic 可以在数百甚至数十万的裸机节点规模下使用,虽然大多数 Ironic 操作员要么运行多个较小的独立 Ironic 部署,少于 500 台物理机器,但有些需要单个部署数千甚至数万台物理节点。在增加规模后,外部操作轮询 ironic 通常难以扩展到这些级别。 也很容易出现配置错误,导致性能下降,因为扩展模型和限制很难理解。

这在使用 Nova 的 Compute 进程运行 nova.virt.ironic 驱动程序时是可观察到的。在操作上很容易陷入这样的情况,即试图支持数千个裸机节点,但 nova-compute 进程太少。 这种情况会导致该进程尝试处理超出其设计能力的工作。

最近,我们发现了一个案例,虽然源于配置错误,但存在与 networking-baremetal 相同的基本扩展问题,它负责轮询和更新 Neutron 中的物理网络映射。 同样的情况,大量的任务和多个进程。 在这种特定情况下,多个(3 个)Neutron 服务正在对 Ironic API 造成压力,检索所有节点,并尝试更新 Neutron 中的所有相关物理网络映射记录,导致同一记录被三次更新,每次由一个服务更新。

根本问题是消耗 Ironic 数据的软件需要能够自我划分整个节点集,并确定分片节点的局部分离点。 需要这种划分,因为执行的进程更加消耗处理器资源,这可能会引入延迟和滞后,从而导致竞争条件。

之前的模型需要下载整个数据集才能构建哈希环,这是之前的挑战。

情况变得更加复杂的是,Ironic 具有 conductor_group 的操作模型,旨在帮助模拟物理分组或操作约束。 这里的挑战是,conductor groups 没有任何自动化的方式,因此 conductor groups 不是我们需要的解决方案。

提议的变更

总的来说,这个想法是在节点对象上引入一个 shard 字段,API 用户(服务)可以使用它来检索节点的子集。

节点对象上的这个新字段将与现有的 API 字段行为约束保持一致,并且可以通过 API 进行设置。

可以提供预设分片的方法,但最终 Ironic 仍然是可选的,并且分片存在是为了 API 消费者的利益。

为了便于 API 客户端使用,/v1/nodes/v1/ports 将更新为接受 shard 参数(例如,GET /v1/nodes?shard=foo, GET /v1/ports?shard=foo, GET /v1/portgroups?shard=foo)在查询中,以便 API 消费者可以自动限制其数据集并自行确定如何减少工作集。 例如,networking-baremetal 可能不关心分配,它只需要减少本地化的工作集。 而 nova-compute 需要分片字段保持静态,除非 nova-compute 或其他 API 消费者请求在节点上更新 shard

注意

目前,整体流程消费者使用的方法是检索所有内容,然后根据结果集的内容限制工作范围。 这会导致大量的工作开销和增加的循环延迟,这也可能导致竞争条件。 nova-computenetworking-baremetal ML2 插件都以不同的使用模式运行这种方式。 拟议解决方案的优势在于能够将范围限制/分组划分为可管理的块。

在访问控制方面,我们还将添加一个新的 RBAC 策略来限制更改,以便系统本身或适当范围内的(例如,管理)用户可以更改该字段。

在这个模型中,conductors 不关心分片键。 它只是节点上的一个数据存储字段。 对整体分片组成/布局的查找,对于 GET /v1/shards,将直接针对节点表执行 SQL 查询。

备选方案

这是一个复杂的解决方案,旨在简化但划分的使用,并且还有许多其他选项可用于特定细节。

最终,应该讨论和考虑每个项目。

迄今为止,一个关键方面是,现有的机制可以被低效地利用来实现这一点。 这方面的例子是 conductor_groupownerlessee 都可以用于过滤节点结果集。 conductor_group 是 API 客户端可以显式请求的一个方面,而 ownerlessee 是基于访问控制的过滤器,与用于身份验证的 API 客户端提交的项目 ID 相关联。 为什么 conductor_group 有问题,在本文档的后面会进一步说明。

与 Nova 团队的讨论一致认为,使用其他字段,虽然在某些有限和特定情况下可能有用,甚至更可取,但并不能解决客户端在首次下载整个节点列表之前,能够自我划分的通用需求。 而检索完整的节点列表本身就是一个已知的扩展挑战,并会增加处理延迟。

conductor_group 的情况下,目前没有办法发现 conductor groups。 而对于 ownerlessee,这些是特定的项目 ID 值字段。

为什么不使用 Conductor Group?

重要的是要强调,从相似性来看,这 conductor groups 类似,但是 conductor groups 主要用于模拟裸机基础设施的物理约束和结构。

例如,如果您在欧洲有一组 conductors,在纽约有一组 conductors,您不希望尝试从欧洲运行纽约服务器的部署。 这种暴露或在 Nova 中使用的吸引力的一部分也是为了与物理结构对齐。 Ironic 社区知道一些基础设施操作员已经利用这个设置和字段来促进其 nova-compute 基础设施的扩展,但是这些操作员也遇到了我们希望通过分片键实现来避免的这种使用模式的问题。

与此努力和预先存在的 conductor groups 的需求不同之处在于,conductor groups 是哈希环建模行为的一部分,而在分片模型中,conductors 将在不考虑分片键值的情况下运行。 我们需要不相交的建模来支持以 API 消费者为中心的使用,以便它们可以在逻辑单元中以不同的工作选择运行。 消费者可能关心 conductor_group 加上分片,因为地理位置划分与需要更小的“工作块”或在本例中“裸机节点组”对于运行的进程负责是分开的。

在这种特定情况下,conductor_group 是完全手动管理的方面,Nova 有一个单独的设置名称,因为名称感知的原因,而我们的希望最终是简单而智能的东西。

注意

Nova 项目在项目团队会议上同意弃用他们以前强制使用的 peer_list 参数,以支持 conductor groups 的哈希环逻辑。

此外,如今的 conductor_group 功能依赖于哈希环模型的用法,Nova 团队希望在接下来的几个开发周期中从 Nova 代码库中删除它。 而 Ironic 将继续使用哈希环功能来管理我们的 conductors 的运行状态,因为它也用于 conductors 管理数千个节点。 这些数千个节点不太适合扩展到 nova-compute 服务。

为什么不使用 owner 或 lessee?

在过去几年中,RBAC 模型改进之后,完全有可能管理单独的项目和凭据,以便 nova-compute 存在并运行其中。 这里的挑战是额外的凭据管理以及映射/交互。

可能“可行”地对扩展 networking-baremetal 与 Ironic 的 API 的交互执行相同的操作,但开销和自我管理节点分组似乎很繁琐且容易出错。

此外,如果采取这种方法,它也会对 nova-compute 节点造成管理上的限制,并且它们将被锁定到手动设置。

如果让 API 消费者自行解决呢?

这可能是一种选择,但会导致更差的性能和更差的用户体验。

基本难题是按顺序有效地枚举,然后对 API 客户端负责交互的每个节点执行操作。

如今,Nova 的 Compute 服务通过一个查询生成列表,枚举每个节点,并获取它需要跟踪/与节点交互的大部分数据,从而将更昂贵的单个节点请求降至最低。 如果客户端必须跟踪事物,它仍然必须提取完整的列表,然后它必须协调、跟踪和映射各个节点。 我们已经看到使用哈希环今天无法正常工作。

同样,networking-baremetal 列出所有端口。 这是它所需要的,但它没有更小的块、块或足够的信息真正创建一个代表现有模型的哈希环。 仅仅期望客户端“自行解决”并“处理这种复杂性”也意味着逻辑远离数据库。 为了提高性能,我们将逻辑和决策保持在索引列附近,效果越好,性能越高,这就是为什么提出这个解决方案。

数据模型影响

节点:添加一个 shard 列/值字符串字段,已索引,

默认值为 None。 该字段被认为是区分大小写的,这与 DB 存储类型一致。 API 查询将寻求精确的字段值匹配。

注意

我们需要与 Nova 团队和 nova.virt.ironic 驱动程序查询模式进行协商,以确保我们涵盖任何复合索引(如果需要)。

为了便于此,需要将数据库迁移和数据模型健全性检查添加到 ironic-status 作为升级检查的一部分。

状态机影响

REST API 影响

PATCH /v1/nodes/<node>

为了设置分片值,用户需要修补该字段。 这是现有节点控制器中的罐装功能,并且将受到 API 版本和 RBAC 策略的保护,以防止对该字段进行不适当的更改。 与所有其他字段一样,此操作采用 JSON Patch 的形式。

GET /v1/nodes?shard=VALUE,VALUE2,VALUE3

返回受分片键限制的节点的子集。 在这种特定情况下,我们还将允许使用字符串值“none”、“None”或“null”来检索没有设置分片键的节点列表。 逻辑处理将在 DB API 层中。

GET /v1/ports?shard=VALUE,VALUE2,VALUEZ GET /v1/portgroupss?shard=VALUE,VALUE2,VALUEZ

返回受分片键或调用者提供的密钥列表限制的端口子集。 具体来说,将使用连接查询到数据库来促进它。

GET /v1/shards

返回一个 JSON,表示分片键和使用该分片的节点计数。

{{“Name”: “Shard-10”, “Count”: 352}, {“Name”: “Shard-11”, “Count”: 351}, {“Name”: “Shard-12”, “Count”: 35}, {“Name”: null, “Count”: 921}}

在可见性方面,新功能将受到 API 微版本的限制。 在访问方面,默认情况下,此字段的使用将限制为 system-readerproject-admin 和未来的 service 角色。 将添加一个特定的 RBAC 策略来访问此端点。

注意

/v1/shards 端点将是只读的。

客户端 (CLI) 影响

通常,但并非总是,如果有任何 REST API 更改,则会对 python-ironicclient 进行相应的更改。 如果是这样,用户界面是什么样的。 如果不是,请描述为什么有 REST API 更改但没有对客户端的更改。

“openstack baremetal” CLI

将添加一个 baremetal shard list 命令。

将添加一个`baremetal node list --shard <shard>` 功能,以列出分片中的所有节点。

还将添加一个用于 `baremetal node set` 的 `--shard` 节点级别参数。

将添加一个 `baremetal port list --shard <shard>` 功能,以限制相关端口到分片中的节点。 同样,`baremetal portgroup list --shard <shard>` 也将被更新。

“openstacksdk”

将添加一个 SDK 方法来获取分片列表,并检查现有的列表方法以确保我们可以按分片查询。

RPC API 影响

目前预计没有。

驱动程序 API 影响

Nova 驱动程序影响

Nova 项目正在提出一份单独的规范文档,以帮助识别和导航整体变更。

也就是说,预计不会产生直接的负面影响。

与 Nova 的整体讨论是既要促进最小影响的迁移,又要避免强制进行具有侵入性和破坏性的变更,这些变更可能不是操作员真正需要的。

注意

设想了一个整体迁移路径,但此处仅为建议和我们对整体过程的理解。

预计的初始 Nova 迁移步骤

Ironic 本身不会提供在每个节点上设置分片值的显式过程,除了 `baremetal node set` 之外。 以下是我们 Ironic 预计的整体迁移步骤,以过渡到这种模式。

  1. 完成 Ironic 迁移。 完成后,执行数据库状态检查(即 `ironic-status upgrade check`)应该检测到并警告,如果数据库中节点存在 `shard` 键,但数据库中存在没有 `shard` 值的节点。

  2. 正在升级的 nova-compute 服务被关闭。

  3. 将执行一个 nova-manage 命令,以重新分配节点到用户提供的 `shard` 值以匹配。 例如:nova-manage ironic-reassign <shard-key> <compute-hostname>

    在程序上,这将从 Ironic 检索匹配键的节点列表,然后更改关联的 ComputeNode 和 Instance 表中的 host 字段,以匹配现有的 nova compute 服务。

    注意

    该命令可能需要匹配/验证这是否/曾经是计算主机名。

    待办事项

    作为 nova-manage 命令退出之前的最后一步,理想情况下,它应该再次检查这些表中的记录状态,以指示是否有其他节点由命名的 Compute 主机名负责。 环境中的最后一个计算主机名不应生成任何警告,任何警告都表明丢失了 ComputeNode、Instance 或 Baremetal 节点记录。

  4. 升级后的 `nova-compute` 服务的 nova-compute.conf 文件将使用 `my_shard`(或其他适当的参数)重新启动,该参数向 `nova.virt.ironic` 驱动程序代码发出信号,不要使用哈希环,而是利用它认为它负责的数据库中的内容以及查询 Ironic baremetal 节点库存时匹配配置的分片键值。

  5. 随着更多计算节点迁移到使用新的分片键设置,现有的计算节点不平衡应该在内部计算节点逻辑方面得到解决,以检索每个节点认为它负责的内容,并最终匹配分片键。

这将促进一种滚动式但隔离式故障影响的能力,因为新的 nova-compute 配置正在上线,并且也允许一种可以为大型操作员自动化的流程。

可管理性,例如如果需要更改 `shard` 或重新平衡分片,尚不清楚。 Nova 项目的当前讨论是,只有在计算服务被“强制关闭”的情况下才能允许重新平衡/重新关联,这是一个不可逆的操作。

Ramdisk 影响

安全影响

只要 RBAC 模型中存在足够的 API 访问权限,`shard` 键就可以由 API 用户设置。

基于 RBAC 模型,`/v/shards` 端点也将受到限制。

预计没有其他安全影响。

其他最终用户影响

无预计

可扩展性影响

预计该模型将允许存储在 Ironic 中的数据用户更具可扩展性。 通常预计不会对 Ironic 的可扩展性产生影响。

性能影响

预计没有实际影响。 虽然正在添加另一个字段,但初步原型基准测试显示,对于大型集合(10,000 个)baremetal 节点,响应时间非常快。

其他部署者影响

认识到操作员可能希望以编程方式自动分配或自动分片节点集。 Ironic 贡献者达成的一致意见是,我们(Ironic)将来不会自动创建新的分片。 新分片的创建将由操作员通过在任何给定节点上设置新的分片键来驱动。

这可能需要一个新的配置选项来控制此逻辑,但总体逻辑不被视为对能够“分配”节点到分片这一更关键需求的障碍。 稍后可以添加此逻辑,我们将努力提供更新的文档来解释适当的使用和选项。

开发人员影响

无预计

实现

负责人

主要负责人

Jay Faulkner (JayF)

其他贡献者

Julia Kreger (TheJulia)

工作项

  • 提出 Nova 规范,用于使用这些键 (https://review.opendev.org/c/openstack/nova-specs/+/862833)

  • 创建数据库模式/升级/模型。

  • 更新对象层,用于 `Node` 和 `Port` 对象,以便允许通过 `shard` 查询这两个对象。

  • 将查询分片功能添加到 Nodes 和 Ports 数据库表。

  • 在节点 API 上公开 `shard`,并增加微版本实施新的 RBAC 策略,该策略限制了更改 `shard` 值的能力

  • 添加预升级状态检查,以警告如果存在字段未一致填充。 例如,`shard` 未填充到所有节点上。 这将为未来的升级者提供对混合和可能配置错误的运行状态的可见性。

  • 更新 OpenStack SDK 和 python-ironicclient

依赖项

此规范在很大程度上依赖于 Nova 接受使用分片模型的计划。 目前,Ironic 团队的理解是 Nova 接受,并且 Ironic 需要合并此规范和相关代码以支持此功能,然后 Nova 才会允许合并 Nova 规范。

测试

预计对添加到 Ironic 以支持此功能的所有基本组件和操作进行单元测试。

我们可能能够为 API 字段和访问交互添加一些 tempest 测试。

升级和向后兼容性

待定。 我们预计标准的升级过程将适用,并且实际上不会有显式的降级兼容性过程,但这种能力和功能主要用于外部消耗,并且那里的细节尚未确定。

文档影响

管理文档需要包含涵盖分片、内部机制和用法的文档。

参考资料

PTG 注释:https://etherpad.opendev.org/p/nova-antelope-ptg Bug:https://launchpad.net/bugs/1730834 Bug:https://launchpad.net/bugs/1825876 相关 Bug:https://launchpad.net/bugs/1853009