Distributed Systems with ZeroMQ and gevent Jeff Lindsay @progrium - - PowerPoint PPT Presentation

distributed systems
SMART_READER_LITE
LIVE PREVIEW

Distributed Systems with ZeroMQ and gevent Jeff Lindsay @progrium - - PowerPoint PPT Presentation

Distributed Systems with ZeroMQ and gevent Jeff Lindsay @progrium Why distributed systems? Harness more CPUs and resources Run faster in parallel Tolerance of individual failures Better separation of concerns Most web apps evolve into


slide-1
SLIDE 1

Distributed Systems

with ZeroMQ and gevent

Jeff Lindsay @progrium

slide-2
SLIDE 2

Why distributed systems?

Harness more CPUs and resources Run faster in parallel Tolerance of individual failures Better separation of concerns

slide-3
SLIDE 3

Most web apps evolve into distributed systems

slide-4
SLIDE 4
slide-5
SLIDE 5
slide-6
SLIDE 6
slide-7
SLIDE 7
slide-8
SLIDE 8
slide-9
SLIDE 9
slide-10
SLIDE 10

OpenStack

slide-11
SLIDE 11

Web API Client Amazon AWS TwiML Provider Provider Provider

slide-12
SLIDE 12

ZeroMQ + gevent

Two powerful and misunderstood tools

slide-13
SLIDE 13

Concurrency

Heart of Distributed Systems

slide-14
SLIDE 14

Distributed computing is just another flavor of local concurrency

slide-15
SLIDE 15

Multithreading Distributed system

Shared Memory Thread Thread Thread Shared Database App App App

slide-16
SLIDE 16

Concurrency models

Execution model Defines the “computational unit” Communication model Means of sharing and coordination

slide-17
SLIDE 17

Concurrency models

Traditional multithreading OS threads Shared memory, locks, etc Async or Evented I/O I/O loop + callback chains Shared memory, futures Actor model Shared nothing “processes” Built-in messaging

slide-18
SLIDE 18

Examples

Erlang Actor model Scala Actor model Go Channels, Goroutines Everything else (Ruby, Python, PHP, Perl, C/C++, Java) Threading Evented

slide-19
SLIDE 19

Normally, the networking of distributed systems is tacked on to the local concurrency model.

Erlang is special.

MQ, RPC, REST, ...

slide-20
SLIDE 20

Why not always use Erlang?

slide-21
SLIDE 21

Why not always use Erlang?

Half reasons Weird/ugly language Limited library ecosystem VM requires operational expertise Functional programming isn’t mainstream

slide-22
SLIDE 22

Why not always use Erlang?

Half reasons Weird/ugly language Limited library ecosystem VM requires operational expertise Functional programming isn’t mainstream Biggest reason It’s not always the right tool for the job

slide-23
SLIDE 23

Web API Client Amazon AWS TwiML Provider Provider Provider

slide-24
SLIDE 24

Service Oriented Architecture

Multiple languages Heterogeneous cluster

slide-25
SLIDE 25

RPC

slide-26
SLIDE 26

Client / server

RPC

slide-27
SLIDE 27

Client / server Mapping to functions

RPC

slide-28
SLIDE 28

Client / server Mapping to functions Message serialization

RPC

slide-29
SLIDE 29

Client / server Mapping to functions Message serialization

RPC

Poor abstraction of what you really want

slide-30
SLIDE 30

What you want are tools to help you get distributed actor model concurrency like Erlang ... without Erlang. Even better if they're decoupled and optional.

slide-31
SLIDE 31

Rarely will you build an application as part of a distributed system that does not also need local concurrency.

slide-32
SLIDE 32

Communication model

How do we unify communications in local concurrency and distributed systems across languages?

slide-33
SLIDE 33

Execution model

How do we get Erlang-style local concurrency without interfering with the language's idiomatic paradigm?

slide-34
SLIDE 34

ZeroMQ

Communication model

slide-35
SLIDE 35

Misconceptions

slide-36
SLIDE 36

Misconceptions

It’s just another MQ, right?

slide-37
SLIDE 37

Misconceptions

It’s just another MQ, right? Not really.

slide-38
SLIDE 38

