http 驱动

这是一个提出创建新的驱动程序实现的提案,该驱动程序通过 HTTP 直接通信 RPC 客户端和服务器,而无需消息队列。

问题描述

在 oslo.messaging 中,RabbitMQ 驱动被广泛使用并验证了该驱动在大多数 OpenStack 环境中都能非常稳定地工作。然而,在使用消息队列的 PUB/SUB 模型中,消息队列本身可能是一个单点故障,并且消息队列也比较难以支持大规模的客户端和服务器通信。

例如,如果有超过 10,000 个虚拟机监控程序,它们托管 nova-compute 和 neutron-agent,每个 RabbitMQ 节点必须始终支持大量的网络连接(例如,超过 40,000 个)来自 nova 和 neutron 客户端。在这种情况下,如果 RabbitMQ 集群重启,大量的 RPC 客户端开始同时连接 RabbitMQ 节点,这会导致 RabbitMQ 节点不稳定。

此外,由于大量的虚拟机监控程序,RabbitMQ 必须支持大量的消息队列,以便允许 neutron-server 和 neutron-agent 进行通信,例如。所有队列数据必须在所有 RabbitMQ 节点之间同步,因此拥有大量的队列也会导致 RabbitMQ 集群不稳定。

请注意,这不是一个否认 RabbitMQ(PUB/SUB 模型)后端的提案。该提案应意识到 PUB/SUB 模型和 REQ/RESP 模型具有不同的优势,如下节所述。

PUB/SUB 优势示例

  • 小型集群中的简单架构

  • 在安全集群中易于配置 ACL

REQ/RESP 优势示例

  • 对控制平面(consul)宕机具有容错性

  • 易于扩展集群

如上所述,PUB/SUB 模型在大多数情况下简单易用,但对于大规模 OpenStack 环境,所有 RPC 通信的 REQ/RESP 模型可能更合适和可靠。

本规范提出实现基于 OpenAPI 的 REQ/RESP 模型驱动程序,称为 http driver,它能够使 RPC 客户端与 RPC 服务器直接通信,而无需 OpenStack 内部通信的单点故障组件。

提议的变更

这是 HTTP 驱动程序用于 RPC Call/Cast/Cast Fanout 请求的概述图。实现该驱动程序有 4 个主要组件。

  • RPC 客户端

  • RPC 服务器

  • 端点数据存储(例如,Consul)

  • 广播器

              +--------------+
      +------>|   Consul     |<------------------+
      |       +--------------+                   |
      |                                     +-------------+
      |                                +--->|  RPC server |
      |                                |    +-------------+
+-------------+   Call/Cast RPC        |    +-------------+
| RPC client  +---------------------------> |  RPC server |
+-------------+                        |    +-------------+
      |                                |    +-------------+
      | Cast Fanout                    +--->|  RPC server |
      |                                |    +-------------+
      |       +--------------+         |
      +------>| Broadcaster  |---------+
              +--------------+
           Send Cast to all RPC servers

注意

提案范围

  • 本提案的范围涵盖 Call/Cast/Cast Fanout RPC 用例

  • 通知不在本提案的范围内

架构需要改进的主要点

  • 将控制平面与数据平面分离

  • 允许直接 API 调用,而无需单点故障

  • 减少多个可用区之间的 RPC 通信

每个组件的职责如下。

RPC 客户端

从 consul 集群获取 RPC 目标服务的 RPC 服务器列表。选择适当的 RPC 服务器进行 RPC,然后通过 HTTP 协议发送 RPC 请求。

RPC 服务器

侦听并处理通过 HTTP 协议传入的 rpc 请求

当 RPC 服务器启动时,服务器将其 RPC 服务器信息注册到 Consul 集群作为 Consul 的“服务”。此外,PRC 服务器以 Push Style 方式工作,而不是轮询方式。

对于通过 RESTful API 进行的 HTTP RPC 客户端/服务器通信,OpenAPI 允许我们轻松定义格式化的 RESTful API 定义。生成 API 定义后,可以使用 Web 框架和 WSGI 服务器将其作为 http 服务器启动。例如,它们是用于启用 HTTP 客户端和服务器的 Web 框架和 WSGI 服务器的候选者。

  • Web 框架:connexion

  • WSGI 服务器:eventlet

端点数据存储

