C++11 为什么ZeroMQ路由器-经销商模式具有高延迟?

C++11 为什么ZeroMQ路由器-经销商模式具有高延迟?,c++11,ubuntu-16.04,centos7,zeromq,latency,nanomsg,C++11,Ubuntu 16.04,Centos7,Zeromq,Latency,Nanomsg,在centos 7上使用libzmq 4.2.5。当消息从经销商发送到路由器时,甚至从路由器发送到经销商时,延迟非常高。因此,我使用tcp编写了一个简单的客户机-服务器程序,并在它们之间发送消息以进行比较。Tcp看起来很快 将单个字节从经销商发送到路由器,zmq需要900微秒 tcp从客户端向服务器发送单个字节需要150微秒 我做错了什么。我想zmq至少会和tcp一样快。我能做些什么调整来使zmq更快 更新 路由器 #include <zmq.hpp> struct data

在centos 7上使用libzmq 4.2.5。当消息从
经销商
发送到
路由器
时,甚至从
路由器
发送到
经销商
时,延迟非常高。因此,我使用tcp编写了一个简单的客户机-服务器程序,并在它们之间发送消息以进行比较。Tcp看起来很快

将单个字节从
经销商
发送到
路由器
zmq
需要900微秒

tcp从客户端向服务器发送单个字节需要150微秒

我做错了什么。我想
zmq
至少会和tcp一样快。我能做些什么调整来使
zmq
更快

更新

路由器

#include <zmq.hpp>
    struct data
    {
    char one[21];
    unsigned long two;
   };
data * pdata;
std::size_t counter=0;

 int main()
{
   zmq::context_t context(1);
   zmq::socket_t Device(context,ZMQ_ROUTER);

   int iHighWaterMark=0;

  Device.setsockopt(ZMQ_SNDHWM,&iHighWaterMark,sizeof(int));
  Device.setsockopt(ZMQ_RCVHWM,&iHighWaterMark,sizeof(int));

  Device.bind("tcp://0.0.0.0:5555");

  pdata=new data[10000];

 struct timespec ts_dtime;
 unsigned long sec;

  zmq::message_t message;

  zmq::pollitem_t arrPollItems[]={{Device, 0, ZMQ_POLLIN, 0},{NULL, 
                                                            0, ZMQ_POLLIN, 0}};

    while(counter < 10000)
      {
        try
      {
        int iAssert = zmq::poll(arrPollItems, 1, -1);
        if (iAssert <= 0)
          {
             if (-1 == iAssert)
          {
             printf("zmq_poll failed errno: %d error:%s", errno, 
                                 zmq_strerror(errno));
          }
            continue;
           }

          if (arrPollItems[0].revents == ZMQ_POLLIN)
           {
             while(true)
            {
               if(! Device.recv(&message,ZMQ_DONTWAIT))
                    break;

               Device.recv(&message);

                strncpy(pdata[counter].one, 
                                      (char*)message.data(),message.size());
               clock_gettime(CLOCK_REALTIME, &ts_dtime);
              pdata[counter].two = (ts_dtime.tv_sec*1e9)+ 
                                                              ts_dtime.tv_nsec;
              ++counter;
            }

           }
      }
          catch(...)
        {

         }

          }

         for(int i=0;i<counter;++i)
         printf("%d %s %lu\n",i+1,pdata[i].one,pdata[i].two);

         return 0;
        }
#include <zmq.hpp>
#include <stdio.h>
#include <stdlib.h>

int main (int argc, char *argv[])
{
    const char *bind_to;
    int roundtrip_count;
    size_t message_size;

    int rc;
    int i;


    if (argc != 4) {
        printf ("usage: local_lat <bind-to> <message-size> "
                "<roundtrip-count>\n");
        return 1;
    }
    bind_to = argv[1];
    message_size = atoi (argv[2]);
    roundtrip_count = atoi (argv[3]);

    zmq::context_t ctx(1);
  zmq::socket_t s(ctx,ZMQ_ROUTER);

  zmq::message_t msg,id;

    int iHighWaterMark=0;
    s.setsockopt(ZMQ_SNDHWM , &iHighWaterMark,
                         sizeof (int));
    s.setsockopt(ZMQ_RCVHWM , &iHighWaterMark,
                                              sizeof (int));
    s.bind( bind_to);
    struct timespec ts_dtime;
    unsigned long sec;
for (i = 0; i != roundtrip_count; i++) {
      rc =s.recv(&id);
        if (rc < 0) {
            printf ("error in zmq_recvmsg: %s\n", zmq_strerror (errno));
            return -1;
        }

        rc = s.recv(&msg, 0);
        if (rc < 0) {
            printf ("error in zmq_recvmsg: %s\n", zmq_strerror (errno));
            return -1;
        }

        clock_gettime(CLOCK_REALTIME, &ts_dtime);
        sec=((ts_dtime.tv_sec*1e9)+ ts_dtime.tv_nsec);
        printf("%.*s %lu\n",20,(char *)msg.data(),sec);
}




    s.close();



    return 0;
}
都在350-450us的范围内