Misconceptions

It’s just another MQ, right? Not really.

slide-39
SLIDE 39

Misconceptions

It’s just another MQ, right? Not really. Oh, it’s just sockets, right?

slide-40
SLIDE 40

Misconceptions

It’s just another MQ, right? Not really. Oh, it’s just sockets, right? Not really.

slide-41
SLIDE 41

Misconceptions

It’s just another MQ, right? Not really. Oh, it’s just sockets, right? Not really.

slide-42
SLIDE 42

Misconceptions

It’s just another MQ, right? Not really. Oh, it’s just sockets, right? Not really. Wait, isn’t messaging a solved problem?

slide-43
SLIDE 43

Misconceptions

It’s just another MQ, right? Not really. Oh, it’s just sockets, right? Not really. Wait, isn’t messaging a solved problem? *sigh* ... maybe.

slide-44
SLIDE 44

Regular Sockets

slide-45
SLIDE 45

Regular Sockets

Point to point

slide-46
SLIDE 46

Regular Sockets

Point to point Stream of bytes

slide-47
SLIDE 47

Regular Sockets

Point to point Stream of bytes Buffering

slide-48
SLIDE 48

Regular Sockets

Point to point Stream of bytes Buffering Standard API

slide-49
SLIDE 49

Regular Sockets

Point to point Stream of bytes Buffering Standard API TCP/IP or UDP, IPC

slide-50
SLIDE 50

Messaging

slide-51
SLIDE 51

Messaging

Messages are atomic

slide-52
SLIDE 52

Messaging

Messages are atomic

slide-53
SLIDE 53

Messaging

Messages are atomic

slide-54
SLIDE 54

Messaging

Messages are atomic

slide-55
SLIDE 55

Messaging

Messages are atomic Messages can be routed

slide-56
SLIDE 56

Messaging

Messages are atomic Messages can be routed

slide-57
SLIDE 57

Messaging

Messages are atomic Messages can be routed

slide-58
SLIDE 58

Messaging

Messages are atomic Messages can be routed Messages may sit around

slide-59
SLIDE 59

Messaging

Messages are atomic Messages can be routed Messages may sit around

slide-60
SLIDE 60

Messaging

Messages are atomic Messages can be routed Messages may sit around

slide-61
SLIDE 61

Messaging

Messages are atomic Messages can be routed Messages may sit around

slide-62
SLIDE 62

Messaging

Messages are atomic Messages can be routed Messages may sit around

slide-63
SLIDE 63

Messaging

Messages are atomic Messages can be routed Messages may sit around

slide-64
SLIDE 64

Messaging

Messages are atomic Messages can be routed Messages may sit around Messages are delivered

slide-65
SLIDE 65

Messaging

Messages are atomic Messages can be routed Messages may sit around Messages are delivered

slide-66
SLIDE 66

Rise of the Big MQ

slide-67
SLIDE 67

App App App App Reliable Message Broker

Persistent Queues

slide-68
SLIDE 68

App App App App

slide-69
SLIDE 69

AMQP

Producer Consumer MQ

slide-70
SLIDE 70

AMQP

Producer Consumer MQ Exchange Queue Binding X

slide-71
SLIDE 71

AMQP

Producer Consumer MQ Exchange Queue X

slide-72
SLIDE 72

AMQP Recipes

slide-73
SLIDE 73

AMQP Recipes

Work queues

Distributing tasks among workers

slide-74
SLIDE 74

AMQP Recipes

Work queues

Distributing tasks among workers

Publish/Subscribe

Sending to many consumers at once

X

slide-75
SLIDE 75

AMQP Recipes

Work queues

Distributing tasks among workers

Publish/Subscribe

Sending to many consumers at once

X

Routing

Receiving messages selectively

X foo bar baz

slide-76
SLIDE 76

AMQP Recipes

Work queues

Distributing tasks among workers

Publish/Subscribe

Sending to many consumers at once

X

RPC

Remote procedure call implementation

Routing

Receiving messages selectively

X foo bar baz

slide-77
SLIDE 77

Drawbacks of Big MQ

Lots of complexity Queues are heavyweight HA is a challenge Poor primitives

