新的 ZeroMQ 驱动程序实现细节¶
https://blueprints.launchpad.net/oslo.messaging/+spec/zmq-patterns-usage
本规范提出新的 ZeroMQ 驱动程序实现细节。该提案可以被视为 [1] 的扩展以及进一步的驱动程序开发路线图。图表和流程图见 [2]。
问题描述¶
Oslo.messaging 提供了组件之间几种通信模式。这些模式是 CAST(FANOUT)、CALL 和 NOTIFY。
ZeroMQ 驱动程序可以通过多种方式实现。现有的驱动程序实现坚持使用通用的 socket 管道方法。这意味着所有消息传递模式都通过单个 socket 管道实现。
在 [1] 中,曾提出从分割的通用前向(PUSH/PULL)+后向(PUB/SUB)管道切换到统一的 REQ/REP 双向管道。这种改变简化了驱动程序实现并使其更可靠,但管道仍然是通用的。
通用管道的主要缺点是无法针对某些特定的消息传递模式进行优化。例如,如果我们想通过通用管道(PUSH/PULL 或 REQ/REP 无所谓)进行 FANOUT cast,我们必须通过多次直接 cast 来模拟它,而可以使用 PUB/SUB zeromq 模式通过单个 api 调用来完成。
本规范建议根据每种消息传递模式,扩展新的 zmq 驱动程序实现,并使用多个特定的 socket 管道。
提议的变更¶
ZMQ 代理¶
在客户端和服务器之间使用代理实体的主要原因是 zmq 库缺乏将多个 socket 绑定到单个 IP 端口的能力。
另一种方法是使用动态端口绑定,就 zmq API 而言,这意味着使用 zmq.Socket.bind_to_random_port() 方法。
尽管无代理的动态端口绑定看起来很有吸引力,但以下严重的问题表明代理解决方案实际上更简单、更可靠。
动态端口绑定建立连接需要更多时间。如果系统中的端口过多繁忙,并且该函数需要多次重试,则可能超过时间限制。
端口数量限制为 16 位整数 2^16 = 65535。因此,未占用端口的数量也可能达到极限,尤其是在大规模云环境中。
不太关键但重要的复杂性是需要以某种方式通知客户端所选端口。可以使用 Redis 在节点之间传递信息来实现这种机制。在 1 中,Redis 同步表所需的时间必须添加到连接时间中。由于网络延迟,这里的延迟可能比 1 更大。
所有这些因素使我们更倾向于代理解决方案。它也有其缺点,但优点是
建立连接的时间更可预测。
为驱动程序分配的固定端口数。
重要的是,代理应尽可能靠近 rpc-server,并应被视为 rpc-server 的一部分。即使它是一种虚拟主机,代理也不是一个中央代理,不应将其运行在单独的主机上。
代理通过 IPC 协议与 rpc-server 通信,并将其与 TCP 网络隔离开来。为了实现“专用 socket 管道”的概念,我们可以为每个管道使用一个单独的代理,以保持它们之间的独立性。
专用 Socket 管道¶
补充 [1] 的变更提案的主要部分。目的是为 oslo.messaging 模式实现使用最合适的 zmq 模式。
REQ/REP (ROUTER/DEALER) 用于 CALL
在 [1] 规范中,曾提出使用基于 REQ/REP 构建的 socket 管道。我们在这里没有改变主意,并保持这个管道,但仅将其用于 CALL 模式的目的。
PUB/SUB 用于 FANOUT CAST
PUB socket 提供了向多个连接的主机发布消息的可能性。SUB 允许订阅到多个发布者,这些发布者正在监听特定主题。在中间有一个代理,我们实际上有 2 步 FANOUT 消息传递。第一步是节点之间的 TCP。第二步是节点内部 rpc-server 订阅主题。
rpc-client(PUB:TCP) -> (XSUB:TCP)proxy(XPUB:IPC) -> (SUB:IPC)rpc-server
为了确切知道哪个主机正在监听哪个主题,我们需要云中间的某种目录服务 (DS)。该服务很可能驻留在控制器节点上。它可以是分布式或独立的。DS 的地址应通过配置选项传递给驱动程序。
Rpc-server 监听器将记录放入 DS,记录内容为主机 + 它正在监听的主题。Rpc-client 获取主题的所有主机,并向它们发布消息。
从某种意义上说,DS 成为一个单点故障,因为在 DS 停止运行的情况下,FANOUT 将无法正常工作。因此,对于实际部署,应将所有标准的 HA 方法应用于该服务。
DS 实现的第一个候选者是 Redis,但并非一定如此。
值得注意的是,使用 DS 并不会模拟中央代理的概念。所有消息都直接从节点到节点发送,因此我们仍然保持消息级别的点对点,这对于可扩展性非常重要。我们也不要在使用直接消息传递模式(如 CALL)时浪费时间请求 DS。在本地代理(代理)上缓存 DS 状态也可以帮助减少对中央节点(节点)的依赖。但后者是一种优化问题。
PUSH/PULL 用于直接 CAST
这是可选的,但 PUSH/PULL 是直接 CAST 的确切模式,因此应该是最优的。从技术上讲,直接 CAST 可以通过任何可用的 zmq socket 类型来实现。
PUB/SUB 用于 Notifier
PUB/SUB zeromq 模式非常适合 Notifier 实现。为了保持 socket 管道以及消息传递模式实现彼此独立,我们需要在另一个管道中进行此操作,尽管 2 也使用 PUB/SUB。
Notifier 的使用不如 RPC(1-3)广泛,因此此项目可以在后续迭代中选择性地实现。Ceilometer 似乎是该模式的主要客户端。
心跳¶
由于我们在所有模式中使用 TCP 传输,因此可以使用 ZMQ_TCP_KEEPALIVE zmq 选项来检测死连接。
备选方案¶
所有内容都可以通过 [1] 中描述的通用 socket 管道来实现。
Impact on Existing APIs¶
无。
安全影响¶
为了安全地传递消息,可以使用 [3] 中的一些功能。
性能影响¶
无。
Configuration Impact¶
应添加配置选项以设置预分配的端口。
9501 - zmq REQ/REP 管道端口 9502 - zmq PUB/SUB CAST+FANOUT 端口 9503 - zmq PUB/SUB Notifier 端口 9504 - 可能的直接 CAST 端口
fanout_ds_address - 驱动程序使用的名称服务的地址。
开发人员影响¶
无。
Testing Impact¶
由于驱动程序内部结构将发生重大变化,因此应重写单元测试。
现有的功能测试应该在不进行更改的情况下通过。也许我们可以通过添加一些更棘手的情况来扩展它们。
我们还有 py27-func-zeromq 配置作为 CI gate 作业运行。应该使用此 gate 来检查新的驱动程序。
我们需要一些多节点部署测试。还需要一些 HA 场景测试。
实现¶
负责人¶
- 主要负责人
ozamiatin
里程碑¶
完成目标里程碑:liberty-3
工作项¶
修改自 [1] 的工作项
- 实现 CALL (REQ/REP) 管道和周围的模块
将消息序列化、主题操作等从现有实现移动到适当的模块
rpc_client 部分
broker_part
rpc_server 部分
回复处理
通过 PUSH/PULL 管道实现 CAST(客户端-代理-服务器)
实现 FANOUT 及其 PUB/SUB 管道
实现 Notifier 分离的 PUB/SUB 管道
孵化¶
无。
采用¶
部署指南可能会略有不同,因为添加了一些新的配置选项(例如,为每个管道分配的额外端口)。
值得注意的是,在稳定期间,旧驱动程序和新驱动程序都将保留在仓库中。稳定后,旧驱动程序将通过标准的弃用路径被弃用。
库¶
oslo.messaging
预计 API 稳定¶
新的驱动程序应该能够在 devstack 上成功运行。现有的 oslo.messaging 功能测试应该能够在 devstack-gate 中成功通过。
文档影响¶
我们需要用详细的文档和 UML 图表涵盖新驱动程序的各个方面。我们还需要更新 zmq 部署指南 [4] 以适应新的驱动程序。
依赖项¶
无。
参考资料¶
注意
本作品采用知识共享署名 3.0 非移植许可协议授权。 http://creativecommons.org/licenses/by/3.0/legalcode