【问题标题】:zeromq with high latencyzeromq 具有高延迟
【发布时间】:2021-07-31 00:27:25
【问题描述】:

我正在尝试使用 PUB / SUB 模式使用 zeromq 运行本地低延迟控制循环。

但是,在不同的标准 Ubuntu LTS 安装(从 16.xx 到 20.xx)和不同的 PC 上都运行默认内核,我遇到了 0.3ms 到 > 1ms 之间的相当高的延迟。

我的 zeromq 版本是 4.3.2,cppzmq 版本是 4.2(但我在节点和 PHP 绑定方面也遇到了同样的问题)。

示例输出:

TOPIC                  RECV_US              SEND_US
[datawriter_CPLUSPLUS] 1627690147280.142090 1627690147279.663086
[datawriter_CPLUSPLUS] 1627690147380.287109 1627690147379.824951
[datawriter_CPLUSPLUS] 1627690147480.525879 1627690147480.058105
[datawriter_CPLUSPLUS] 1627690147580.789062 1627690147580.251953
[datawriter_CPLUSPLUS] 1627690147680.885010 1627690147680.388916
[datawriter_CPLUSPLUS] 1627690147781.051025 1627690147780.531982
[datawriter_CPLUSPLUS] 1627690147881.116943 1627690147880.676025
[datawriter_CPLUSPLUS] 1627690147981.365967 1627690147980.818115
[datawriter_CPLUSPLUS] 1627690148081.508057 1627690148080.954102
[datawriter_CPLUSPLUS] 1627690148181.571045 1627690148181.091064
[datawriter_CPLUSPLUS] 1627690148281.747070 1627690148281.235107
[datawriter_CPLUSPLUS] 1627690148381.841064 1627690148381.378906
[datawriter_CPLUSPLUS] 1627690148482.018066 1627690148481.541992
[datawriter_CPLUSPLUS] 1627690148582.245117 1627690148581.775879
[datawriter_CPLUSPLUS] 1627690148682.593018 1627690148681.972900

输出来自运行以下我为调试而编写的简单发布者和订阅者程序:

出版商

#include "zhelpers.hpp"
#include <future>
#include <iostream>
#include <string>

int main()
{
    zmq::context_t ctx;
    zmq::socket_t publisher(ctx, zmq::socket_type::pub);
    publisher.bind("tcp://127.0.0.1:3000");

    struct timeval time;
    while (true) {
        gettimeofday(&time, NULL);
        unsigned long long microsec = ((unsigned long long)time.tv_sec * 1000000) + time.tv_usec;
        std::string string = std::to_string(microsec/1E3);
        zmq::message_t message(string.size());
        std::memcpy (message.data(), string.data(), string.size());

        publisher.send(zmq::str_buffer("datawriter_CPLUSPLUS"), zmq::send_flags::sndmore);
        publisher.send(message);
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}

订阅者


#include "zhelpers.hpp"
#include <future>
#include <iostream>
#include <string>

int main () {
    zmq::context_t context(1);
    zmq::socket_t subscriber (context, ZMQ_SUB);
    subscriber.connect("tcp://localhost:3000");
    subscriber.setsockopt( ZMQ_SUBSCRIBE, "datalogger_CPLUSPLUS", 1);
    
    struct timeval time;

    while (1) {
        std::string address = s_recv (subscriber);
        std::string contents = s_recv (subscriber);
        
        gettimeofday(&time, NULL);
        unsigned long long microsec = ((unsigned long long)time.tv_sec * 1000000) + time.tv_usec;
        std::string string = std::to_string(microsec/1E3);


        std::cout << "[" << address << "] " << string << " " << contents << std::endl;
    }
    return 0;
}

我的目标延迟低于 100 微秒,而不是当前的 300 - 1300 微秒。 上面的延迟对我来说看起来非常高,如果这是我的 zeromq、实现或我的系统/内核配置的问题,我有点想不通。

添加

这是我机器的上下文切换时间,在不同的运行中非常一致:

./cpubench.sh
model name : AMD Ryzen 7 PRO 4750U with Radeon Graphics
1 physical CPUs, 8 cores/CPU, 2 hardware threads/core = 16 hw threads total
-- No CPU affinity --
10000000 system calls in 874207825ns (87.4ns/syscall)
2000000 process context switches in 4237346473ns (2118.7ns/ctxsw)
2000000  thread context switches in 4877734722ns (2438.9ns/ctxsw)
2000000  thread context switches in 318133810ns (159.1ns/ctxsw)
-- With CPU affinity --
10000000 system calls in 525663616ns (52.6ns/syscall)
2000000 process context switches in 2814706665ns (1407.4ns/ctxsw)
2000000  thread context switches in 2402846574ns (1201.4ns/ctxsw)
2000000  thread context switches in 407292570ns (203.6ns/ctxsw)

这是一个在默认安装本地 redis-server 上的简单 PHP redis 脚本,其延迟(

1627695114039.4 1627695114039.2
1627695114139.8 1627695114139.6
1627695114240.1 1627695114239.9
1627695114340.3 1627695114340.2
1627695114440.5 1627695114440.3
1627695114540.7 1627695114540.6
1627695114640.9 1627695114640.8
1627695114741.2 1627695114741.1

【问题讨论】:

  • 桌面操作系统不是实时操作系统。尝试测量您的机器的任务上下文切换持续时间......我发现任务上下文切换通常比函数调用慢 3 或 4 个数量级。而且默认的 Linux 不是实时的。如果您的目标是 3 到 13 * 100(即已经比您的“需要”慢 2 个数量级),那么您可能选择了错误的系统。
  • 谢谢,我添加了一个上下文切换基准,并与使用 PHP 脚本作为读取器和写入器的标准 redis 服务器安装进行了比较。
  • 最简单的 1Gig 以太网的 Ping 时间超过 0.48 毫秒(我见过的最短时间)。鉴于这是可以通过网络执行的最简单/最快的往返事务,我怀疑 TCP(在 ZMTP 之上运行)对于单向传输的数据包可以击败一半,事实上你已经发现至少 0.3ms。有趣的是,前一段时间的传说是 100M 网络上的 ping 时间比 1Gig 网络上的要短。

标签: c++ zeromq


【解决方案1】:

您测量的延迟是从发布者中对 gettimeofday() 的调用到订阅者中的 gettimeofday() 的调用。两台 PC 的 RTC 之间的差异会有所不同,即使与 ntpd 之类的东西同步,也不会完全对齐。如果您让订阅者将消息反射回另一个套接字,那么发布者将能够测量往返时间。

话虽如此,但无论如何,我认为延迟不会比您在通过以太网进行的任何数据交换上测量的更好。流量过多地受网络中发生的所有其他事情的摆布,以及有关 PC 的事情。如果您需要保证一台 PC 会在另一台 PC 上发生事件的 100us 内做出反应,以太网/TCPIP/Linux/PC 可能是不适合使用的技术。

例如,如果您的 PC 的 CPU 决定更改电压/时钟模式,则整个 PC 可能会暂时停止,此时发生的时间超过 100 微秒。我已经看到一些 Xeon 系统在发生这种 CPU 模式更改时整机暂停 300 毫秒。这些事情超出了操作系统的控制能力 - 它位于固件层。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-14
    • 2021-09-30
    • 1970-01-01
    • 1970-01-01
    • 2023-01-18
    • 2016-07-23
    • 1970-01-01
    相关资源
    最近更新 更多