我对 ZeroMQ PUB/SUB 进行了快速测试,现在有了一些工作代码。但是,我对 zeromq 中应用的高水位线的概念有点困惑。
我在我的发布者代码中设置了一个 HWM,它为连接到套接字的每个订阅者设置队列长度。
然而,也可以在订阅者的接收套接字上设置一个 HWM。是否有任何理由在订阅者端设置 HWM,这与设置发布者 HWM 有何不同?
我对 ZeroMQ PUB/SUB 进行了快速测试,现在有了一些工作代码。但是,我对 zeromq 中应用的高水位线的概念有点困惑。
我在我的发布者代码中设置了一个 HWM,它为连接到套接字的每个订阅者设置队列长度。
然而,也可以在订阅者的接收套接字上设置一个 HWM。是否有任何理由在订阅者端设置 HWM,这与设置发布者 HWM 有何不同?
在发布者中,我们几乎应该始终仔细考虑 HWM,因为有很多原因导致崩溃(内存不足)影响整个系统(因为发布者为所有订阅者提供服务)。
同样在订阅者中,在某些情况下调节 HWM 可能是有用的,但这主要取决于订阅者的性质、它对接收到的消息做了什么以及它无法处理的概率有多高大量接收消息的时间;以及预期的运行时环境(可用内存量、订阅者数量等)
ZMQ 使用 HWM(高水位线)的概念来定义其内部管道的容量。每个从套接字出来或进入套接字的连接都有自己的管道,以及用于发送和/或接收的 HWM,具体取决于套接字类型。一些套接字 ( PUB
, PUSH
)只有发送缓冲区。有些 ( SUB
, PULL
, REQ
, REP
)只有接收缓冲区。有些 ( DEALER
, ROUTER
, PAIR
) 同时具有发送和接收缓冲区。
可用的套接字选项有:
ZMQ 3.0+ 强制对其内部缓冲区(所谓的 HWM)进行默认限制,因为 HWM 是减少内存溢出问题的好方法
两者ZMQ_PUB
都ZMQ_SUB
将ZMQ_HWM
选项操作设置为“Drop”,因此当限制丰富时,订阅者或发布者的内存应该停止增长,至少取决于 ZMQ 缓冲区。
通常最需要保护以防止不加区别地使用内存(内存不足问题)的是发布者:
在 inproc 传输中,发送方和接收方共享相同的缓冲区,因此真正的 HWM 是双方设置的 HWM 的总和。
但是如果您使用 TCP 并且订阅者很慢,则消息将在发布者上排队。
常见的故障原因PUB-SUB
包括:
通过在发布者上排队消息会使发布者耗尽内存并崩溃,尤其是在有很多订阅者并且出于性能原因而无法刷新到磁盘的情况下。
从发布者的角度来看,我们通过适当设置 ZWM 使用的最佳策略是停止排队新消息一段时间后,新消息只会被拒绝或丢弃;这是 ØMQ 在发布者设置 HWM 时所做的。
ZMQ 还可以在订阅者上排队消息
如果有人要耗尽内存并崩溃, 那将是订阅者而不是发布者, 这是公平的。这对于订阅者暂时无法跟上,但在流变慢时可以赶上的“高峰”流来说是完美的。
注意:HWM 不准确;虽然默认情况下您可能会收到多达 1,000 条消息,但由于 libzmq 实现其队列的方式,实际缓冲区大小可能要小得多(只有一半)。
这些假设的主要来源是 Pieter Hintjens 的书“Code Connected Volume 1”,以电子格式在线提供;它有一章专门讨论高水位标记,其中包含有关该主题的进一步解释。
如果您一次订阅超过 1000 个主题,那么在订阅者上设置 ZMQ_SNDHWM 会很有用(据我所知,默认情况下 ZMQ_SNDHWM 为 1000)。因此,如果您像这样订阅:
for(i = 0; i < 2000; i++)
{
subscriber.setsockopt( ZMQ_SUBSCRIBE, &i, sizeof(i));
}
由于输出队列溢出,它将不起作用。
但是如果你在连接之前设置
subscriber.setsockopt( ZMQ_RCVHWM, &i, sizeof(i));
subscriber.setsockopt( ZMQ_SNDHWM, &i, sizeof(i));
它工作得很好。