存储 RPC 服务器信息。

服务器信息包括以下项目。oslo.messaging 层信息(exchange、topic 和服务器)RPC 服务器信息(IP 地址、端口等)。

在本规范中,Consul 是端点数据存储的一个示例实现。

对于其他用例,应添加具有可选择后端实现的 service discovery 功能代码,供希望避免引入新的数据存储依赖项的用户使用。

HTTP 广播器

HTTP 请求的放大器

HTTP 协议没有广播机制,尽管 oslo RPC 具有 Cast Fanout RPC。广播器将传入的 RPC 发送到所有目标 RPC 服务器。

Nova 的示例 RPC 通信流程

              +--------------+
      +------>|   Consul     |
      |       +--------------+
      |
      |             * Call RPC
+----------------+  (1) select_destinations    +----------------+
| nova-conductor +---------------------------> | nova-scheduler |
|                +------+                      +----------------+
+----------------+      | * Cast RPC
                        | (2) build_and_run_instance
                        |                      +----------------+
                        +--------------------->|  nova-compute  |
                                               +----------------+

在此图中,左侧的 nova-conductor 是 RPC 客户端,右侧的每个 nova-scheduler 和 nova-compute 都是 RPC 服务器。

select_destinations() Call RPC

在实例创建期间,为了选择启动新实例的目标 nova-compute 节点,nova-conductor 向 nova-scheduler 发送 select_destinations() Call RPC 请求。在这种情况下,Call RPC 通信按以下步骤进行。

  1. nova-conductor 从 Consul 获取 nova-scheduler 的 hostn 和 port 端口信息,并随机选择一个 Call RPC 目标

  2. nova-conductor 发出 select_destinations() Call RPC 并等待响应。

build_and_run_instance() Cast RPC

在实例创建期间,一旦由 scheduler 选择目标 nova-compute,nova-conductor 使用 build_and_run_instance() Cast RPC 将实例创建请求发送到目标 nova-compute。在这种情况下,Cast RPC 通信按以下步骤进行。

  1. nova-conductor 从 Consul 获取目标 nova-compute 的 host 和 port 信息

  2. nova-conductor 发出 build_and_run_instance() Cast RPC 并立即返回,而不等待实际的实例创建

在 Consul 中注册的示例 RPC 服务器信息

Nova 的 RPC 服务器信息

此图显示 Nova 的 RPC 服务器信息注册到 nova AZ。Nova 具有 nova.scheduler、nova-conductor、nova-compute 和 nova-consoleauth 作为 RPC 服务器。

../../_images/consul-service-list.png

nova-condutor RPC 服务器列表

此图显示 nova AZ 上的 nova-conductor RPC 服务器列表。每个 nova-conductor 都有 <service name>:<port number>,以及 <IP address>:<port number> 标识符。RPC 客户端通过 <IP address>:<port number> 访问 RPC 服务器。

../../_images/conductor-service-list.png

nova-condutor RPC 服务器之一的健康检查状态

Consul 具有注册 HTTP 端点的健康检查机制。该图显示 nova-conductor RPC 服务器之一响应 Consul 的定期健康检查的 200 OK。如果端点正常,则该端点标记为绿色复选标记。

../../_images/conductor-health-check.png

多 AZ 支持

Consul 具有将多个 Consul 集群联合成一个的功能,以支持多个数据中心的情况。在该图中,有多个 nova AZ,例如 novaaz-1az-2az-3,然后每个 nova AZ 都有一个 Consul 集群。这些 4 个 Consule 集群使用 Consul 联合管理为单个集群。

../../_images/consul-federation.png

备选方案

用于主机/主题管理的数据存储

在上述架构中,选择 Consul 是因为它支持健康检查机制和多 DC 联合,这些功能使用户能够轻松监控 RPC 服务器状态,并轻松扩展以支持大规模 OpenStack。

但是,作为替代方案,使用 Keystone 服务目录、DNS 或将数据注册到类似于 ZeroMQ 的 Redis 集群进行服务端点管理是另一种选择。

一旦端点数据存储支持可选择的机制,就可以根据用例开发这些替代数据存储插件。

Cast Fanout 支持设计