slide-78
SLIDE 78

Enter ZeroMQ

“Float like a butterfly, sting like a bee”

slide-79
SLIDE 79

Echo in Python

Server Client

import zmq context = zmq.Context() socket = context.socket(zmq.REP) socket.bind("tcp://127.0.0.1:5000") while True: msg = socket.recv() print "Received", msg socket.send(msg) 1 2 3 4 5 6 7 8 9 import zmq context = zmq.Context() socket = context.socket(zmq.REQ) socket.connect("tcp://127.0.0.1:5000") for i in range(10): msg = "msg %s" % i socket.send(msg) print "Sending", msg reply = socket.recv() 1 2 3 4 5 6 7 8 9 10

slide-80
SLIDE 80

Echo in Ruby

Server Client

require "zmq" context = ZMQ::Context.new(1) socket = context.socket(ZMQ::REP) socket.bind("tcp://127.0.0.1:5000") loop do msg = socket.recv puts "Received #{msg}" socket.send(msg) end 1 2 3 4 5 6 7 8 9 10 require "zmq" context = ZMQ::Context.new(1) socket = context.socket(ZMQ::REQ) socket.connect("tcp://127.0.0.1:5000") (0...10).each do |i| msg = "msg #{i}" socket.send(msg) puts "Sending #{msg}" reply = socket.recv end 1 2 3 4 5 6 7 8 9 10 11

slide-81
SLIDE 81

Echo in PHP

Server Client

<?php $context = new ZMQContext(); $socket = $context->getSocket(ZMQ::SOCKET_REP); $socket->bind("tcp://127.0.0.1:5000"); while (true) { $msg = $socket->recv(); echo "Received {$msg}"; $socket->send($msg); } ?> 1 2 3 4 5 6 7 8 9 10 11 <?php $context = new ZMQContext(); $socket = $context->getSocket(ZMQ::SOCKET_REQ); $socket->connect("tcp://127.0.0.1:5000"); foreach (range(0, 9) as $i) { $msg = "msg {$i}"; $socket->send($msg); echo "Sending {$msg}"; $reply = $socket->recv(); } ?> 1 2 3 4 5 6 7 8 9 10 11 12

slide-82
SLIDE 82

Bindings

ActionScript, Ada, Bash, Basic, C, Chicken Scheme, Common Lisp, C#, C++, D, Erlang, F#, Go, Guile, Haskell, Haxe, Java, JavaScript, Lua, Node.js, Objective-C, Objective Caml,

  • oc, Perl, PHP, Python, Racket, REBOL,

Red, Ruby, Smalltalk

slide-83
SLIDE 83

Plumbing

slide-84
SLIDE 84

Plumbing

slide-85
SLIDE 85

Plumbing

slide-86
SLIDE 86

Plumbing

slide-87
SLIDE 87

Plumbing

slide-88
SLIDE 88

Plumbing

inproc ipc tcp multicast

slide-89
SLIDE 89

Plumbing

inproc ipc tcp multicast

socket.bind("tcp://localhost:5560") socket.bind("ipc:///tmp/this-socket") socket.connect("tcp://10.0.0.100:9000") socket.connect("ipc:///tmp/another-socket") socket.connect("inproc://another-socket")

slide-90
SLIDE 90

Plumbing

inproc ipc tcp multicast

socket.bind("tcp://localhost:5560") socket.bind("ipc:///tmp/this-socket") socket.connect("tcp://10.0.0.100:9000") socket.connect("ipc:///tmp/another-socket") socket.connect("inproc://another-socket")

slide-91
SLIDE 91

Plumbing

inproc ipc tcp multicast

socket.bind("tcp://localhost:5560") socket.bind("ipc:///tmp/this-socket") socket.connect("tcp://10.0.0.100:9000") socket.connect("ipc:///tmp/another-socket") socket.connect("inproc://another-socket")

slide-92
SLIDE 92

Message Patterns

slide-93
SLIDE 93

Message Patterns

Request-Reply

REQ REP

slide-94
SLIDE 94

Message Patterns

Request-Reply

REQ REP REP REP

slide-95
SLIDE 95

Message Patterns

Request-Reply

