[zeromq-dev] Load balancing REQ/REP sockets

Martin Sustrik sustrik at 250bpm.com
Wed Mar 17 11:16:58 CET 2010


Jon Dyte wrote:
> Brian Granger wrote:
>> Hi,
>>
>> REQ/REP sockets have a load balancing feature.  If you have 1 master
>> with a REQ socket that binds:
>>
>>     ctx = zmq.Context()
>>     s = ctx.socket(zmq.REQ)
>>     s.bind('tcp://127.0.0.1:5555')
>>
>> And multiple workers that connect REP sockets to the REQ:
>>
>>     # Each worker does this.
>>     ctx = zmq.Context()
>>     s = ctx.socket(zmq.REP)
>>     s.connect('tcp://127.0.0.1:5555')
>>
>> When the master does a send, the requests will be load balanced to all
>> connected workers.  That works fine.
>>
>> But, a REQ socket cannot do another send until it gets back a reply
>> (by doing a recv).  So here is my question:
>>
>> How can you actually get load balancing in practice if the REQ socket
>> in the master cannot issue another send
>> (to a different worker) until first worker has replied.  Another way
>> of putting this is I don't see how to get the multiple
>> workers handling requests *simultaneously*.  Am I missing something or
>> is this by design.
>>
>> I can see how to accomplish this pattern with P2P sockets, but it
>> would require a much more complicated application logic to implement.
>>
>> thoughts?
>>
>> Cheers,
>>
>> Brian
>>
>>   
> you can get load balancing from multiple REQ sockets, but each 
> individual REQ socket
> effectively serialises each req and reply as far as I understand.
> 
> to do this intra-process you do something like see attached zmqserver.cpp
> which uses Xrep/xreq with a client like
> 
> // zmq
> #include <zmq.hpp>
> #include <unistd.h>
> #include <iostream>
> #include <stdio.h>
> 
> 
> int main(int argc , char*argv[])
> {
>  zmq::context_t ctx (1, 1);
> 
>  zmq::socket_t s (ctx, ZMQ_REQ);
> 
>  s.connect ("tcp://127.0.0.1:43210");
>  for (unsigned char i = 'A' ; i < 'Z' ; ++i)
>  {             
>    zmq::message_t request(1);
>      *((char*)request.data()) =  i;
>      printf("send %x\n", (int)     *((char*)request.data()));
>      s.send(request);
>        zmq::message_t response;
>      s.recv(&response);
>      printf("recv %x\n", (int)     *((char*)response.data()));
>      sleep(::getpid()%3);
>  }
>  return 0;
> 
> }
> 
> 
> you can also use the zmq_queue device which does the same thing but 
> doesnt use the inprocess endpoints.
> 
> thus you can have
> 
> REQ*<->SHARED_QUEUE(XREP,XREQ) <->REP*
> 
> * multiple of these, 1 shared queue.
> 
> caveat at the moment you have to do some special processing in the REP 
> socket.
> 
> Normally i have the shared queue do the binds for the xrep,xreq sockets 
> and then
> the workers(REP) and clients(REQ) connect to that.
> 
> There is a working zmq_queue device in the latest release.
> 
> does this make sense?

The whole XREQ/XREP business is still messy. If you absolutely need it 
at the moment you can use XREQ to connect and load-balance messages to 
mutliple REPs. That way you'll get what you need without a need to do 
any special processing on the REP side.

However, it's experimental functionality, so no warranty is given :)

Martin




More information about the zeromq-dev mailing list