在上面的图中,广播器进程作为 RPC 客户端中的另一个服务拆分出来。Cast Fanout 可以实现到 RPC 客户端中,但如果目标数量非常庞大,则会占用大量的 CPU 和内存。相反,通过拆分广播器,用户可以根据 OpenStack 集群上的目标数量轻松扩展广播器进程的数量。

API 框架

对于 API 模式定义,可以使用任何方法。例如,REST、OpenAPI、json-rpc、gRPC 或任何 http 协议实现都可以使用,只要它允许与 oslo.service 中使用的 eventlet 集成即可。在上面的图中,选择了 OpenAPI,以便实现 HTTP 协议客户端-服务器模型。

高级功能

多可用区支持

  • Consul 提供了多个 Consul 集群之间的联合机制。

  • 通过使用联合,可以将 Consul 集群拆分为每个 OpenStack 可用区。

  • 将 Consul 拆分为多个集群可以减少 Consul 的工作负载并使集群稳定。

  • 此外,在基本情况下,RPC 客户端和服务器通信发生在单个可用区中。这减少了多个 AZ 之间的网络通信。

Availability Zone-A                Availability Zone-B
+----------------+                 +----------------+
|                |   RPC Request   |                |
|   RPC server   |        +------->+   RPC server   |
|       |        |        |        |       |        |
|       |        |        |        |       |        |
|   RPC client   +--------+        |   RPC client   |
|       |        |                 |       |        |
|       |        |   Federation    |       |        |
| Consul Cluster +<--------------->+ Consul Cluster |
|                |                 |                |
+----------------+                 +----------------+

Impact on Existing APIs

无。

安全影响

  • OpenAPI 支持客户端和服务器之间的基于 SSL 的通信。这可以实现与其它消息驱动程序相同的安全 RPC 通信。

性能影响

性能应该会更好,因为 RPC 客户端通过 HTTP 直接与 RPC 服务器通信。

Configuration Impact

需要新的配置选项来配置 http 服务器。以下是在 oslo.messaging 库用户配置文件(例如 nova.conf、neutron.conf)中定义的示例配置参数。

[oslo_messaging_http]
port_range=20000:20100

[consul]
port = 8500
host = <Consul hostname>
token = <Consul token>
check_timeout = 60s
check_deregister = 30m

[http_driver]
http_token = <Token to access OpenAPI server>
http_api_config_file = <OpenAPI definition>
enable_ssl = True
ssl_certfile = <Path for SSL Cert file>
ssl_keyfile =  <Path for SSL Key file>
listen_timeout = 60

port_range 的详细设计

对于 port_range,以下规范可以减少此选项的复杂性。

  1. 如果未定义 port_range,则会随机选择未使用的临时端口。对于大多数用例,这满足了要求。

  2. 如果定义了 port_range,RPC 服务器将在服务启动期间从指定的范围内选择端口。

以下是为什么 RPC 服务器需要多个端口的原因。例如,Nova 具有“conductor.workers”配置参数,Neutron-server 具有“rpc_workers”配置参数。通过为这些配置指定大于“1”的值,可以在单个主机上启动多个 RPC worker。因此,从 RPC 客户端-服务器通信的角度来看,每个 RPC worker 必须具有单独的目标端口号才能在主机上启动它。

port_range 的目的是支持严格管理防火墙上源/目标端口的网络通信的安全云环境,默认行为是随机选择未使用的临时端口会更好。

开发人员影响

如果其它 OpenStack 组件使用 http rpc_backend,则必须根据 Consul 和 OpenAPI 配置定义 oslo_messaging_httpconsulhttp_driver 配置部分。

Testing Impact

将实现基本的单元测试和集成测试(使用 DevStack)。

实现

负责人

主要负责人

Mitsuhiro Tanino (mitsuhiro-tanino)

其他贡献者

Xiang Wang

Yushiro Furukawa (y-furukawa-2)

Masahito Muroi (masahito-muroi)

里程碑

工作项

  • 提出驱动程序和测试代码

  • 发布说明和文档

文档影响

http 驱动程序的文档将添加到库中。此文档将遵循其它驱动程序提供的文档的风格,并应包括以下主题

  • http 驱动程序架构概述

  • 先决条件

  • 驱动程序选项概述

  • Consul 配置

  • HTTP 广播器配置

依赖项

参考资料

注意

本作品采用知识共享署名 3.0 非移植许可协议授权。 http://creativecommons.org/licenses/by/3.0/legalcode