REQ REP REP REP

slide-96
SLIDE 96

Message Patterns

Request-Reply

REQ REP REP REP

slide-97
SLIDE 97

Message Patterns

Request-Reply

REQ REP REP REP

slide-98
SLIDE 98

Message Patterns

Request-Reply Publish-Subscribe

REQ REP REP REP PUB SUB SUB SUB

slide-99
SLIDE 99

Message Patterns

Request-Reply Publish-Subscribe Push-Pull (Pipelining)

REQ REP REP REP PUB SUB SUB SUB PUSH PULL PULL PULL

slide-100
SLIDE 100

Message Patterns

Request-Reply Publish-Subscribe Push-Pull (Pipelining)

REQ REP REP REP PUB SUB SUB SUB PUSH PULL PULL PULL

slide-101
SLIDE 101

Message Patterns

Request-Reply Publish-Subscribe Push-Pull (Pipelining)

REQ REP REP REP PUB SUB SUB SUB PUSH PULL PULL PULL

slide-102
SLIDE 102

Message Patterns

Request-Reply Publish-Subscribe Push-Pull (Pipelining)

REQ REP REP REP PUB SUB SUB SUB PUSH PULL PULL PULL

slide-103
SLIDE 103

Message Patterns

Request-Reply Publish-Subscribe Push-Pull (Pipelining) Pair

REQ REP REP REP PUB SUB SUB SUB PUSH PULL PULL PULL PAIR PAIR

slide-104
SLIDE 104

Devices

Queue Forwarder Streamer Design architectures around devices.

slide-105
SLIDE 105

Devices

Queue Forwarder Streamer Design architectures around devices.

REQ REP

slide-106
SLIDE 106

Devices

Queue Forwarder Streamer Design architectures around devices.

PUB SUB

slide-107
SLIDE 107

Devices

Queue Forwarder Streamer Design architectures around devices.

PUSH PULL

slide-108
SLIDE 108

Performance

slide-109
SLIDE 109

Performance

Orders of magnitude faster than most MQs

slide-110
SLIDE 110

Performance

Orders of magnitude faster than most MQs Higher throughput than raw sockets

slide-111
SLIDE 111

Performance

Orders of magnitude faster than most MQs Higher throughput than raw sockets Intelligent message batching

slide-112
SLIDE 112

Performance

Orders of magnitude faster than most MQs Higher throughput than raw sockets Intelligent message batching Edge case optimizations

slide-113
SLIDE 113

Concurrency?

"Come for the messaging, stay for the easy concurrency"

slide-114
SLIDE 114

Hintjens’ Law of Concurrency

e = mc2

E is effort, the pain that it takes M is mass, the size of the code C is conflict, when C threads collide

slide-115
SLIDE 115

Hintjens’ Law of Concurrency

slide-116
SLIDE 116

Hintjens’ Law of Concurrency

slide-117
SLIDE 117

Hintjens’ Law of Concurrency

e=mc2, for c=1

ZeroMQ:

slide-118
SLIDE 118

ZeroMQ

Easy Cheap Fast Expressive

Messaging toolkit for concurrency and distributed systems.

... familiar socket API ... lightweight queues in a library ... higher throughput than raw TCP ... maps to your architecture

slide-119
SLIDE 119

gevent

Execution model

slide-120
SLIDE 120

Threading vs Evented

Evented seems to be preferred for scalable I/O applications

slide-121
SLIDE 121

Evented Stack

Non-blocking Code Flow Control I/O Abstraction Reactor Event Poller I/O Loop

slide-122
SLIDE 122

def lookup(country, search_term): main_d = defer.Deferred() def first_step(): query = "http://www.google.%s/search?q=%s" % (country,search_term) d = getPage(query) d.addCallback(second_step, country) d.addErrback(failure, country) def second_step(content, country): m = re.search('<div id="?res.*?href="(?P<url>http://[^"]+)"', content, re.DOTALL) if not m: main_d.callback(None) return url = m.group('url') d = getPage(url) d.addCallback(third_step, country, url) d.addErrback(failure, country) def third_step(content, country, url): m = re.search("<title>(.*?)</title>", content) if m: title = m.group(1) main_d.callback(dict(url = url, title = title)) else: main_d.callback(dict(url=url, title="{not-specified}")) def failure(e, country): print ".%s FAILED: %s" % (country, str(e)) main_d.callback(None) first_step() return main_d 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34

