Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SlideShare a Scribd company logo
Evented programming in node.js
and ruby
Overview
• Evented Programming
• Evented Web Backends
• Evented Ruby vs Evented Javascript
• Improving Rails Concurrency
Evented Programming
$(‘body’).click(function(){
$(this).css(‘color’, ‘red’);
});
Event Callback
Reactor Pattern
Reactor Pattern
• Events: keyboard, mouse, touch
• Reusable reactors: browser
Node.js
• Node.js is an event driven, non-blocking I/O
model that makes it lightweight efficient,
perfect for data intensive real time that run
across distributed devices.
Blocking I/O
If RAM was an F-18 Hornet with a max speed of
1,190 mph, disk access is a banana slug with a
top speed of 0.007 mph
Blocking I/O
F = Fast F18 Hornet
S = Slow Banana Slug
data = File.read(‘file.txt’)
FSSSSSSSSSSSSSSSSSF
CPU is idle
Blocking I/O
• Switches b/w busy processes
• OS and h/w caches hides complexity
Blocking I/O
Node.js switches b/w I/O within the same
process
Web Apps
• Blocking I/O decreases concurrency
• Database, file system – disk
• S3, external APIs – network
• ImageMagick – shelling out
Rails Concurrency
tweet = Tweet.new(params[‘tweet’]) # 1.
tweet.shorten_links! # 2. network
tweet.save # 3. disk
Rails Concurrency
Rails Concurrency
• Process Concurrency
• Lots of memory
Node Concurrency
tweet = new Tweet(); // 1.
tweet.shorten_links(function(tweet) { // 2. callback
tweet.save(function(){ // 3. callback
})
})
Node Concurrency
Node Concurrency
• Reactor switches b/w requests
• Fewer processes needed => Less memory
Latency
• Blocking I/O does not speed up
• Optimize response latency first
Code Smell
tweet = new Tweet(); // 1.
tweet.shorten_links(function(tweet) { // 2. callback
tweet.save(function(){ // 3. callback
})
})
• App code aware of blocking I/O
• Ugly syntax, nested contexts
Node use cases
• Chat Server
• Fast File Upload Client
• API’s
• Proxy server(In SOA)
• Data Streaming
• Any Real Time Data Apps
Who are using node
How event driven programming can be
done in ruby
Think ruby way
• Instead of waiting for something to happen
before executing code,
• Put that code in proc,
• Invoke the proc when something happens
Writing asyc code
• Synchronous ruby code uses return values
– ret = operation()
– do_something_with(ret)
• Evented async code uses blocks instead
– operation{ |ret| do_something_with(ret) }
• Different from how you usually use ruby
blocks. The is stored and invoked later(it’s
asynchronous)
Evented Ruby
• Ruby is capable of evented programming
• Multi-paradigm: procedural, evented, parallel
• Mix and match paradigms
Ruby Reactors
• Reactor is just a gem
• Eventmachine, cool.io, others
Basic concepts
• Threads
• Fibers
Threads
• Shared state and memory space
• Light weight
• Preemptive scheduling
Downsides
• Race conditions
• Deadlocks
• Hard to debug
• GIL
Fibers
• Cooperative scheduling
• Relatively lightweight
• Maintains state
Upsides
• No races
• No need of locks
• Parallelism
• Explicit yielding and resuming
Add Events
http = EM::HttpRequest.new(‘http://vinsol-meetup.com/’).get
http.callback {
# request finished
}
OK, so how do I use EM?
• gem install ‘eventmachine’
• require ‘eventmachine’
Deferring work
• The reactor itself is single threaded and the
EM methods which work with the reactor are
not thread-safe.
• This has two outcomes.
– code that takes a long time to run and moved to a
bg thread(db queries, http requests etc.)
– Once moved to bg thread, we have ability to tell
reactor to do work for us
• This is where EM#defer comes into play.
EM#defer(op, cb)
• We can schedule the execution of a block to
one of the threads in EventMachines thread
pool.
• EM#thread_pool_size = 20(default)
• EM#defer takes a second parameter, the
callback. This callback will be executed on the
main reactor thread and will be provided with
the return value of our deferred operation.
Code Smell
http = EM::HttpRequest.new(‘http://vinsol-com.com/’).get
http.callback {
# request finished
}
• App code aware of blocking I/O
• Code doesn’t look like ruby
Procedural Interface,
Evented Execution
Faraday.default_adapter = :em_synchrony
response = Faraday.get ‘http://vinsol-taf.com/’
• Hides system event callbacks in libraries
• Keeps app code clean
Procedural Interface,
Evented Execution
Procedural Interface,
Evented Execution
Code Smell?
One Requests per Fiber
• Wrap each req in its own fiber
• Web reqs are independent of each other
• Switch between requests instead of processes
Rack::FiberPool
Recap
• App server is reactor aware
• One fiber per request
• App code is unchanged
Mixing Paradigms
• Libraries may block the reactor
But that’s ok…
Starting Points
• Data stores
• http
• Kernel.system calls
Data Stores
• Redis
• Mysql
• Postgresql
• mongo
HTTP
• Faraday: use an event aware http adapter
System Calls
• EM.popen – non-blocking version
• EM.defer – run blocking call outside of reactor
thread
Final Result
Why Ruby
• Reuse existing code
• Performance won’t be worse
• Keep procedural syntax
• Multi-paradigm
Why Node
• Single paradigm consistency
• Community
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
Thanks!

More Related Content

Evented Ruby VS Node.js