将 Inspector 分割为 API 和 Worker

https://bugs.launchpad.net/ironic-inspector/+bug/1525218

这项工作是 Ironic Inspector 的高可用性 规范的一部分。为了实现 inspector 的高可用性和可扩展性,需要将单个 inspector 服务分割为 API 服务和 worker 服务。本规范重点描述上述工作的重要部分——上述服务之间的内部通信。

问题描述

inspector 是一个单体服务,包含 API、后台处理、防火墙和 DHCP 管理。因此,inspector 无法很好地处理大量的 ironic 裸机节点,也不适合大规模部署。引入新服务来解决这些问题也会带来一些复杂性,因为它需要一种内部服务通信机制。

提议的变更

节点内省是一个异步任务序列。一个任务可以描述为 inspector 状态机的 FSM 转换 1,由诸如以下事件触发:

  • starting(wait) -> waiting

  • waiting(process) -> processing

  • waiting(timeout) -> error

  • processing(finish) -> finished

可以异步执行的 API 请求可以被认为是异步任务。正是这些任务允许将服务分割为 APIWorker 部分,前者创建任务,后者消费这些任务。这些服务部分之间的通信需要一种媒介,即 队列,这三者共同构成了 消息队列范例。OpenStack 项目使用一种称为 AMQP 的开放标准消息中间件。这种消息中间件,oslo.messaging,使在多台服务器上运行的服务能够相互通信。

每个 inspector worker 提供一个 worker 线程池,该线程池通过队列从 API 服务获取状态转换请求。API 服务调用 worker 上的方法,最终成为一个任务。换句话说,存在 client 角色,由 API 服务执行,以及 server 角色,由 worker 线程执行。服务器通过 oslo.messaging 提供 RPC 接口供客户端使用。

客户端 - inspector API

inspector API 将实现一个简单的 oslo.messaging 客户端,该客户端将连接到消息传输并发送带有状态转换事件的消息。

方法可以通过两种方式调用,请参阅 2
  • cast - 方法异步调用,不向调用者返回结果。

  • call - 方法同步调用,并将结果返回给调用者。

inspector 端点,调用 RPC

方法

RPC 类型

API

Worker

POST /introspection/<node_id>

cast

检查配置状态,验证电源接口,设置 starting 状态,<RPC> cast inspect

添加查找属性,更新 pxe 过滤器,将 pxe 设置为启动设备,重新启动节点,设置 waiting 状态

POST /continue

cast

节点查找,检查配置状态,<RPC> cast process

设置 processing 状态,运行处理钩子,应用规则,更新 pxe 过滤器,保存内省数据,关闭节点电源,设置 finished 状态

POST /introspection/<node_id>

/abort

cast

在缓存中查找节点,<RPC> cast abort

强制关闭电源,更新 pxe 过滤器,设置 error 状态

POST /introspection/<id>/data

/unprocessed

cast

在缓存中查找节点,<RPC> cast reapply

获取内省数据,设置 reapplying 状态,运行处理钩子,保存内省数据,应用规则,设置 finished 状态

内省的流程如下所示:

Client           API            Worker           Node           Ironic
  +               +               +                +               +
  | <HTTP>Start   |               |                |               |
  +--inspection--->               |                |               |
  |               X Validate power|                |               |
  |               X interface,    |                |               |
  |               X initiate task |                |               |
  |               X for inspection|                |               |
  |               X               |                |               |
  |               X  <RPC> Cast   |                |               |
  X               +- inspection--->                |               |
  X               |               X Update pxe     |               |
  X               |               X filters, set   |               |
  X               |               X lookup attrs   |               |
  X               |               X                |               |
  X               |               X <HTTP> Set pxe |               |
  X               |               +-boot dev,reboot+--------------->
  X               |               |                |     Reboot    |
  X               |               |                <---------------+
  X               |               |    DHCP, boot, X               |
  X               |               |   Collect data X               |
  X               |               |                X               |
  X               |Send inspection data to inspector               |
  X               <---------------+----------------+               |
  X               X Node lookup,  |                |               |
  X               X verify collect|                |               |
  X               X failures      |                |               |
  X               X               |                |               |
  X               X   <RPC> Cast  |                |               |
  X               +-process data-->                |               |
  X               |               X Run process    |               |
  X               |               X hooks, apply   |               |
  X               |               X rules, update  |               |
  X               |               X filters        |               |
  X               |               X     <HTTP> Set power off       |
  X               |               +----------------+--------------->
  X               |               |                |  Power off    |
  X               +               +                <-------------  +

