20/ZRE
ZeroMQ 实时交换协议
- 状态:已淘汰
- 编辑:Pieter Hintjens ph@imatix.com
ZeroMQ 实时交换协议(ZRE)规定了网络上的一组对等方如何相互发现、组织成组以及相互发送事件。ZRE 运行在 ZeroMQ ZMTP 协议之上。请注意,本规范已被 rfc.zeromq.org/spec:36/ZRE 取代。
前言
版权所有 (c) 2009-2013 iMatix Corporation
本规范是自由软件;您可以根据自由软件基金会发布的 GNU 通用公共许可证的条款重新分发和/或修改它;许可证的第三版,或者(由您选择)任何后续版本。分发本规范是希望它有用,但没有任何担保;甚至不包括适销性或特定用途适用性的隐含担保。有关更多详情,请参阅 GNU 通用公共许可证。您应该已经随程序收到一份 GNU 通用公共许可证的副本;如果未收到,请参见 https://gnu.ac.cn/licenses。
本规范是一个自由和开放标准,受数字标准组织的共识导向规范系统管辖。
本文档中的关键词“MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、“MAY”和“OPTIONAL”应按照 RFC 2119 中的描述进行解释。
目标
ZRE 协议提供了一种方式,使本地网络上的一组节点可以相互发现、跟踪对等方何时加入和离开、发送消息给单个对等方(单播)以及发送消息给对等方组(多播)。其目标是
- 无需任何集中服务或中介,只需使用网络默认提供的服务即可工作。
- 在低质量网络上具有鲁棒性,特别是无线网络。
- 最小化检测新对等方到达网络所需的时间。
- 从瞬时连接故障中恢复。
- 与操作系统、编程语言和硬件无关。
- 允许任意数量的节点在一个进程中运行,以实现大规模模拟和测试。
- 提供跨网络收集日志信息的机制。
实现
节点标识和生命周期
一个 ZRE 节点代表消息的源或目标。节点通常映射到应用程序。ZRE 节点由一个 16 字节的通用唯一标识符 (UUID) 识别。ZRE 不定义如何创建或销毁节点,但确实假设节点具有一定的持久性。
节点发现和存在
ZRE 使用 UDP IPv4 信标广播来发现节点。每个 ZRE 节点 必须 监听 ZRE 发现服务,即 UDP 端口 5670(由 IANA 分配的 ZRE-DISC 端口)。每个 ZRE 节点 必须 定期在 UDP 端口 5670 上广播一个信标,以向网络上任何监听的节点标识自己。
ZRE 信标由一个 22 字节的 UDP 消息组成,格式如下
+---+---+---+------+ +------+------+
| Z | R | E | %x01 | | UUID | port |
+---+---+---+------+ +------+------+
Header Body
头部 必须 由字母 ‘Z’、‘R’ 和 ‘E’ 组成,后跟信标版本号,版本号 必须 是 %x01。
正文 必须 由发送方的 16 字节 UUID 组成,后跟一个按网络字节序排列的两字节邮箱端口号。如果端口号非零,则表明对等方将接受在该端口号上的 ZeroMQ TCP 连接。如果端口号为零,则表明对等方正在断开网络连接。
一个有效的信标 必须:使用可识别的头部;使用正确大小的正文;并提供非零的邮箱端口号。接收到无效信标的节点 必须 默默丢弃它。节点 可以 记录发送方的 IP 地址用于调试目的。节点 必须 丢弃自己发送并收到的信标。
当 ZRE 节点接收到来自它尚不知道的节点且端口号非零的信标时,它 必须 将此视为一个新对等方。
当 ZRE 节点接收到来自已知节点且端口号非零的信标时,它 必须 与此对等方断开连接。
互连模型
每个节点 必须 创建一个 ZeroMQ ROUTER 套接字并将其 绑定 到一个临时 TCP 端口(范围在 %C000x - %FFFFx)。节点 必须 在其发送的所有信标中广播此邮箱端口号。请注意,节点不广播其 IP 地址,因为这由 UDP recvfrom 函数提供。
此 ROUTER 套接字 必须 用于接收来自其他节点的所有 ZeroMQ 消息。节点 必须 不 通过此套接字发送消息给对等方。
当节点发现一个新对等方时,它 必须 创建一个 ZeroMQ DEALER 套接字,在该套接字上设置其身份(二进制 16 字节 UUID),并将其 连接 到对等方的邮箱端口。节点可以在连接后立即通过此 DEALER 套接字开始向对等方发送消息。
一个节点 必须 将每个 DEALER 套接字连接到至多一个对等方。如果对等方在一段时间内未能响应(参见心跳机制),节点可以断开其 DEALER 套接字。
此 DEALER 套接字 必须 用于向特定对等方发送所有 ZeroMQ 消息。节点 必须 不 在此套接字上接收消息。发送方 可以 设置一个高水位标记 (HWM),例如每秒 100 条消息(如果超时周期是 30 秒,这意味着 HWM 是 3,000 条消息)。发送方 应 将套接字上的发送超时设置为零,以便可以检测到完整的发送缓冲区并将其视为“对等方无响应”。
请注意,ROUTER 套接字为调用方提供套接字上接收到的任何消息的发送方 UUID,作为消息中其他帧之前的身份帧。因此,对等方可以使用接收到消息中的身份来查找用于回发给该对等方的相应 DEALER 套接字。身份 必须 是一个二进制的 16 字节 UUID 值。
当节点在其 ROUTER 套接字上收到来自未知节点的有效消息时,它 必须 将此视为一个新对等方,其处理方式与收到来自未知节点的 UDP 信标时完全相同。
注意:ZRE 使用的 ROUTER-to-DEALER 模式旨在确保消息永远不会因同步问题而丢失。发送到尚未连接到对等方的 ROUTER 套接字会导致消息被丢弃。
协议签名
通过 TCP 发送的每条 ZRE 消息 必须 以 ZRE 协议签名 %xAA %xA1 开头。节点 必须 默默丢弃任何接收到的不以这两个字节开头的数据。
此机制专门设计用于绑定到临时端口的应用程序,这些端口可能之前已被其他协议使用,并且仍有节点试图连接。它也是一种通用的快速失败机制,用于检测格式错误的消息。
TCP协议语法
以下 ABNF 语法定义了 ZRE 协议,其中所有命令都由一个节点(发送方,“S:")发送给另一个对等方(接收方,“R:")
zre-protocol = greeting *traffic
greeting = S:HELLO
traffic = S:WHISPER
/ S:SHOUT
/ S:JOIN
/ S:LEAVE
/ S:PING R:PING-OK
; Greet a peer so it can connect back to us
S:HELLO = signature %x01 sequence ipaddress mailbox groups status headers
signature = %xAA %xA1
sequence = 2OCTET ; Incremental sequence number
ipaddress = string ; Sender IP address
string = size *VCHAR
size = OCTET
mailbox = 2OCTET ; Sender mailbox port number
groups = strings ; List of groups sender is in
strings = size *string
status = OCTET ; Sender group status sequence
headers = dictionary ; Sender header properties
dictionary = size *key-value
key-value = string ; Formatted as name=value
; Send a message to a peer
S:WHISPER = signature %x02 sequence content
content = FRAME ; Message content as 0MQ frame
; Send a message to a group
S:SHOUT = signature %x03 sequence group content
group = string ; Name of group
content = FRAME ; Message content as 0MQ frame
; Join a group
S:JOIN = signature %x04 sequence group status
status = OCTET ; Sender group status sequence
; Leave a group
S:LEAVE = signature %x05 sequence group status
; Ping a peer that has gone silent
S:PING = signature %06 sequence
; Reply to a peer's ping
R:PING-OK = signature %07 sequence
ZRE 命令
HELLO 命令
每个节点 必须 通过发送 HELLO 命令作为连接到对等方的第一个命令来启动对话。
当节点收到来自新对等方的消息时,它 必须 默默忽略任何在 HELLO 命令之前的命令。
HELLO 命令包含以下字段
- ip地址- 发送方将接受连接的 IP 地址。
- 邮箱- 发送方邮箱的端口号。
- 组- 发送方所在的组列表,以字符串列表形式表示。
- 状态- 发送方的组状态序列。
- 头部字段- 发送方设置的零个或多个属性。
如果接收方尚未连接到此对等方,它 必须 创建一个 ZeroMQ DEALER 套接字并将其连接到指定为“tcp://ip地址:邮箱”的端点。
“组状态序列”是一个单字节数字,每当对等方加入或离开组时都会递增。每个对等方 可以 使用此序列来断言其自身组管理信息的准确性。
WHISPER 命令
当节点希望向单个对等方发送消息时,它 必须 使用 WHISPER 命令。WHISPER 命令包含一个字段,即定义为单个 0MQ 帧的消息内容。ZRE 不支持多帧消息内容。
SHOUT 命令
当节点希望向参与某个组的一组节点发送消息时,它 必须 使用 SHOUT 命令。SHOUT 命令包含两个字段:组的名称,以及定义为单个 0MQ 帧的消息内容。
请注意,消息通过 TCP 上的 ZeroMQ 发送,因此 SHOUT 命令是单播到每个应该接收它的对等方。ZRE 不提供任何 UDP 多播功能。
JOIN 命令
当节点加入组时,它 必须 向所有对等方广播 JOIN 命令。JOIN 命令有两个字段:要加入的组的名称,以及加入组 后 的组状态序列号。组名区分大小写。
LEAVE 命令
当节点离开组时,它 必须 向所有对等方广播 LEAVE 命令。LEAVE 命令有两个字段:要离开的组的名称,以及离开组 后 的组状态序列号。
PING 命令
节点 应 向在一定时间内(通常是五秒)没有收到 UDP 信标的任何对等方发送 PING 命令。请注意,在高度饱和的网络上可能会丢弃 UDP 流量。如果节点在较长一段时间内(通常是 30 秒)没有收到对 PING 命令的回复,也没有收到来自对等方的其他流量,它 应 将该对等方视为已死亡。
请注意,PING 命令 应 仅用于对等方沉默的有针对性的情况。否则,PING 命令的成本将随连接的对等方数量呈指数级增长,并可能降低网络性能。
PING-OK 命令
当节点收到 PING 命令时,它 必须 回复 PING-OK 命令。
ZRE 扩展协议
ZRE 允许添加共享 ZRE 发现机制的扩展协议。这些协议具有以下共同属性
- 它们使用基于 TCP 的 ZeroMQ 消息传递;
- 它们基于一种服务模型,其中每个节点可以提供零个或多个服务;
- 每个服务绑定到一个临时端口并向其他节点宣布自己;
- 希望使用服务的节点可以连接到它。
每个扩展协议使用特定的 ZeroMQ 套接字模式和消息格式。目前 ZRE 支持两种扩展协议
要宣布一个扩展协议,节点会在 HELLO 命令中添加一个 headers 字段,格式如下
service-name=tcp://ipaddress:port
我们正式指定这些扩展协议
- ZRE 日志收集协议 (ZRE/LOG),它提供了一个子系统,用于从分布式网络收集日志数据。服务名称是“X-ZRELOG”。
ZRE/LOG 扩展协议
日志服务 必须 创建一个 ZeroMQ SUB 套接字并将其 绑定 到一个临时 TCP 端口(范围在 %C000x - %FFFFx)。日志服务 必须 在 HELLO 命令中广播其连接端点,如上所述。任何希望发送日志数据的节点 必须 创建一个 PUB 套接字并将其连接到此端点。
每条 ZRE/LOG 消息 必须 以协议签名 %xAA %xA2 开头。日志服务 必须 默默丢弃任何接收到的不以这两个字节开头的数据。
以下 ABNF 语法定义了 ZRE/LOG 协议
zrelog-protocol = *LOG
; Send a log message to the log service
LOG = signature %x01 level event node peer time data
header = signature
signature = %xAA %xA2
level = ERROR / WARNING / INFO
ERROR = %x01
WARNING = %x02
INFO = %x03
event = JOIN / LEAVE / ENTER / EXIT / SEND / RECV
JOIN = %x01 ; We joined a group
LEAVE = %x02 ; We left a group
ENTER = %x03 ; Peer joined network
EXIT = %x04 ; Peer left network
SEND = %x05 ; Sent outgoing message
RECV = %x06 ; Received message
node = 2OCTET ; Hash of node UUID
peer = 2OCTET ; Hash of peer UUID
time = 8OCTET ; Time in msecs
data = string ; Printable error text
string = size *VCHAR
size = OCTET
节点发现和存在
ZRE 使用 UDP IPv4 信标广播来发现节点并跟踪其存在。其工作方式如下
- 一个 ZRE 节点 必须 监听 ZRE 发现服务,即 UDP 端口 5670(由 IANA 分配的 ZRE-DISC 端口)。
- 每个 ZRE 节点 必须 定期广播一个 UDP 信标,以向网络上任何监听的节点标识自己。
- 当 ZRE 节点收到来自它尚不知道的节点的信标时,它 必须 将此视为一个新对等方。
- 当 ZRE 节点停止接收来自它已知对等方的信标时,经过一定间隔后,它 必须 将此对等方视为已断开连接或已死亡。
ZRE 信标由一个 22 字节的 UDP 消息组成,格式如下
+---+---+---+------+ +------+------+
| Z | R | E | %x01 | | UUID | port |
+---+---+---+------+ +------+------+
Header Body
实施者注意事项
- 头部 必须 由字母 ‘Z’、‘R’ 和 ‘E’ 组成,后跟信标版本号,版本号 必须 是 %x01。
- 正文 必须 由发送方的 16 字节 UUID 组成,后跟一个按网络字节序排列的两字节邮箱端口号。
- 一个有效的信标 必须:使用可识别的头部;使用正确大小的正文;并提供非零的邮箱端口号。
- 接收到无效信标的节点 必须 默默丢弃它。节点 可以 记录发送方的 IP 地址用于调试目的。
- 节点 必须 丢弃自己发送并收到的信标。
安全方面
ZRE 安全性由底层传输处理。对于 ZMTP v2 和 v1,没有安全模型,所有信息都以明文形式交换。对于 ZMTP v3,可以使用任何已定义的安全机制。