我需要构建一个实时的低延迟消息传递系统。
我读了ZeroMQ指南,因为我的需求ROUTER-DEALER
模式完全匹配。我围绕它构建了系统,它工作得很好。但当我做性能测试时,我发现ZeroMQ延迟高得惊人。
libzmq版本:4.2.5
./local_lat tcp://127.0.0.1:5555 1 1000
./remote_lat tcp://127.0.0.1:5555 1 1000
message size: 1 [B]
roundtrip count: 1000
average latency: 26.123 [us]
当消息数很高时,ZeroMQ性能非常好,但是当消息数为1时,延迟相当高。
./local_lat tcp://127.0.0.1:5555 1 1
./remote_lat tcp://127.0.0.1:5555 1 1
message size: 1 [B]
roundtrip count: 1
average latency: 506.500 [us]
我仍然不满意,我从ZeroMQ指南中选择了PUB-SUB
示例,修改为ROUTER-DEALER
,添加了时间戳并再次测试。延迟也非常高。这使得ZeroMQ无法使用。我同意当消息量很高时,没有什么能击败ZeroMQ,但对于延迟非常关键的系统,即使是单个消息ZeroMQ也会失败。
注意:我还运行了PUB-SUB
示例,它显示了相同的延迟数字
sender.cpp
#include <zmq.hpp>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <sys/time.h>
int main () {
// Prepare our context and publisher
zmq::context_t context (1);
zmq::socket_t publisher (context, ZMQ_ROUTER);
publisher.bind("tcp://*:5556");
//wait for peer to connect
//once connected store the identity to send message later
zmq::message_t identity,m;
publisher.recv(&identity);//identity
publisher.recv(&m);//message
sleep(1);//sleep to set up connections
struct timeval timeofday;
int i=1;//no of messages to send
while (i) {
zmq::message_t id,message("10101",5);
id.copy(&identity);
gettimeofday(&timeofday,NULL);
publisher.send(id,ZMQ_SNDMORE);
publisher.send(message);
std::cout << timeofday.tv_sec << ", " << timeofday.tv_usec << std::endl;
usleep(1);
--i;
}
return 0;
}
型
reciever.cpp
#include <zmq.hpp>
#include <iostream>
#include <sys/time.h>
int main (int argc, char *argv[])
{
zmq::context_t context (1);
zmq::socket_t subscriber (context, ZMQ_DEALER);
subscriber.setsockopt(ZMQ_IDENTITY,"1",1);
subscriber.connect("tcp://localhost:5556");
struct timeval timeofday;
subscriber.send(" ",1);
int update_nbr;
int i=1;
for (update_nbr = 0; update_nbr < i; update_nbr++) {
zmq::message_t update;
subscriber.recv(&update);
gettimeofday(&timeofday,NULL);
std::cout << timeofday.tv_sec << ", " << timeofday.tv_usec << std::endl;
}
return 0;
}
发送器输出
1562908600, 842072
接收机输出
1562908600, 842533
如您所见,这大约需要400 ms。
有什么办法可以减少延迟吗?
2条答案
按热度按时间vm0i2vca1#
建立TCP连接的开销并不小--而且ZMQ的开销会增加,因为创建连接的操作是在后台完成的,需要一些TCP往返。
因此,第一条消息的延迟不仅仅是消息本身的延迟,而是消息的延迟加上建立连接所涉及的消息的延迟。
另一件需要注意的事情是,1字节是一个“惊人的”低效的有效负载,即使是普通的TCP。如果ZMQ在发送时做了“任何”类型的批处理,这将大大改善大量消息的延迟。我不知道它是否在引擎盖下做了这些事情。但事实仍然是1字节与1000字节一样背负着TCP和ZMQ两者为建立连接所涉及的相同的不可避免的开销,它仅仅压倒了发送1字节所涉及的等待时间,并且对于1000字节来说是可以忽略的。
我建议你发送两条消息,并观察每条消息的延迟--如果我是对的,第二条消息应该回到大约25微秒的范围内。如果是这样的话,那么这个开销是否会带来问题就取决于你了。我想实际上不会。
ifmq2ha22#
ZMQ不连续发送消息,即底层TCP套接字上的zmq_send()和send()函数之间没有1:1的关系。作为一个消息队列,它给缓冲区提供了在TCP实际发送之间填充至少一些消息的机会。这种延迟非常小,但足以允许同时发送许多消息,潜在地利用两点之间的整个可用带宽。如果我没有弄错,ZMQ的IO将自动调整自己,以最大化吞吐量,同时在发送之间不填充缓冲区的情况下保持尽可能少的延迟。因此,如果通过TCP,真实的延迟可能高达100毫秒甚至更长,但如果队列被足够快地填充,实际上一次发送数千条消息。