Slide 1

Slide 1 text

Evented Ruby vs Node.js Monday, October 8, 12

Slide 2

Slide 2 text

Hi, I’m Jerry http://github.com/jch @whatcodecraves Monday, October 8, 12

Slide 3

Slide 3 text

Performance Goals ✓ Low hanging fruit ✓ Micro-optimizations (don’t do ‘em) ✓ Sustainable changes ✓ Minimal Monday, October 8, 12

Slide 4

Slide 4 text

Evented... ✓ ... programming ✓ ... server side web ✓ ... Ruby vs Javascript ✓ ... app concurrency Monday, October 8, 12

Slide 5

Slide 5 text

Evented Programming $("body").click(function(e) { $(this).css('color', 'red'); }); Event Callback Event Monday, October 8, 12

Slide 6

Slide 6 text

Reactor Pattern Reactor callbacks callbacks Click Drag Monday, October 8, 12

Slide 7

Slide 7 text

Reactor Pattern ✓ UI events: keyboard, mouse, touch ✓ Reusable reactors: browser, game loop ✓ Other events: network up, disk Monday, October 8, 12

Slide 8

Slide 8 text

Node.js Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices. Monday, October 8, 12

Slide 9

Slide 9 text

Blocking I/O If RAM was an F-18 Hornet with a max speed of 1,190 mph, disk access speed is a banana slug with a top speed of 0.007 mph Monday, October 8, 12

Slide 10

Slide 10 text

Blocking I/O data = File.read(‘file.txt’) F = Fast F18 Hornet S = Slow Banana Slug FSSSSSSSSSSSSSSSF CPU is idle Monday, October 8, 12

Slide 11

Slide 11 text

Blocking I/O ✓ Switch between busy processes ✓ OS and hardware caches hides complexity OS Rails Browser iTunes Monday, October 8, 12

Slide 12

Slide 12 text

Blocking I/O OS Node Browser iTunes I/O Node.js switches between I/O within the same process Monday, October 8, 12

Slide 13

Slide 13 text

Web Apps ✓ blocking I/O decreases concurrency ✓ database, filesystem - disk ✓ S3, external APIs - network ✓ ImageMagick - shelling out Monday, October 8, 12

Slide 14

Slide 14 text

Rails Concurrency tweet = Tweet.new(params["tweet"]) # 1. tweet.shorten_links! # 2. network tweet.save # 3. disk Monday, October 8, 12

Slide 15

Slide 15 text

Rails Concurrency Request Request Request Request Green is executing thread Red is waiting on I/O finished request start 2nd request Monday, October 8, 12

Slide 16

Slide 16 text

Rails Concurrency Web Server Rails Rails Rails ✓ Process concurrency ✓ Lots of memory Monday, October 8, 12

Slide 17

Slide 17 text

Node Concurrency tweet = new Tweet(); // 1. tweet.shortenLinks(function(tweet) { // 2. callback tweet.save(function(tweet) { // 3. callback } }) Monday, October 8, 12

Slide 18

Slide 18 text

Node Concurrency Reactor Request Request Reactor Request Request Green is executing thread Red is waiting on I/O Monday, October 8, 12

Slide 19

Slide 19 text

Node Concurrency Reactor Request Request Reactor Request Request Green is executing thread Red is waiting on I/O Start 1st request Monday, October 8, 12

Slide 20

Slide 20 text

Node Concurrency Reactor Request Request Reactor Request Request Green is executing thread Red is waiting on I/O Monday, October 8, 12

Slide 21

Slide 21 text

Node Concurrency Reactor Request Request Reactor Request Request Green is executing thread Red is waiting on I/O Start 2nd request Monday, October 8, 12

Slide 22

Slide 22 text

Node Concurrency Reactor Request Request Reactor Request Request Green is executing thread Red is waiting on I/O Monday, October 8, 12

Slide 23

Slide 23 text

Node Concurrency Reactor Request Request Reactor Request Request Green is executing thread Red is waiting on I/O IO finishes for first request Monday, October 8, 12

Slide 24

Slide 24 text

Node Concurrency Reactor Request Request Reactor Request Request Green is executing thread Red is waiting on I/O Monday, October 8, 12

