【问题标题】:Majordomo broker throughput measurementMajordomo 代理吞吐量测量
【发布时间】:2014-12-15 05:48:55
【问题描述】:

我正在测试 majordomo 代理的吞吐量。 github上majordomo代码附带的test_client.c发送同步请求。我想测试 majordomo 代理可以实现的最大吞吐量。规范 (http://rfc.zeromq.org/spec:7) 说它每秒最多可以切换一百万条消息。

首先,我将客户端代码更改为异步发送 100k 请求。即使将所有套接字上的 HWM 设置得足够高,并将 TCP 缓冲区增加到 4 MB,我仍然观察到三个客户端并行运行的数据包丢失。

所以我将客户端更改为一次发送 10k 个请求,然后为它收到的每个回复发送两个请求。我选择 10k 是因为这允许我并行运行多达 10 个客户端(每个客户端发送 100k 条消息)而不会丢失任何数据包。这是客户端代码:

#include "../include/mdp.h"
#include <time.h>
int main (int argc, char *argv [])
{
    int verbose = (argc > 1 && streq (argv [1], "-v"));
    mdp_client_t *session = mdp_client_new (argv[1], verbose);
    int count1, count2;
    struct timeval start,end;
    gettimeofday(&start, NULL);
    for (count1 = 0; count1 < 10000; count1++) {
        zmsg_t *request = zmsg_new ();
        zmsg_pushstr (request, "Hello world");
        mdp_client_send (session, "echo", &request);
    }
    for (count1 = 0; count1 < 45000; count1++) {
        zmsg_t *reply = mdp_client_recv (session,NULL,NULL);
        if (reply)
        {
            zmsg_destroy (&reply);
            zmsg_t *request = zmsg_new ();
            zmsg_pushstr (request, "Hello world");
            mdp_client_send (session, "echo", &request);
            request = zmsg_new ();
            zmsg_pushstr (request, "Hello world");
            mdp_client_send (session, "echo", &request);
        }
        else
            break; //  Interrupted by Ctrl-C
    }

    /* receiving the remaining 55k replies */
    for(count1 = 45000; count1 < 100000; count1++)
    {
        zmsg_t *reply = mdp_client_recv (session,NULL,NULL);
        if (reply)
        {
            zmsg_destroy (&reply);
        }
        else
        break;
    }
    gettimeofday(&end, NULL);
    long elapsed = (end.tv_sec - start.tv_sec) +((end.tv_usec - start.tv_usec)/1000000);
    printf("time = %ld\n", elapsed);
    printf ("%d replies received\n", count1);
    mdp_client_destroy (&session);
    return 0;
}

我在同一台机器上运行代理、工作者和客户端。这是记录的时间:

number of clients in parallel 
(each client sends 100k )                           Time elapsed (seconds)

1                                                   4                

2                                                   9

3                                                   12

4                                                   16

5                                                   21

10                                                  43

因此,对于每 10 万个请求,代理大约需要 4 秒。这是预期的行为吗?我不确定如何达到每秒百万条消息。

最新更新:

我想出了一个提高系统吞吐量的方法:

  1. 两个代理而不是一个。其中一个代理 (broker1) 负责将客户端请求发送给工作人员,而另一个代理 (broker2) 负责将工作人员的响应发送给客户端。

  2. worker 向 broker1 注册。

  3. 客户端生成唯一的 id 并向 broker2 注册。

  4. 与请求一起,客户端还将其唯一 ID 发送给 broker1。

  5. Worker 从请求中提取唯一的客户端 ID,并将其响应(连同必须向其发送响应的客户端 ID)发送到 broker2。

现在,每 10 万个请求大约需要 2 秒而不是 4 秒(使用单个代理时)。我在代理代码中添加了 gettimeofday 调用,以测量代理本身增加了多少延迟。

这是我记录的

  1. 100k 请求(总时间:~2 秒)-> 代理添加的延迟为 2 秒
  2. 200k 请求(总时间:~4 秒)-> 代理添加的延迟为 3 秒
  3. 300k 请求(总时间:~7 秒)-> 代理添加的延迟为 5 秒

所以大部分时间都花在了代理代码上。有人可以建议如何改进这一点。

【问题讨论】:

    标签: sockets zeromq distributed distributed-computing


    【解决方案1】:

    最大吞吐量受代理的最大吞吐量的约束,但它也受工作人员的最大吞吐量的约束。

    在我看来,您似乎只开始了一名工人。如果您仔细阅读 majordomo 协议规范,它说代理应该能够每秒最多切换数百万条消息,但并不能保证单个工作人员每秒可以处理数百万条请求。

    鉴于工作人员一次只处理一个请求并与工作人员使用完全同步的对话(代理在得到答复之前不会发送另一个请求),因此不可能通过单个工作人员,甚至单个工作人员:在回复和下一个请求之间执行与代理的完整网络往返,因此工作人员大部分时间都在等待。

    对于初学者,您应该尝试添加更多工人 :-)

    编辑:快速演示。

    我使用带有 ZeroMQ 的 Majordomo 模式的 Python 实现来运行回显服务。当然,这是 Python 代码将进行全面错误检查,而 C 版本应该快得多,但它显示了让多个工作人员响应回复的影响。

    测试设置

    1. 1 个客户
    2. 客户端一次最多发送 1000 个未完成的请求(最初发送 1000 个,然后客户端在每次收到响应时发送一个新请求);
    3. 客户端一共发送了100,000个请求;

    结果

    • 使用 1 个工作器,客户端在 13.6 秒内获得 100,000 条回复 (~7300 RPS)。
    • 使用 2 名工作人员,客户端在 8.0 秒内获得 100,000 条回复 (~12500 RPS)。
    • 使用 3 名工作人员,客户端在 7.8 秒内获得 100,000 条回复 (~13000 RPS)。

    使用更多客户端将在代理中产生更好的吞吐量,因为它将在多个套接字上执行 I/O,但计算总代理吞吐量并不容易,因此我将留给您测量。

    【讨论】:

    • 一旦客户端请求到达代理,就会调用函数 service_dispatch。因此,broker 在发送请求之前不会等待收到 worker 的回复。
    • @user1274878 假设您使用reference implementation 或符合majordomo protocol specification 的实现,服务分派算法将请求放入代理的内存中每个服务队列中。该请求只会发送给空闲的工作人员。代理只会在收到初始的READY 消息或来自工作人员的REPLY 消息后发送请求。
    • @user1274878 引用规范:“MDP/Worker 是由 service worker 发起的同步请求-回复对话和双向独立操作的异步心跳对话的混合体。”
    • 对不起,但我仍然不相信。我再次查看了服务调度代码。特定服务的工作人员存储在队列中(等待是服务结构中的成员)。当请求到达时,调用 service_dispatch 方法,从队列中弹出一个工作人员,将请求发送给它,然后将工作人员附加回队列中。假设只有一个worker,它将被定位在队列的头部。现在,如果另一个请求到达,即使代理没有收到它的回复,它也会被发送给工作人员。
    猜你喜欢
    • 1970-01-01
    • 2016-11-16
    • 2015-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-16
    • 1970-01-01
    • 2016-11-08
    相关资源
    最近更新 更多