Pro Yearly is on sale from $80 to $50! »

Eventlet, ZeroMQ, and You

Eventlet, ZeroMQ, and You

A talk I gave at PyCon Ukraine 2011.


Andrew Godwin

October 22, 2011


  1. Eventlet, ZeroMQ & You Andrew Godwin @andrewgodwin

  2. Who am I?

  3. The Plan

  4. Eventlet Asynchronous concurrency framework

  5. import eventlet from import urllib2 urls = ['', '']

    results = [] def fetch(url): results.append(urllib2.urlopen(url).read()) for url in urls: eventlet.spawn(fetch, url)
  6. Cooperative Threading You have to yield control.

  7. import eventlet import time def thread1(): time.sleep(5) # Does not

    yield print 'five seconds a' eventlet.spawn(thread1) time.sleep(5) # Does not yield print 'five seconds b'
  8. import eventlet import time def thread1(): eventlet.sleep(5) print 'five seconds

    a' eventlet.spawn(thread1) eventlet.sleep(5) print 'five seconds b'
  9. Greening the World It's that or monkeypatching.

  10. import urllib2 from import urllib2 import zmq from

    import zmq import socket from import socket
  11. Nice Primitives Not to mention less race conditions.

  12. from eventlet.timeout import Timeout try: with Timeout(30): do_stuff() except Timeout:

  13. from eventlet.semaphore import Semaphore sem = Semaphore(1) with sem: use_resource()

  14. from eventlet.queue import Queue q = Queue() def worker(): while

    True: print q.get() def producer(): while True: eventlet.sleep(1) q.put('lol') eventlet.spawn(worker) eventlet.spawn(producer)
  15. from eventlet import GreenPool from eventlet.pools import Pool conns =

    Pool(create=make_db_connection) threads = GreenPool(10) def querier(id): with pool.item() as conn: conn.execute('... WHERE id = %s', [id]) pool.imap(querier, [1, 2, 3, 4, 5])
  16. Experiences from production There's still race conditions and bad libraries.
  17. Case Study: Epio Loadbalancer Now at version three.

  18. Version One: HAProxy + reloader Occasionally slow, occasionally didn't reload.

  19. Version Two: Custom Integrated Worked alright, but leaked sockets.

  20. Version Three: Fresh, Separate Codenamed ”Mantrid”

  21. address = ('', 80) family = socket.AF_INET sock = eventlet.listen(address,

    family) eventlet.serve( sock, self.handle, concurrency = 10000, )
  22. address = ('', 8042) family = socket.AF_INET sock = eventlet.listen(address,

    family) management_app = ManagementApp(self) wsgi.server( sock, management_app.handle, )
  23. class Spin(Action): def handle(self, sock, read_data, path, headers): while True:

    # Sleep first eventlet.sleep(self.check_interval) # Check for another action action = self.balancer.resolve_host( if not isinstance(action, Spin): return action.handle( sock, read_data, path, headers )
  24. ZeroMQ I was too lazy to use an Ø.

  25. Not a message queue More like 'better sockets'.


  27. from import zmq ctx = zmq.Context() sock = ctx.socket(zmq.REQ)

    sock.connect('tcp://') sock.connect('tcp://') sock.send('hi there') print sock.recv()
  28. from import zmq ctx = zmq.Context() sock = ctx.socket(zmq.REP)

    sock.bind('tcp://') while True: message = sock.recv() sock.send('you said: %s' % message)
  29. from import zmq ctx = zmq.Context() sock = ctx.socket(zmq.PUB)

    sock.connect('tcp://') sock.send('Hello, world!')
  30. from import zmq ctx = zmq.Context() sock = ctx.socket(zmq.SUB)

    sock.bind('tcp://') while True: print sock.recv()
  31. The restrictions It's not quite too good to be true.
  32. Advanced ZeroMQ & Eventlet When one greenthread is not enough
  33. sock = ctx.socket(zmq.REQ) sock.send('help me! you're my only hope!') try:

    with Timeout(30): response = sock.recv() deal_with(response) except Timeout: cleanup()
  34. @zmq_loop(zmq.XREP, 8000) def handle_request(string): eventlet.sleep(10) return string * 2

  35. try: parts = sock.recv_multipart(flags=zmq.NOBLOCK) except zmq.ZMQError, e: if e.errno ==

    zmq.EAGAIN: eventlet.sleep(0.1) continue else: raise identities = parts[:parts.index("")] def call(identities, data): result = func(self, data) sock.send_multipart(identities + ["", result]) eventlet.spawn_n(call, identities, parts[-1])
  36. Case Study: Epio Logging We really, really like data

  37. Logging clients They're the things that make logs

  38. Logging servers They're the things that save and store logs

  39. # Servers zmq.PULL -> Recieves logs zmq.REP -> Lets website

    query for log data # Clients zmq.PUSH -> Sends logs, connected to all servers
  40. Conclusions Where Andrew waffles for a bit.

  41. Thanks. Andrew Godwin @andrewgodwin