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? http://www.flickr.com/photos/maistora/3014414972

  3. The Plan http://www.flickr.com/photos/snapsi42/2609025344/

  4. Eventlet Asynchronous concurrency framework http://www.flickr.com/photos/pagedooley/2814895287/

  5. import eventlet from eventlet.green import urllib2 urls = ['http://ep.io', 'http://t.co']

    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. http://www.flickr.com/photos/nickwheeleroz/3406931272/

  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. http://www.flickr.com/photos/mightyboybrian/3457507731/

  10. import urllib2 from eventlet.green import urllib2 import zmq from eventlet.green

    import zmq import socket from eventlet.green import socket
  11. Nice Primitives Not to mention less race conditions. http://www.flickr.com/photos/mightyboybrian/3457507731/

  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. http://www.flickr.com/photos/jasohill/118616905/

  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(self.host) if not isinstance(action, Spin): return action.handle( sock, read_data, path, headers )
  24. ZeroMQ I was too lazy to use an Ø. http://www.flickr.com/photos/andresrueda/2926348197/

  25. Not a message queue More like 'better sockets'. http://www.flickr.com/photos/96dpi/3816391053/


  27. from eventlet.green 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 eventlet.green 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 eventlet.green import zmq ctx = zmq.Context() sock = ctx.socket(zmq.PUB)

    sock.connect('tcp://') sock.send('Hello, world!')
  30. from eventlet.green 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 http://www.flickr.com/photos/jasohill/118616905/

  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. http://www.flickr.com/photos/oimax/108058706/

  41. Thanks. Andrew Godwin @andrewgodwin http://aeracode.org