Slide 25

Slide 25 text

Node Concurrency Reactor Request Request Reactor Request Request Green is executing thread Red is waiting on I/O IO finishes for last request Monday, October 8, 12

Slide 26

Slide 26 text

Node Concurrency Reactor Request Request Reactor Request Request Green is executing thread Red is waiting on I/O Monday, October 8, 12

Slide 27

Slide 27 text

Node Concurrency ✓ One reactor process switches between requests ✓ Fewer processes => Less memory Web Server Node Node Monday, October 8, 12

Slide 28

Slide 28 text

Latency SSSFSSSSSSSSSFSSSS SSSFSSSSSSSSSFSSSS SSSFSSSSSSSSSFSSSS SSSFSSSSSSSSSFSSSS SSSFSSSSSSSSSFSSSS JS Ruby Single request takes the same time ✓ Blocking I/O is not sped up ✓ Optimize response latency first Monday, October 8, 12

Slide 29

Slide 29 text

Code Smell ✓ App code aware of blocking I/O ✓ Ugly syntax, nested contexts tweet = new Tweet(); // 1. tweet.shortenLinks(function(tweet) { // 2. callback tweet.save(function(tweet) { // 3. callback } }) Monday, October 8, 12

Slide 30

Slide 30 text

Evented Ruby ✓ ruby is capable of evented programming ✓ multi-paradigm: procedural, evented, parallel ✓ mix and match paradigms Monday, October 8, 12

Slide 31

Slide 31 text

Ruby Reactors ✓ reactor is just a gem ✓ eventmachine, cool.io, ... # Starting an EventMachine reactor EM.run { # reactor aware code here... } Monday, October 8, 12

Slide 32

Slide 32 text

Add a Reactor Process Concurrency Application Code Reactor Thin, Rainbows!, Passenger (w/ patch) Monday, October 8, 12

Slide 33

Slide 33 text

