负载测试 ZeroMQ (ZMQ_STREAM) 以找到它可以处理的最大同时用户

Posted

技术标签:

【中文标题】负载测试 ZeroMQ (ZMQ_STREAM) 以找到它可以处理的最大同时用户【英文标题】:Load testing ZeroMQ (ZMQ_STREAM) for finding the maximum simultaneous users it can handle 【发布时间】:2014-05-13 07:31:12 【问题描述】:

有没有人在实际场景中对 ZMQ 套接字进行负载测试以获得最大数量。他们可以处理的“并发用户”(不是吞吐量)?看起来 ZeroMQ 在 FD 限制方面存在一些严重问题。

场景是:有许多网络服务器框架吹嘘他们可以处理数百万并发用户 - 现在如果 ZeroMQ 无法处理超过 FD_SETSIZE 没有。任何时间点的用户数量,对可扩展性都是一个非常严重的限制(因为 FD 不仅是进程资源,也是机器资源,所以在同一台机器上生成新进程没有意义)。

为了验证,我正在尝试加载测试 ZMQ_STREAM 以找出它可以维持多少并发用户。它是一个简单的“hello-world”响应服务器,它只侦听 ZMQ_STREAM 并为每个请求返回“hello world”(在严格的接收后发送样式中)。

现在,在使用 JMeter 进行测试时(使用 users=1000),点击断言:zmq_assert (fds.size () <= FD_SETSIZE)。这意味着什么?那个 ZMQ 持有 FD_SETSIZE 个 FD?但是(根据下面的代码)每个连接都会立即打开和关闭,我看不出有可能在任何时间点同时打开多个 FD。

问题:如果是这种情况,任何基于 ZMQ 的应用程序的方式是什么 实现百万用户并发连接? (除了 每次处理 1000 台机器的明显且毫无意义的解决方案 1000 个用户,或者将 FD_SETSIZE 增加到一个非常大的数字)

任何人都知道这些 FD 的使用方式和原因以及它们是如何耗尽的(更重要的是,其他框架,例如 nginx node.js 没有这个问题),请提供一些启示。

服务器代码如下:

#include <zmq.h>
#include <assert.h>
#include <string.h>
#include <iostream>
int main(void)

    void *ctx = zmq_ctx_new();

    void *socket = zmq_socket(ctx, ZMQ_STREAM);
    int rc = zmq_bind(socket, "tcp://*:8080");
    uint8_t id[256];
    size_t id_size = 256;
    char msg[4096];
    size_t msg_size = 4096;
    int nCount = 0;
    char http_response[] =
        "HTTP/1.0 200 OK\r\n"
        "Content-Type: text/plain\r\n"
        "\r\n"
        "Hello, World!";
    int nResponseLen = strlen(http_response);
    while (1) 
        id_size = zmq_recv(socket, id, 256, 0);
        msg_size = zmq_recv(socket, msg, sizeof(msg), 0);
        msg[msg_size] = '\0';
        std::cout << ++nCount << " -----\n";

        zmq_send(socket, id, id_size, ZMQ_SNDMORE);
        zmq_send(socket, http_response, nResponseLen, ZMQ_SNDMORE);

        zmq_send(socket, id, id_size, ZMQ_SNDMORE);
        zmq_send(socket, 0, 0, ZMQ_SNDMORE);
    
    zmq_close(socket);
    zmq_ctx_destroy(ctx);
    return 0;

使用 JMeter,users=1000

【问题讨论】:

你的操作系统是什么? zeromq.jira.com/browse/LIBZMQ-57 操作系统是windows。是的,知道增加 FD_SETSIZE 作为解决方法的可能性。但更感兴趣的是找出实现最大数量的正确方法。并发连接数(使用 ZMQ,如果可能,其他框架如何避免这个问题)。如果 ZMQ 套接字的每个连接的客户端都需要一个新的 FD,那么我们又回到了“每个客户端一个线程”风格的资源匮乏服务器问题(slashdot、c10k 等)的游戏中。 FD 可能比线程便宜,但仍然是可扩展性瓶颈。 【参考方案1】:

当您说“每个连接都立即打开和关闭”时,您究竟是什么意思?您绑定在stream 套接字上,该套接字接受while 循环中的传入请求,该循环永久运行并且从不关闭任何内容。循环后对zmq_close(socket); 的调用永远不会到达。

即使消息的最后一部分也明确使用了ZMQ_SNDMORE,这应该保持连接打开等待更多文本。我猜想可能是为了让少数客户端减少重复连接的开销。应该是:

zmq_send(socket, 0, 0, 0);

我不知道这些问题中的哪一个会释放资源以允许更多的客户端,如果有的话,但可能是滥用 ZMQ(或至少被误导)尝试在其中编写 HTTP 服务器或尝试使其扩展到数百万并发对等点/客户端。

node.js 和 nginx 是基于事件的并发 I/O 系统,它们在架构上与 ZMQ 有很大不同,它们是为解决不同的问题而设计的。试图将 ZMQ 融入其中是错误的做法。您可能想要将 node.js 与 socket.io 一起使用,或者如果您将它用于 HTTP,那么只需使用它的原生 http 模块。

【讨论】:

关于 ZMQ 不适合此类事情,您是对的 - 但最近很少有人声称 ZMQ_ROUTER_RAW 和 ZMQ_STREAM 套接字相反。因此进行负载测试,看看他们是否真的有能力做一些严肃的工作——但直到现在还找不到任何证据。至于连接和 ZMQ_SNDMORE,出于某种原因,这就是示例要求它们的方式(注意不要遵循它们会导致奇怪的结果)。无论如何,目标是确认 ZMQ 具有这些严重的资源限制。看来ZMQ还有很长的路要走。 明白了,这是有道理的,尽管我会犹豫只将这里所做的工作定性为“严肃的工作”......众所周知,ZMQ 可以以合理的方式处理高消息负载同行/客户的数量非常好。您是否介意在此处发布 ZMQ 适用于您所针对的工作负载类型的声明的链接? 顺便说一句,他在Pieter Hintjen's blog entry 中编写了这似乎基于的代码(我在底部看到了您的评论),他肯定用0 而不是关闭send ZMQ_SNDMORE。我想 C++ 绑定可能存在问题(尽管这似乎不太可能)。无论如何,请尝试使用该修复程序,看看您是否会得到不同的结果。 另外,about a year ago in this zmq mailing list post Hintjen 表示,他对这个人达到 10 万个连接感到“印象深刻”,暗示这可能并不容易。 +1 谢谢杰森。说得通。关于使用 0,这确实是我的第一次尝试——也没有任何好转。这里是相关q:***.com/questions/23305254/…

以上是关于负载测试 ZeroMQ (ZMQ_STREAM) 以找到它可以处理的最大同时用户的主要内容,如果未能解决你的问题,请参考以下文章

通过 AWS 负载均衡器连接 ZeroMQ 端点

使用ZeroMq源测试Kuiper吞吐量

ZeroMQ 作业分配

grpc 和 zeromq 比较

ZeroMQ/ZMQ 推/拉模式的用处

ZeroMQ中PUB-SUB模式测试