slide-123
SLIDE 123

gevent

Reactor / Event Poller Greenlets Monkey patching “Regular” Python

slide-124
SLIDE 124

Green threads

“Threads” implemented in user space (VM, library)

slide-125
SLIDE 125

Monkey patching

socket, ssl, threading, time

slide-126
SLIDE 126

Twisted

slide-127
SLIDE 127

Twisted

~400 modules

slide-128
SLIDE 128

gevent

25 modules

slide-129
SLIDE 129

Performance

http://nichol.as

slide-130
SLIDE 130

Performance

http://nichol.as

slide-131
SLIDE 131

Performance

http://nichol.as

slide-132
SLIDE 132

Building a Networking App

#=== # 1. Basic gevent TCP server from gevent.server import StreamServer def handle_tcp(socket, address): print 'new tcp connection!' while True: socket.send('hello\n') gevent.sleep(1) tcp_server = StreamServer(('127.0.0.1', 1234), handle_tcp) tcp_server.serve_forever() 1 2 3 4 5 6 7 8 9 10 11 12 13

slide-133
SLIDE 133

#=== # 2. Basic gevent TCP server and WSGI server from gevent.pywsgi import WSGIServer from gevent.server import StreamServer def handle_http(env, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) print 'new http request!' return ["hello world"] def handle_tcp(socket, address): print 'new tcp connection!' while True: socket.send('hello\n') gevent.sleep(1) tcp_server = StreamServer(('127.0.0.1', 1234), handle_tcp) tcp_server.start() http_server = WSGIServer(('127.0.0.1', 8080), handle_http) http_server.serve_forever() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

slide-134
SLIDE 134

from gevent.pywsgi import WSGIServer from gevent.server import StreamServer from gevent.socket import create_connection def handle_http(env, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) print 'new http request!' return ["hello world"] def handle_tcp(socket, address): print 'new tcp connection!' while True: socket.send('hello\n') gevent.sleep(1) def client_connect(address): sockfile = create_connection(address).makefile() while True: line = sockfile.readline() # returns None on EOF if line is not None: print "<<<", line, else: break tcp_server = StreamServer(('127.0.0.1', 1234), handle_tcp) tcp_server.start() gevent.spawn(client_connect, ('127.0.0.1', 1234)) http_server = WSGIServer(('127.0.0.1', 8080), handle_http) http_server.serve_forever() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

slide-135
SLIDE 135

from gevent.pywsgi import WSGIServer from gevent.server import StreamServer from gevent.socket import create_connection def handle_http(env, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) print 'new http request!' return ["hello world"] def handle_tcp(socket, address): print 'new tcp connection!' while True: socket.send('hello\n') gevent.sleep(1) def client_connect(address): sockfile = create_connection(address).makefile() while True: line = sockfile.readline() # returns None on EOF if line is not None: print "<<<", line, else: break tcp_server = StreamServer(('127.0.0.1', 1234), handle_tcp) http_server = WSGIServer(('127.0.0.1', 8080), handle_http) greenlets = [ gevent.spawn(tcp_server.serve_forever), gevent.spawn(http_server.serve_forever), gevent.spawn(client_connect, ('127.0.0.1', 1234)), ] gevent.joinall(greenlets) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

slide-136
SLIDE 136

ZeroMQ in gevent?

slide-137
SLIDE 137
slide-138
SLIDE 138

from gevent import spawn from gevent_zeromq import zmq context = zmq.Context() def serve(): socket = context.socket(zmq.REP) socket.bind("tcp://localhost:5559") while True: message = socket.recv() print "Received request: ", message socket.send("World") server = spawn(serve) def client(): socket = context.socket(zmq.REQ) socket.connect("tcp://localhost:5559") for request in range(10): socket.send("Hello") message = socket.recv() print "Received reply ", request, "[", message, "]" spawn(client).join() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

slide-139
SLIDE 139

Actor model?

