我有一个应用程序,周期性地需要发送其当前状态的快照,当前状态将由大约500,000个64字节消息表示.使用ZMQ,我很难快速可靠地发送和接收这么多消息.
我一直在使用PUB/SUB而不是tcp这样做,但是我不会拘泥于模式或协议,只要它能完成工作.在我的实验中,我专注于使用发送和接收高水位标记,发送和接收缓冲区设置,以及向发送循环添加一些睡眠以尝试将其减慢一点.对我来说设置似乎相当慷慨(500K HWM,10MB缓冲区)并且仅使用环回连接,消息仍然不是一直被接收的.
我对这些或其他调整参数的适当设置感兴趣,更广泛地了解如何推断各种设置将产生的效果.
一些可能有助于提供适当答案的进一步细节:
分布是一对多.预计接收人数约为20人.
每条消息代表一组关于不同金融工具的信息,所有信息都同时被观察到.在我看来,可以将它们组合成一个大消息(所有消息的集合在逻辑上构成一个完整的快照)和保持它们分开(客户可能只对某些仪器感兴趣,并且我认为这将有所帮助)更容易过滤掉它们).
消息的预期频率基本上不会快于每20毫秒,并且不会慢于5秒.我实际降落的地方可能会受到性能考虑因素的影响(即,我的服务器实际上可以将消息抽出多快以及哪种数据速率对客户来说是压倒性的).
让我们打破这个.
首先,为什么HWM没有"工作":
HWM不是一个确切的限制,因为内部缓冲区由两个独立的线程填充和清空,并且当有大量活动时,可用空间的数量可能会滞后很多.0MQ zmq_setsockopt手册页说:"0MQ不保证套接字将接受与ZMQ_SNDHWM消息一样多的数量,并且实际限制可能会低多达60-70%,具体取决于套接字上的消息流."
第二,你为什么要丢失消息:
当您将0.5M消息(x 20)转储到套接字缓冲区时,您将随机命中HWM,然后PUB套接字的行为将丢弃它无法排队的消息.
三,如何解决这个问题:
将状态分解为单独的消息是没有理由的; 唯一的理由是,如果国家不适应记忆,那很容易.发送为multipart(ZMQ_SNDMORE); 这会创建一个有效的消息,在传出缓冲区中占用1个插槽.
然后,删除500K HWM限制并恢复为默认值(1000),这将是绰绰有余的.
第四,如何获得更好的表现:
显然,尽可能地描述和改进您的发布者和订阅者代码; 这些是通常的瓶颈.
然后,如果消息稀疏,可以考虑对消息进行某种形式的压缩,并且可以在没有太多CPU成本的情况下执行此操作.在20个订户中,您通常会从网络开销中获得更多,而不会因为CPU成本而损失.
最后,如果您增加到更多用户并且它是一个关键系统,请查看PGM多播,这将有效地消除网络成本.
经过一天的半随机试验各种组合后,我得出了以下初步结论:
在我的发送循环中添加睡眠语句以限制消息速率,可以提高基本上任何选项集的可靠性。
将 500,000 条消息作为单个消息的帧发送,而不是 500K 单独的消息,可以提高可靠性。
使用 epgm 而不是 tcp 协议可以实现更高的吞吐量。
对于 EPGM,多播速率选项需要与睡眠语句实现的所需消息速率相匹配。
增加高水位线和缓冲区有助于可靠性,但您必须增加这两个设置,并在客户端和服务器上执行此操作。如果所有这些都不结合起来,往往不会有帮助。您必须将它们设置得相当高,才能使单个消息(而不是单个消息的帧)运行任何类型的可靠性。在本例中,直到将高水位线设置为 1,000,000 并将缓冲区设置为 65 MB 后,我才获得良好的结果。(是我尝试发送的消息集大小的两倍。)这远远超出了我本能地想尝试的水平。该案例在每轮 500K 消息之间暂停 5 秒。将间隔降低到 1 秒后,我必须将它们推得更高,达到单批消息大小的 4 倍。
对于epgm,恢复间隔设置没有太大帮助。