6

我有一个应用程序需要定期发送其当前状态的快照,当前状态将由大约 500,000 条 64 字节消息表示。我一直难以使用 ZMQ 快速可靠地发送和接收这么多消息。

我目前一直在通过 tcp 使用 PUB/SUB 来执行此操作,但我并不热衷于模式或协议,只要它能完成工作。在我的实验中,我专注于处理发送和接收高水位标记、发送和接收缓冲区设置,并在发送循环中添加一些睡眠以尝试减慢它的速度。使用对我来说似乎相当慷慨的设置(500K HWM,10MB 缓冲区)并且仅使用环回连接,消息仍然无法始终如一地接收。

我对这些或其他调整参数的适当设置感兴趣,更广泛地对如何推断各种设置将产生的影响感兴趣。

一些可能有助于提供适当答案的进一步细节:

  • 分布是一对多的。预计收件人人数约为 20 人。

  • 每条消息代表一组关于不同金融工具的信息,所有这些信息都是同时观察到的。在我看来,既可以将它们组合成一个大消息(所有消息的集合在逻辑上构成一个完整的快照),也可以将它们分开(客户可能只对某些工具感兴趣,我认为这会有所帮助更容易过滤掉它们)。

  • 消息的预期频率基本上不快于每 20 毫秒,也不慢于 5 秒。我实际登陆的位置可能会受到性能考虑的影响(即,我的服务器实际上可以多快将消息抽出,以及什么样的数据速率会证明对客户端来说是压倒性的)。

4

2 回答 2

5

让我们分解一下。

首先,为什么 HWM 不能“工作”:

HWM 不是一个确切的限制,因为内部缓冲区由两个单独的线程填充和清空,当有很多活动时,可用空间的计数可能会滞后很多。0MQ zmq_setsockopt 手册页说:“0MQ 不保证套接字将接受与 ZMQ_SNDHWM 一样多的消息,实际限制可能会降低 60-70%,具体取决于套接字上的消息流。”

其次,您为什么会丢失消息:

当您将 0.5M 消息 (x 20) 转储到套接字的缓冲区中时,您将随机命中 HWM,然后 PUB 套接字的行为是丢弃它无法排队的消息。

三、如何解决:

将状态分解为单独的消息的理由为零;这样做的唯一理由是,如果状态不适合记忆,它很容易做到。作为多部分发送(ZMQ_SNDMORE);这将创建一条有效消息,该消息在传出缓冲区中占用 1 个插槽。

然后,删除您的 500K HWM 限制并恢复为默认值 (1000),这将绰绰有余。

四、如何获得更好的性能:

显然,尽可能地描述和改进您的发布者和订阅者代码;这些是通常的瓶颈。

然后,如果消息是稀疏的,请考虑对消息进行某种形式的压缩,并且您可以在没有太多 CPU 成本的情况下做到这一点。在 20 个订阅者时,您从网络开销中获得的收益通常比从 CPU 成本中损失的多。

最后,如果您增长到更多的订阅者并且它是一个关键系统,请查看 PGM 多播,这将有效地消除网络成本。

于 2012-12-15T08:42:34.170 回答
1

经过一天半随机的各种组合试验,我得出以下初步结论:

  • 在我的发送循环中添加 sleep 语句以限制消息速率,基本上可以使用任何一组选项来提高可靠性。

  • 将 500,000 条消息作为单个消息的帧而不是 500,000 条单独的消息发送可以提高可靠性。

  • 使用 epgm 而不是 tcp 协议可以实现更高的吞吐量。

  • 使用 epgm,多播速率选项需要与 sleep 语句实现的所需消息速率相匹配。

  • 增加高水位线和缓冲区有助于提高可靠性,但您必须同时增加这两个设置,并在客户端和服务器上都这样做。如果所有这些都没有结合起来,它往往无济于事。您必须将这些设置得相当高才能使单个消息(而不是单个消息的帧)运行任何类型的可靠性。在这种情况下,直到我将高水位标记设置为 1,000,000 并将缓冲区设置为 65 MB 之前,我并没有得到好的结果。(两倍于我试图发送的消息集的大小。)这远远高于我本能地想尝试的。该案例在每轮 500K 消息之间暂停 5 秒。将间隔降低到 1 秒,我不得不将它们推得更高,达到单批消息大小的 4 倍。

  • 使用 epgm,恢复间隔设置没有多大帮助。

于 2012-12-14T21:03:38.913 回答