服务器 - inspector worker

一个 RPC 服务器暴露 inspector 端点,包含一组可以由客户端通过给定的传输远程调用的方法。传输驱动程序将根据用户的消息配置加载。有关配置选项的更多详细信息,请参阅 3

一个 inspector worker 将实现一个单独的 oslo.service 进程,并拥有自己的绿色线程池。worker 将定期消费和处理来自客户端的消息。

RPC 可靠性

对于客户端通过 cast(异步)发送的每条消息,都会立即发送回确认消息,并且消息将从队列中删除。因此,无法保证 worker 将处理内省任务。

这种模型,称为 最多一次传递,如果 worker 死亡,则不能保证异步任务的处理。

如果 worker 在处理内省数据期间死亡(连接关闭或丢失),则任务请求消息将消失,内省任务将挂在 processing 状态,直到发生 timeout

备选方案

使用 Kombu 库实现我们自己的 Publisher/Consumer 功能。这种方法有一些好处:

  • 支持 至少一次传递 语义。对于每个被消费者检索和处理的消息,都会向消息生产者发送回确认消息。如果未在一定时间内收到此确认消息,则消息将被重新发送

    API               Worker thread
     +                      +
     |                      |
     +--------------------->+
     |                      |
     |             +--------+
     |             |        |
     |      Process|        |
     |      Request|        |
     |             |        |
     |             +------->+
     |         ACK          |
     +<---------------------+
     |                      |
     +                      +
    

    如果消费者在不发送确认的情况下死亡,则消息未被处理,如果有其他消费者同时在线,则消息将被重新处理。

另一方面,这种方法也有相当大的缺点:

  • 实现我们自己的 Publisher/Consumer。这意味着支持新功能的复杂性,缺乏与 oslo.messaging 相比的受支持后端,例如 0MQ

  • 更糟糕的部署者 UX。inspector 中的消息后端配置将与其它服务(包括 ironic)不同,这给部署者带来了一些痛苦。

数据模型影响

HTTP API 影响

端点 /continue 将返回 ACCEPTED 而不是 OK

客户端 (CLI) 影响

Ironic python agent 影响

性能和可扩展性影响

提议的更改将允许用户在未来进行更多工作后,水平扩展 ironic-inspector,包括 API 和 Worker。有关更多详细信息,请参阅 Ironic Inspector 的高可用性

安全影响

新引入的服务需要额外的保护。将用作传输层的消息服务,例如 RabbitMQ,应依赖于传输层加密,有关更多详细信息,请参阅 4

部署者影响

新引入的消息总线层需要一些消息代理来连接 inspector API 和 worker。OpenStack 安装中最常用的代理实现是 RabbitMQ,有关更多详细信息,请参阅 5

为了实现弹性,应将多个 API 服务和 worker 服务实例部署在多个物理主机上。

还添加了新的配置选项,请参阅 3

开发者影响

开发人员需要在添加需要作为后台任务处理的新功能时,考虑新的架构和 inspector API 和 Worker 通信细节。

升级和向后兼容性

当前的 inspector 服务是一个单一进程,因此部署者可能需要添加更多服务,新添加的 inspector Worker,消息传输后端(RabbitMQ)。控制脚本 ironic-inspector 可以更改为使用 in-memory 后端运行 API 和 Worker 服务,用于消息传输。这允许以向后兼容的方式运行 ironic-inspector - 在单个主机上运行两个服务,而无需消息代理。

实现

负责人

  • aarefiev (Anton Arefiev)

工作项

  • 添加基本服务功能;

  • 引入 Client/Servers worker;

  • 实现 API/Worker 管理器;

  • 将服务分割为 API 和 Worker;

  • 在 Devstack 中实现对这些服务支持;

  • 使用 WSGI 6 实现 API 服务。

依赖项

测试

所有新功能都将通过功能测试和单元测试进行测试。已经运行的 Tempest 测试以及使用 Grenade 进行的升级测试也将涵盖添加的功能。

功能测试同时运行 Inspector API 和 Worker,并使用 in-memory 后端。

完成所有工作项将允许设置多节点 devstack 并最终在集群模式下测试 Inspector。