Quick ZeroMQ Round Robin (push-pull) with Python

Posted on Friday, August 10, 2012

Before I get too far into this one I finally found the documentation for PyZMQ API at http://zeromq.github.com/pyzmq/api/index.html [1].

This has been very helpful to me in figuring some of this stuff out.

… Now onto the problem at hand, how do you do round-robin with ZeroMQ?  For those unfamiliar with the concept of round robin you can see the Wikipedia page about it here http://en.wikipedia.org/wiki/Round-robin_scheduling [2].  In short you can have a group of workers and a foreman handing out work.   Think of your machines as the workers, let’s say there are 10.  The foreman gets a job and hands it out to the first worker, the second job to the second, and so on until he gets the last worker (the 10th).   After he has run out of workers to hand jobs to he starts the process over again handing the next job to the first worker…

Now beyond this simple example you can expand the idea out.  What if a worker leaves?  What if he comes back?  What if you have a job and the next worker is too busy to grab it?   ZeroMQ handles a lot of these ideas right out of the box.

In ZeroMQ they use the term  PUSH/PULL which is round-robin if you go to this page http://api.zeromq.org/2-1:zmq-socket [3] and search for ZMQ_PUSH and ZMQ_PULL you will get a lot more details then I will show here.  To quote the page

The pipeline pattern is used for distributing data to nodes arranged in a pipeline. Data always flows down the pipeline, and each stage of the pipeline is connected to at least one node. When a pipeline stage is connected to multiple nodes data is round-robined among all connected nodes.

A socket of type ZMQ_PUSH is used by a pipeline node to send messages to downstream pipeline nodes.

This guide assumes you already have ZeroMQ and related libraries installed and running on your machine.  If you have not installed any ZeroMQ refer to this guide Quick ZeroMQ with Python 
   This code was all written and tested on an Ubuntu 12.04 server installation.


First let’s write the push program

I am going to run this on a local virtual Ubuntu machine that already has all the necessary zeroMQ libraries installed.  The machines address is

Open the document for editing

       > vi zeroMQ_PUSH.py

import zmq
import time
ctx = zmq.Context()
push_socket= ctx.socket(zmq.PUSH)
for x in range(20):
    msg = str(x) + " , " + str(time.time())
    print x
    #Pause 1 second

This is a simple program it binds a push to the port 1234.
It starts sending out messages via push (round robin)


I am going to run this on a local virtual Ubuntu machine that already has all the necessary zeroMQ libraries installed.  The machines address is and

Open the document for editing

       >    vi zeroMQ_PULL.py

import zmq
ctx = zmq.Context()
pull_socket = ctx.socket(zmq.PULL)
while True:
    msg = pull_socket.recv()
    print msg

Now run this program from 2 machines and 163

They both sit there and wait for messages to come in.

Now, once they are both running, start up the PUSH program

Then you will see the work getting divided out between the two.  On the first machine

You can see it gets the first two messages in a row (probably because the second machine has not yet connected up with the PUSH machine)

Here is the output from the second machine.

If I run this again and kill one of the PULL machines midway through….

You can see the second machine now gets all the messages, since the first machine was turned off after message 7.

If I turn it off then bring it back…

You can after message 7 the second machine came online and the work was distributed between the two.

ZeroMQ does a lot of the heavy lifting, getting back connections so you do not have to.  You can focus on programming new features rather than doing all this heavy lifting maintaining connections, dropouts and reconnections.

 [1]  The PyZQM API
       Visited 08/2012
[2]  Wikipedia: Round-robin scheduling
       Visited 08/2012
[3]  zmq socket
       Visited 08/2012

No comments:

Post a Comment