Easy to implement, in whole or in part,

  • ptionally with ZeroMQ
slide-140
SLIDE 140
slide-141
SLIDE 141

What is gevent missing?

slide-142
SLIDE 142

What is gevent missing?

Documentation

slide-143
SLIDE 143

What is gevent missing?

Documentation Application framework

slide-144
SLIDE 144

gservice

Application framework for gevent

slide-145
SLIDE 145

from gevent.pywsgi import WSGIServer from gevent.server import StreamServer from gevent.socket import create_connection def handle_http(env, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) print 'new http request!' return ["hello world"] def handle_tcp(socket, address): print 'new tcp connection!' while True: socket.send('hello\n') gevent.sleep(1) def client_connect(address): sockfile = create_connection(address).makefile() while True: line = sockfile.readline() # returns None on EOF if line is not None: print "<<<", line, else: break tcp_server = StreamServer(('127.0.0.1', 1234), handle_tcp) http_server = WSGIServer(('127.0.0.1', 8080), handle_http) greenlets = [ gevent.spawn(tcp_server.serve_forever), gevent.spawn(http_server.serve_forever), gevent.spawn(client_connect, ('127.0.0.1', 1234)), ] gevent.joinall(greenlets) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

slide-146
SLIDE 146

from gevent.pywsgi import WSGIServer from gevent.server import StreamServer from gevent.socket import create_connection from gservice.core import Service def handle_http(env, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) print 'new http request!' return ["hello world"] def handle_tcp(socket, address): print 'new tcp connection!' while True: socket.send('hello\n') gevent.sleep(1) def client_connect(address): sockfile = create_connection(address).makefile() while True: line = sockfile.readline() # returns None on EOF if line is not None: print "<<<", line, else: break app = Service() app.add_service(StreamServer(('127.0.0.1', 1234), handle_tcp)) app.add_service(WSGIServer(('127.0.0.1', 8080), handle_http)) app.add_service(TcpClient(('127.0.0.1', 1234), client_connect)) app.serve_forever() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

slide-147
SLIDE 147

from gservice.core import Service from gservice.config import Setting class MyApplication(Service): http_port = Setting('http_port') tcp_port = Setting('tcp_port') connect_address = Setting('connect_address') def __init__(self): self.add_service(WSGIServer(('127.0.0.1', self.http_port), self.handle_http)) self.add_service(StreamServer(('127.0.0.1', self.tcp_port), self.handle_tcp)) self.add_service(TcpClient(self.connect_address, self.client_connect)) def client_connect(self, address): sockfile = create_connection(address).makefile() while True: line = sockfile.readline() # returns None on EOF if line is not None: print "<<<", line, else: break def handle_tcp(self, socket, address): print 'new tcp connection!' while True: socket.send('hello\n') gevent.sleep(1) def handle_http(self, env, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) print 'new http request!' return ["hello world"] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

slide-148
SLIDE 148

# example.conf.py pidfile = 'example.pid' logfile = 'example.log' http_port = 8080 tcp_port = 1234 connect_address = ('127.0.0.1', 1234) def service(): from example import MyApplication return MyApplication() 1 2 3 4 5 6 7 8 9 10 11 # Run in the foreground gservice -C example.conf.py # Start service as daemon gservice -C example.conf.py start # Control service gservice -C example.conf.py restart gservice -C example.conf.py reload gservice -C example.conf.py stop # Run with overriding configuration gservice -C example.conf.py -X 'http_port = 7070'

slide-149
SLIDE 149

Generalizing

gevent proves a model that can be implemented in almost any language that can implement an evented stack

slide-150
SLIDE 150

gevent

Easy Small Fast Compatible

Futuristic evented platform for network applications.

... just normal Python ... only 25 modules ... top performing server ... works with most libraries

slide-151
SLIDE 151

Raiden

Lightning fast, scalable messaging https://github.com/progrium/raiden

slide-152
SLIDE 152

Concurrency models

Traditional multithreading Async or Evented I/O Actor model

slide-153
SLIDE 153

Conclusion

Two very simple, but very powerful tools for distributed / concurrent systems

slide-154
SLIDE 154

Thanks

@progrium