【问题标题】:zeromq, C++, is it necessary to set a high water mark for subscribers?zeromq,C++,是否需要为订阅者设置高水位线?
【发布时间】:2013-04-20 03:47:56
【问题描述】:

我对 ZeroMQ PUB/SUB 进行了快速测试,现在有了一些工作代码。但是,我对 zeromq 中应用的高水位线的概念有点困惑。

我在发布者代码中设置了一个 HWM,它为连接到套接字的每个订阅者设置队列长度。

然而,也可以在订阅者的接收套接字上设置一个 HWM。是否有任何理由在订阅者端设置 HWM,这与设置发布者 HWM 有何不同?

【问题讨论】:

    标签: zeromq publish-subscribe


    【解决方案1】:

    简答:

    发布者中,我们几乎总是应该仔细考虑 HWM,因为有很多原因会导致崩溃(内存不足)影响整个系统(因为发布者为所有订阅者提供服务)。

    同样在订阅者中,在某些情况下调节 HWM 可能是有用的,但这主要取决于订阅者的性质、它如何处理收到的消息以及大量接收到的消息无法及时处理的概率;以及预期的运行时环境(可用内存量、订阅者数量等)

    更详细的答案:

    ZMQ 使用 HWM(高水位线)的概念来定义其内部管道的容量。每个从套接字出来或进入套接字的连接都有自己的管道,以及用于发送和/或接收的 HWM,具体取决于套接字类型。一些套接字(PUBPUSH只有发送缓冲区。有些(SUBPULLREQREP只有接收缓冲区。有些(DEALERROUTERPAIR)同时具有发送和接收缓冲区。

    可用的socket option 是:

    ZMQ 3.0+ 强制对其内部缓冲区(所谓的 HWM)进行默认限制,因为 HWM 是减少内存溢出问题的好方法

    ZMQ_PUBZMQ_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”,以电子格式在线提供;它有一章专门介绍 High-Water Marks,其中包含有关该主题的进一步解释。

    【讨论】:

    • 您好 Franco,感谢您的回答,这有助于部分回答问题,但在实施方面仍有些不清楚。听起来我想要订阅者和发布者上的 HWM 以避免双方崩溃,所以我会使用 ZMQ_DEALER。我是否需要在 client.cpp 和 server.cpp 中显式设置 ZMQ_SNDHWM 和 ZMQ_RCVHWM?或者仅在 server.cpp 上设置 ZMQ_SNDHWM 和在 client.cpp 上设置 ZMQ_RCVHWM 是否足够
    • FI 足以在用于发送消息的套接字上设置 ZMQ_SNDHWM 并在接收消息的套接字上设置 ZMQ_RCVHWM。你会使用不同的模式,请阅读api.zeromq.org/3-0%3azmq-socket并注意ZMQ_HWM选项操作,因为它根据套接字的类型而有所不同。
    • @FrancoRondini,感谢您的详尽回答,对我帮助很大。
    【解决方案2】:

    如果您一次订阅超过 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));
    

    效果很好。

    【讨论】:

    • 主题数和它有什么关系?确定它取决于数据速率吗?
    • 嗯...我想在一开始就订阅所有主题,但我有超过 1000 个。所以这是一个问题,因为事实上订阅甚至在对等点连接之前就可能发生。也许,一步一步地做,说有一些延迟,它可以工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-23
    • 1970-01-01
    相关资源
    最近更新 更多