问题1:我做错了什么?
我想
zmq
至少会和tcp一样快。 代码方面,什么都没有

就性能而言,ZeroMQ is fantastic plus具有许多功能,因此
tcp
不会也不会立即提供:

测试设置“发送单字节…”似乎直接进入了高性能/低延迟消息服务的左边缘:

让我们首先了解延迟及其来源: 观察到的结果延迟数字是资源使用量(资源分配+资源池管理操作+数据操作)和处理工作量(由于系统调度器计划的多任务工作单元调度,我们试图处理的所有数据,包括我们的任务必须花费在等待队列中的时间,这些数据不是来自我们的测试工作负载,而是操作系统必须根据公平调度策略和实际进程优先级设置进行调度和执行)和通信信道传输延迟(通信E2E传输延迟)

让我们接下来了解我们试图与之进行比较的内容: 传输控制协议(raw
tcp
)与ZeroMQ
zmq
智能可伸缩正式通信原型框架(具有丰富的高级分布式行为)之间的区别大约有几个星系

ZeroMQ被设计成一个信令和消息传递基础设施,使用了一些功能丰富的行为集,这些行为集通常由一些类似人类的行为原型描述:

一个
推送
-es,任意数量的加入交易对手
拉送

一个
REQ
-ests,电话另一端的一组人
REP
-lies

一个,甚至可能是一个更大的代理组,
-lishes,任何数量的已经订阅的订阅者都会收到这样一条
子签名的消息

有关详细信息,请阅读[]部分中关于主要概念差异的简要概述

这是TCP协议无法单独提供的

这是一种舒适感,人们喜欢通过一些可以忽略不计的延迟来支付。可以忽略不计?是的,与许多人*年的终极软件技术相比,任何人都必须为设计另一个至少类似的智能消息框架来与ZeroMQ竞争而付费

问题2:我能做些什么调整来使
zmq
更快? 也许是的,也许不是

更新:
-尝试避免身份管理(tcp也没有这样的东西,所以测量的RTT-s比较小或有意义)
-尝试避免HWM配置的阻塞方式(tcp也没有这种情况)
-可以尝试通过非tcp协议(一个
PAIR/PAIR
正式的可伸缩通信原型,最好通过最不复杂的协议数据泵,如
inproc://
is或
ipc://
,以防您的沙箱测试台仍然需要保存分布式非本地副本等)来测量相同的性能ZeroMQ
context
-实例在
.send()
resp.
.receive()
方法上花费的内部开销
-可以尝试通过为
上下文
实例使用更多可用线程来略微提高性能
(其他性能去屏蔽技巧取决于实际使用的性质——对丢弃的消息的鲁棒性、使用合并操作模式的可行性、与O/S更好的缓冲区对齐、零拷贝技巧——所有这些都是本文感兴趣的,但必须让并保持分布式行为的智能ZeroMQ基础设施运行,要执行的任务要复杂得多,而不是一个简单的串行序列,否则是盲目的和孤立的tcp套接字字节级操作-因此,比较时间是可能的,但比较单个龙德拉格斯特级汽车(好吧,更好的汽车,甚至不是汽车)具有类似于分布式行为的全球运营基础设施(如Taxify或Uber,在这里命名只是为了利用大致相同规模的平凡(不)相似性)留下一些关于现象的报告,这些现象没有提供类似的舒适性、用例的可伸缩性、几乎线性的性能伸缩性和真实世界使用的健壮性)
-通过将
上下文
-实例各自的
IoTHREADs
-硬连线到各自的CPU内核上,可以添加更多的调度确定性,从而使总体I/O性能永远不会从CPU调度中退出,并保持确定性映射/预锁定,即使是专用的管理CPU内核-如果试图进行此终极性能测试,则取决于需求和管理策略的级别

对于任何与性能相关的调整,都需要
#include <zmq.hpp>
#include <stdio.h>
#include <stdlib.h>

