centos 单个消息的最差延迟

ruarlubt  于 2022-12-18  发布在  其他
关注(0)|答案(2)|浏览(180)

我需要构建一个实时的低延迟消息传递系统。
我读了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。
有什么办法可以减少延迟吗?

vm0i2vca

vm0i2vca1#

建立TCP连接的开销并不小--而且ZMQ的开销会增加,因为创建连接的操作是在后台完成的,需要一些TCP往返。
因此,第一条消息的延迟不仅仅是消息本身的延迟,而是消息的延迟加上建立连接所涉及的消息的延迟。
另一件需要注意的事情是,1字节是一个“惊人的”低效的有效负载,即使是普通的TCP。如果ZMQ在发送时做了“任何”类型的批处理,这将大大改善大量消息的延迟。我不知道它是否在引擎盖下做了这些事情。但事实仍然是1字节与1000字节一样背负着TCP和ZMQ两者为建立连接所涉及的相同的不可避免的开销,它仅仅压倒了发送1字节所涉及的等待时间,并且对于1000字节来说是可以忽略的。
我建议你发送两条消息,并观察每条消息的延迟--如果我是对的,第二条消息应该回到大约25微秒的范围内。如果是这样的话,那么这个开销是否会带来问题就取决于你了。我想实际上不会。

ifmq2ha2

ifmq2ha22#

ZMQ不连续发送消息,即底层TCP套接字上的zmq_send()和send()函数之间没有1:1的关系。作为一个消息队列,它给缓冲区提供了在TCP实际发送之间填充至少一些消息的机会。这种延迟非常小,但足以允许同时发送许多消息,潜在地利用两点之间的整个可用带宽。如果我没有弄错,ZMQ的IO将自动调整自己,以最大化吞吐量,同时在发送之间不填充缓冲区的情况下保持尽可能少的延迟。因此,如果通过TCP,真实的延迟可能高达100毫秒甚至更长,但如果队列被足够快地填充,实际上一次发送数千条消息。

相关问题