ZeroMQ工作分配

时间:2015-06-15 17:02:42

标签: sockets client-server load-balancing zeromq

我有以下设置: 有一个客户端,多个工作人员和一个接收器。 工作人员通过ZeroMQ消息从客户端接收作业请求。他们处理输入,并将答案发送到另一个进程(接收器)。处理消息大约需要1毫秒,我们需要处理大约50,000条消息/秒 - 这意味着我们需要超过50名工作人员来处理负载。

我尝试了一个简单的设置,客户端创建了一个ZeroMQ PUSH套接字,所有工作者都连接(通过PULL)套接字。类似地,接收器创建一个PULL套接字,所有工作者都使用PUSH套接字连接到该套接字。

IIUC,ZeroMQ使用"循环法向工人发送消息" - 每次另一名工人得到这份工作。这种设置似乎能够有效地与~10名工人(以及适当的负载)一起工作。但是,当进一步增加工人数量和负载时,这会很快中断并且系统开始累积延迟。

我知道有几种模式可以解决负载均衡问题,但是它们面向多个客户端并且需要两者之间的路由器,这意味着需要额外的代码+ cpu周期。问题是:

1)在单个客户端,多个工作人员,单个接收器的情况下,最佳模式是什么?

2)是否可以在客户端与工作人员之间没有路由器的情况下通过客户端路由来实现此目的?

3)应该使用什么样的ZeroMQ套接字?

谢谢!

Diagram

编辑: 添加代码。

客户端:

    void *context = zmq_ctx_new ();

    //  Socket to send messages on
    void *sender = zmq_socket (context, ZMQ_PUSH);
    zmq_bind (sender, "tcp://*:5557");

    //  Socket to send start of batch message on
    void *sink = zmq_socket (context, ZMQ_PUSH);
    zmq_connect (sink, "tcp://localhost:5558");

    printf ("Press Enter when the workers are ready: ");
    getchar ();
    printf ("Sending tasks to workers\n");

    //  The first message is "0" and signals start of batch
    s_send (sink, "0");

    unsigned long i;
    const int nmsgs = atoi(argv[1]);
    const int nmsgs_sec = atoi(argv[2]);
    const int buff_size = 1024; // 1KB msgs
    unsigned long t, t_start;
    t_start = timestamp();
    for (i = 0; i < nmsgs; i++) {
            t = timestamp();
            // Pace the sending according to nmsgs_sec
            while( i * 1000000 / (t+1-t_start) > nmsgs_sec) {
                    // busy wait
                    t = timestamp();
            }
            char buffer [buff_size];
            // Write current timestamp in the packet beginning
            sprintf (buffer, "%lu", t);
            zmq_send (sender, buffer, buff_size, 0);
    }
    printf("Total time: %lu ms Planned time: %d ms\n", (timestamp() - t_start)/1000, nmsgs * 1000 / nmsgs_sec);

    zmq_close (sink);
    zmq_close (sender);
    zmq_ctx_destroy (context);

工人:

//  Socket to receive messages on
void *context = zmq_ctx_new ();
void *receiver = zmq_socket (context, ZMQ_PULL);
zmq_connect (receiver, receiver_addr);

//  Socket to send messages to
void *sender = zmq_socket (context, ZMQ_PUSH);
zmq_connect (sender, sender_addr);

//  Process tasks forever
const int buff_size = 1024;
char buffer[buff_size];
while (1) {
    zmq_recv (receiver, buffer, buff_size, 0);
    s_send (sender, buffer);
}
zmq_close (receiver);
zmq_close (sender);
zmq_ctx_destroy (context);

水槽:

//  Prepare our context and socket
void *context = zmq_ctx_new ();
void *receiver = zmq_socket (context, ZMQ_PULL);
zmq_bind (receiver, "tcp://*:5558");

//  Wait for start of batch
char *string = s_recv (receiver);
free (string);

unsigned long t1;
unsigned long maxdt = 0;
unsigned long sumdt = 0;

int task_nbr;
int nmsgs = atoi(argv[1]);
printf("nmsgs = %d\n", nmsgs);
for (task_nbr = 0; task_nbr < nmsgs; task_nbr++) {
    char *string = s_recv (receiver);
    t1 = timestamp();
    unsigned long t0 = atoll(string);
    free (string);

    unsigned long dt = t1-t0;
    maxdt = (maxdt > dt ? maxdt : dt);
    sumdt += dt;

    if(task_nbr % 10000 == 0) {
            printf("%d %lu\n", task_nbr, dt);
    }
}

printf("Average time: %lu usec\tMax time: %lu usec\n", sumdt/nmsgs, maxdt);

zmq_close (receiver);
zmq_ctx_destroy (context);

1 个答案:

答案 0 :(得分:0)

您有多种选择,具体取决于您当前设置中实际错误的显示位置(从您提供的信息中无法判断)。

你绝对不需要另一个&#34;中间&#34;节点

如果问题是连接量(1-> 50)是当前设置中的问题,您可以在客户端上设置多个PUSH套接字,每个套接字都有一部分工作人员,并在客户端内部进行负载均衡。

如果问题是PUSH套接字本身,你可以在&#34; push&#34;上使用DEALER套接字。 &#34;拉&#34;侧面和ROUTER插座侧。但我不认为这是个问题。

一般情况下,我希望您当前的设置是&#34;正确的&#34;一个,也许你的实现中有一个错误。你知道错误的来源吗?客户 - &gt;工人或工人 - &gt;下沉?或者也许在其他地方?