int main (int argc, char *argv[])
{
    const char *bind_to;
    int roundtrip_count;
    size_t message_size;

    int rc;
    int i;


    if (argc != 4) {
        printf ("usage: local_lat <bind-to> <message-size> "
                "<roundtrip-count>\n");
        return 1;
    }
    bind_to = argv[1];
    message_size = atoi (argv[2]);
    roundtrip_count = atoi (argv[3]);

    zmq::context_t ctx(1);
  zmq::socket_t s(ctx,ZMQ_ROUTER);

  zmq::message_t msg,id;

    int iHighWaterMark=0;
    s.setsockopt(ZMQ_SNDHWM , &iHighWaterMark,
                         sizeof (int));
    s.setsockopt(ZMQ_RCVHWM , &iHighWaterMark,
                                              sizeof (int));
    s.bind( bind_to);
    struct timespec ts_dtime;
    unsigned long sec;
for (i = 0; i != roundtrip_count; i++) {
      rc =s.recv(&id);
        if (rc < 0) {
            printf ("error in zmq_recvmsg: %s\n", zmq_strerror (errno));
            return -1;
        }

        rc = s.recv(&msg, 0);
        if (rc < 0) {
            printf ("error in zmq_recvmsg: %s\n", zmq_strerror (errno));
            return -1;
        }

        clock_gettime(CLOCK_REALTIME, &ts_dtime);
        sec=((ts_dtime.tv_sec*1e9)+ ts_dtime.tv_nsec);
        printf("%.*s %lu\n",20,(char *)msg.data(),sec);
}




    s.close();



    return 0;
}
#include <zmq.hpp>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main (int argc, char *argv[])
{
    const char *connect_to;
    int roundtrip_count;
    size_t message_size;

    int rc;
    int i;

    void *watch;
    unsigned long elapsed;
    double latency;

    if (argc != 4) {
        printf ("usage: remote_lat <connect-to> <message-size> "
                "<roundtrip-count>\n");
        return 1;
    }
    connect_to = argv[1];
    message_size = atoi (argv[2]);
    roundtrip_count = atoi (argv[3]);

    zmq::context_t ctx(1);
  zmq::socket_t s(ctx,ZMQ_DEALER);

  struct timespec ts_dtime;
  unsigned long sec;
int iHighWaterMark=0;
    s.setsockopt(ZMQ_SNDHWM , &iHighWaterMark,
                         sizeof (int));
    s.setsockopt(ZMQ_RCVHWM , &iHighWaterMark,
                                              sizeof (int));

    s.connect(connect_to);


    for (i = 0; i != roundtrip_count; i++) {
      zmq::message_t msg(message_size+20);
      clock_gettime(CLOCK_REALTIME, &ts_dtime);
      sec=(ts_dtime.tv_sec*1e9)+ ts_dtime.tv_nsec;
      sprintf((char *)msg.data(),"%lu",sec);
      rc = s.send(msg);
        if (rc < 0) {
            printf ("error in zmq_sendmsg: %s\n", zmq_strerror (errno));
            return -1;
        }

        sleep(1);
}
s.close();


    return 0;
}
1562125527489432576 1562125527489773568
1562125528489582848 1562125528489961472
1562125529489740032 1562125529490124032
1562125530489944832 1562125530490288896
1562125531490101760 1562125531490439424
1562125532490261248 1562125532490631680
1562125533490422272 1562125533490798080
1562125534490555648 1562125534490980096
1562125535490745856 1562125535491161856
1562125536490894848 1562125536491245824
1562125537491039232 1562125537491416320
1562125538491229184 1562125538491601152
1562125539491375872 1562125539491764736
1562125540491517184 1562125540491908352
1562125541491657984 1562125541492027392
1562125542491816704 1562125542492193536
1562125543491963136 1562125543492338944
1562125544492103680 1562125544492564992
1562125545492248832 1562125545492675328
1562125546492397312 1562125546492783616
1562125547492543744 1562125547492926720
1562125564495211008 1562125564495629824
1562125565495372032 1562125565495783168
1562125566495515904 1562125566495924224
1562125567495660800 1562125567496006144
1562125568495806464 1562125568496160000
1562125569495896064 1562125569496235520
1562125570496080128 1562125570496547584
1562125571496235008 1562125571496666624
1562125572496391424 1562125572496803584
1562125573496532224 1562125573496935680
1562125574496652800 1562125574497053952
1562125575496843776 1562125575497277184
1562125576496997120 1562125576497417216
1562125577497182208 1562125577497726976
1562125578497336832 1562125578497726464
1562125579497549312 1562125579497928704
1562125580497696512 1562125580498115328
1562125581497847808 1562125581498198528
1562125582497998336 1562125582498340096
1562125583498140160 1562125583498622464
1562125584498295296 1562125584498680832
1562125585498445312 1562125585498842624
1562125586498627328 1562125586499025920