Add Events http = EM::HttpRequest.new('https://github.com/').get http.callback { # request finished } Monday, October 8, 12

Slide 34

Slide 34 text

Code Smell http = EM::HttpRequest.new('https://github.com/').get http.callback { # request finished } ✓ app code aware of blocking I/O ✓ code doesn’t look like ruby Monday, October 8, 12

Slide 35

Slide 35 text

Procedural Interface, Evented Execution response = Faraday.get 'https://github.com/' Monday, October 8, 12

Slide 36

Slide 36 text

Procedural Interface, Evented Execution response = Faraday.get 'https://github.com/' Faraday.default_adapter = :em_synchrony Monday, October 8, 12

Slide 37

Slide 37 text

Procedural Interface, Evented Execution response = Faraday.get 'https://github.com/' ✓ hides system event callbacks in libraries ✓ keeps app code clean Faraday.default_adapter = :em_synchrony Monday, October 8, 12

Slide 38

Slide 38 text

Procedural Interface, Evented Execution Fibers are primitives for implementing light weight cooperative concurrency in Ruby. Basically they are a means of creating code blocks that can be paused and resumed, much like threads. The main difference is that they are never preempted and that the scheduling must be done by the programmer and not the VM. Monday, October 8, 12

Slide 39

Slide 39 text

Procedural Interface, Evented Execution Reactor Request Fiber1 Fiber2 Monday, October 8, 12

Slide 40

Slide 40 text

Procedural Interface, Evented Execution Reactor Request Fiber1 Fiber2 Start request Monday, October 8, 12

Slide 41

Slide 41 text

Procedural Interface, Evented Execution Reactor Request Fiber1 Fiber2 when blocked on I/O, pause Fiber2, resume Fiber1 Start request Monday, October 8, 12

Slide 42

Slide 42 text

Procedural Interface, Evented Execution Reactor Request Fiber1 Fiber2 when blocked on I/O, pause Fiber2, resume Fiber1 Start request Resume Fiber in I/O callback Monday, October 8, 12

Slide 43

Slide 43 text

Code Smell? ...The main difference is that they are never preempted and that the scheduling must be done by the programmer and not the VM. Monday, October 8, 12

Slide 44

Slide 44 text

Just add Fibers ✓ wrap each request in it’s own fiber ✓ web requests are independent from one another ✓ switch between requests instead of processes Monday, October 8, 12

Slide 45

Slide 45 text

Rack::FiberPool # Rails config.middleware.prepend Rack::FiberPool # Generic rack apps: sinatra, grape, etc use Rack::FiberPool Monday, October 8, 12

Slide 46

Slide 46 text

Recap ✓ App server is reactor-aware ✓ One fiber per request ✓ App code is unchanged Monday, October 8, 12

Slide 47

Slide 47 text

Mixing Paradigms ✓ libraries may block reactor Request Request Request Request Reactor Monday, October 8, 12

Slide 48

Slide 48 text

Mixing Paradigms ✓ libraries may block reactor Request Request Request Request Reactor 1st request Monday, October 8, 12

Slide 49

Slide 49 text

Mixing Paradigms ✓ libraries may block reactor Request Request Request Request Reactor Monday, October 8, 12

Slide 50

Slide 50 text

Mixing Paradigms ✓ libraries may block reactor Request Request Request Request Reactor Blocking library, doesn’t yield to reactor Monday, October 8, 12

Slide 51

Slide 51 text

Mixing Paradigms ✓ libraries may block reactor Request Request Request Request Reactor Monday, October 8, 12

Slide 52

Slide 52 text

Mixing Paradigms ✓ libraries may block reactor Request Request Request Request Reactor 2nd request, reactor blocked, can’t start Monday, October 8, 12

Slide 53

Slide 53 text

Mixing Paradigms ✓ libraries may block reactor Request Request Request Request Reactor Monday, October 8, 12

Slide 54

Slide 54 text

Mixing Paradigms ✓ libraries may block reactor Request Request Request Request Reactor Reactor starts 2nd request Monday, October 8, 12

Slide 55

Slide 55 text

But that’s ok... Web Server Rails Rails Rails Can’t do worse than one request per process Monday, October 8, 12

Slide 56

Slide 56 text

Starting Points ✓ data stores ✓ http ✓ Kernel.system calls Monday, October 8, 12

Slide 57

Slide 57 text

Data Stores ✓ redis ✓ mysql ✓ postgresql ✓ mongo Monday, October 8, 12

Slide 58

Slide 58 text

HTTP ✓ Faraday: use an EM-aware http adapter Monday, October 8, 12

Slide 59

Slide 59 text

System Calls ✓ EM.popen - non-blocking version ✓ EM.defer - run blocking call outside of reactor thread Monday, October 8, 12

Slide 60

Slide 60 text

Final Result Reactor Request Request Fiber1 Fiber2 Fiber3 Green is executing thread Red is waiting on I/O Monday, October 8, 12

Slide 61

Slide 61 text

Why Ruby ✓ Reuse existing code ✓ Performance won’t be worse ✓ Keep procedural syntax ✓ Multi-paradigm Monday, October 8, 12

Slide 62

Slide 62 text

Why Node ✓ Single paradigm consistency ✓ Community Monday, October 8, 12

Slide 63

Slide 63 text

Have cake and eat it too ✓ Don’t go and rewrite your Rails app ✓ Write specific features as an evented subsystem Monday, October 8, 12

Slide 64

Slide 64 text

Example https://github.com/blog/678-meet-nodeload-the-new-download-server Monday, October 8, 12

Slide 65

Slide 65 text

Wrapping Up Monday, October 8, 12

Slide 66

Slide 66 text

Wrapping Up ✓ Evented programming is hard in any language Monday, October 8, 12

Slide 67

Slide 67 text

Wrapping Up ✓ Evented programming is hard in any language ✓ Evented programming for evented problems Monday, October 8, 12

Slide 68

Slide 68 text

Wrapping Up ✓ Evented programming is hard in any language ✓ Evented programming for evented problems ✓ Evented programming doesn’t fix latency Monday, October 8, 12

Slide 69

Slide 69 text

Wrapping Up ✓ Evented programming is hard in any language ✓ Evented programming for evented problems ✓ Evented programming doesn’t fix latency ✓ Avoid evented I/O interface in app code Monday, October 8, 12

Slide 70

Slide 70 text

Thanks! http://github.com/jch @whatcodecraves Monday, October 8, 12