SlideShare ist ein Scribd-Unternehmen logo
1 von 51
Downloaden Sie, um offline zu lesen
Scaling :ruby 
with Evented I/O 
Omer Gazit 
[github.com/omerisimo]
Scaling Strategies[] 
<< "Machines" 
<< "Processes" 
<< "Threads" 
<< "Reactor pattern"
Blocking I/O 
start 
wait for I/O [e.g. file,network] 
complete
Non-Blocking I/O 
start 
call I/O operation 
Do something else 
complete 
Kernel 
I/O 
callback()
:sync 
def sync_io(file_name) 
file = File.open(file_name) 
puts "File #{file_name} opened" 
end
:async 
def async_io(file_name) 
file = File.async_open(file_name) 
file.callback do |result| 
puts "File #{file_name} opened" 
end 
end
Reactor pattern 
“The reactor design pattern is an event 
handling pattern for handling service 
requests delivered concurrently… 
The service handler then demultiplexes the 
incoming requests and dispatches them 
synchronously to the associated request 
handlers.” 
-wikipedia
Reactor pattern 
“The reactor design pattern is an event 
handling pattern for handling service 
requests delivered concurrently… 
The service handler then demultiplexes the 
incoming requests and dispatches them 
synchronously to the associated request 
handlers.” 
-wikipedia
Reactor pattern 
IO Stream 
Demultiplexer 
Event Handler A 
Event Handler B 
Event Handler C 
Event 
Dispatcher
Reactor pattern 
A reactor is a single thread 
running an endless loop that 
reacts to incoming events
Reactor pattern 
A reactor is a single thread 
running an endless loop that 
reacts to incoming events
event_loop do 
while reactor_running? 
expired_timers.each { |timer| timer.process } 
new_network_io.each { |io| io.process } 
end
Reactor.when? 
● Proxies 
● Real time data delivery 
(Websockets) 
● Streaming 
● Background processing (MQ listener) 
● High throughput and mostly I/O 
bound
{ 
javascript: "Node.js", 
ruby: "EventMachine", 
perl: "AnyEvent", 
python: "Twisted", 
c: ["libev", "libevent"] 
} 
implementations=
EventMachine 
A toolkit for writing evented applications 
in Ruby
But node.js is so 
much faster... 
Is it really faster?
Simple HTTP Server 
Node.js 
var http = require('http'); 
http.createServer(function (request, response) { 
response.writeHead(200, 
{'Content-Type': 'text/plain'} 
); 
response.send('Hello Worldn'); 
}).listen(8080, '0.0.0.0'); 
console.log('Server running on port 8080');
Simple HTTP Server 
EventMachine 
EM.run do 
EM.start_server "0.0.0.0", 8080 do |server| 
def server.receive_data(data) 
response = EM::DelegatedHttpResponse .new(self) 
response.status = 200; 
response.content_type 'text/plain' 
response.content = "Hello World n" 
response.send_response 
end 
end 
end
Showdown 
results = { 
node: { req_per_sec: 2898, 
req_time_ms: 35 }, 
em: { req_per_sec: 6751, 
req_time_ms: 15 } 
} 
ab -n 1000 -c 100 "http://localhost:8080/" 
* executed on my MacBook Air
RabbitMQ Processor 
Node.js 
var amqp = require('amqp'); 
var connection = amqp.createConnection(); 
connection.on( 'ready', function() { 
connection.queue( 'my_queue' , function(queue) { 
queue.subscribe( function(payload) { 
console.log("Received message: " + payload.body); 
} 
}); 
var exchange = connection.exchange(); 
exchange.publish( 'my_queue' , { body: 'Hello World!' }); 
});
RabbitMQ Processor 
EventMachine 
require 'amqp' 
EM.run do 
connection = AMQP.connect(host: '0.0.0.0') 
channel = AMQP::Channel .new(connection) 
queue = channel.queue( "my_queue" ) 
queue.subscribe do |metadata, payload| 
puts "Received message: #{payload}." 
end 
exchange = channel.default_exchange 
exchange.publish "Hello world!" ,routing_key : "my_queue" 
end
Showdown 
average_time_ms = { 
node: 4285, 
em: 3488 
} 
send and receive 10k messages 
* executed on my MacBook Air
EM can be really fast 
If used correctly!
Never Block the 
Event Loop
Never Block 
Blocking Non-Blocking 
EM.run do 
puts "Started EM" 
sleep 2.0 
puts "Shutting down EM" 
EM.stop 
end 
EM.run do 
puts "Started EM" 
EM.add_periodic_timer( 1.0) do 
puts "Tick" 
end 
EM.add_timer( 2.0) do 
puts "Shutting down EM" 
EM.stop 
end 
end
Never Block 
Blocking Non-Blocking 
require 'net/http' 
EM.run do 
response = Net::HTTP.get(URL) 
puts "Completed HTTP request" 
EM.stop 
end 
require 'em-http' 
EM.run do 
http = EM::HttpRequest .new(URL).get 
http.callback do |response| 
puts "Completed HTTP request" 
EM.stop 
end 
end
module NonBlock 
<< "igrigorik/em-http-request" # Asynchronous HTTP Client 
<< "eventmachine/evma_httpserver" # HTTP Server 
<< "igrigorik/em-websocket" # WebSockets server 
<< "igrigorik/em-proxy" # High-performance transparent proxies 
<< "brianmario/mysql2" # Make sure to use with :async => true 
<< "royaltm/ruby-em-pg-client" # PostgreSQL EM client 
<< "bcg/em-mongo" # EM MongoDB driver (based off of RMongo) 
<< "simulacre/em-ssh" # EM compatible Net::SSH 
<< "pressly/uber-s3" # S3 client with asynchronous I/O adapters 
<< "tmm1/amqp" # AMQP client for EM 
* See full list of protocols at: github.com/eventmachine/eventmachine/wiki/Protocol-Implementations
module NonBlock 
<< "igrigorik/em-http-request" 
<< "eventmachine/evma_httpserver" 
<< "igrigorik/em-websocket" 
<< "igrigorik/em-proxy" 
<< "brianmario/mysql2" 
<< "royaltm/ruby-em-pg-client" 
<< "bcg/em-mongo" 
<< "simulacre/em-ssh" 
<< "pressly/uber-s3" 
<< "tmm1/amqp" 
* See full list of protocols at: github.com/eventmachine/eventmachine/wiki/Protocol-Implementations
Never Block the 
Event Loop
EM.defer 
Defer blocking code to a thread 
EM.run do 
long_operation = proc { 
sleep(1.0) 
"result" 
} 
callback = proc {|result| 
puts "Received #{result}" 
EM.stop 
} 
EM.defer(long_operation, callback) 
end
EM.next_tick 
Postpone execution to the next iteration 
Blocking Non-Blocking 
EM.run do 
(1..10000).each do |index| 
puts "Processing #{index}" 
end 
EM.stop 
end 
EM.run do 
index = 0 
process_index = proc { 
if index < 10000 
puts "Processing #{index}" 
index += 1 
EM.next_tick &process_index 
else 
EM.stop 
end 
} 
EM.next_tick &process_index 
end
EM::Primitives
EM::Deferrable 
EM::Deferrable != EM.defer 
class DeferrableTimer 
include EM::Deferrable 
def wait 
EM.add_timer( 1.0) do 
succeed "result" 
end 
self 
end 
end 
EM.run do 
timer = DeferrableTimer .new.wait 
timer.callback do |result| 
puts "1 second has passed!" 
EM.stop 
end 
end
EM::Connection 
class EchoServer < EM::Connection 
def post_init 
puts "Client connecting" 
end 
def receive_data (data) 
puts "Client sending data #{data}" 
send_data ">> #{data}" 
end 
def unbind 
puts "Client disconnecting" 
end 
end 
EM.run do 
EM.start_server( "0.0.0.0", 9000, EchoServer ) # Listen on TCP socket 
end
EM::Queue 
A cross thread, reactor scheduled, linear queue 
EM.run do 
queue = EM::Queue.new 
queue_handler = proc { |message| 
puts "Handling message #{message}" 
EM.next_tick{ queue.pop( &queue_handler) } 
} 
EM.next_tick{ queue.pop( &queue_handler) } 
EM.add_periodic_timer( 1.0) do 
message = Time.now.to_s 
puts "Pushing message ' #{message}' to queue" 
queue.push(message) 
end 
end
EM::Channel 
Provides a simple thread-safe way to transfer data 
between (typically)long running tasks 
EM.run do 
channel = EM::Channel.new 
handler_1 = proc { | message| puts "Handler 1 message #{message}" } 
handler_2 = proc { | message| puts "Handler 2 message #{message}" } 
channel.subscribe &handler_1 
channel.subscribe &handler_2 
EM.add_periodic_timer( 1.0) do 
message = Time.now.to_s 
puts "Sending message ' #{message}' to channel" 
channel << message 
end 
end
EM::Primitives 
<< EM::Queue # A cross thread, reactor scheduled, 
linear queue 
<< EM::Channel # Simple thread-safe way to transfer 
data between (typically)long running tasks 
<< EM::Iterator # A simple iterator for concurrent 
asynchronous work 
<< EM.System() # Run external commands without 
blocking
EM.run do 
EM.add_timer( 1) do 
json = nil 
begin 
data = JSON.parse(json) 
puts "Parsed Json data: #{data}" 
rescue StandardException => e 
puts "Error: #{e.message}" 
end 
EM.stop 
end 
end 
Error Handling
Error Handling 
EM.run do 
EM.add_timer( 1) do 
http = EM::HttpRequest .new(BAD_URI).get 
http.callback do 
puts "Completed HTTP request" 
EM.stop 
end 
http.errback do |error| 
puts "Error: #{error.error }" 
EM.stop 
end 
end 
end
EM::Synchrony 
Fiber aware EventMachine clients and 
convenience classes 
github.com/igrigorik/em-synchrony
EM::Synchrony 
em-synchrony/em-http 
require 'em-synchrony' 
require 'em-synchrony/em-http' 
EM.synchrony do 
res = EM::HttpRequest .new(URL).get 
puts "Response: #{res.response }" 
EM.stop 
end 
em-http-request 
require 'eventmachine' 
require 'em-http' 
EM.run do 
http = EM::HttpRequest .new(URL).get 
http.callback do 
puts "Completed HTTP request" 
EM.stop 
end 
end
Testing
EM::Spec 
require 'em-spec/rspec' 
describe LazyCalculator do 
include EM::SpecHelper 
default_timeout( 2.0) 
it "divides x by y" do 
em do 
calc = LazyCalculator .new.divide(6,3) 
calc.callback do |result| 
expect(result).to eq 2 
done 
end 
end 
end 
end 
class LazyCalculator 
include EM::Deferrable 
def divide(x, y) 
EM.add_timer( 1.0) do 
if(y == 0) 
fail ZeroDivisionError .new 
else 
result = x/y 
succeed result 
end 
end 
self 
end 
end
EM::Spec 
require 'em-spec/rspec' 
describe LazyCalculator do 
include EM::SpecHelper 
default_timeout( 2.0) 
it "fails when dividing by zero" do 
em do 
calc = LazyCalculator .new.divide(6,0) 
calc.errback do |error| 
expect(error).to be_a ZeroDivisionError 
done 
end 
end 
end 
end 
class LazyCalculator 
include EM::Deferrable 
def divide(x, y) 
EM.add_timer( 1.0) do 
if(y == 0) 
fail ZeroDivisionError .new 
else 
result = x/y 
succeed result 
end 
end 
self 
end 
end
RSpec::EM::FakeClock 
require 'rspec/em' 
describe LazyCalculator do 
include RSpec::EM::FakeClock 
before { clock.stub } 
after { clock.reset } 
it "divides x by y" do 
calc = LazyCalculator .new.divide(6,3) 
expect(calc).to receive(: succeed).with 2 
clock.tick( 1) 
end 
it "fails when dividing by zero" do 
calc = LazyCalculator .new.divide(6,0) 
expect(calc).to receive(: fail).with(kind_of( ZeroDivisionError )) 
clock.tick( 1) 
end 
end
Project Demo 
A proxy for Google Geocode API
Limitations 
● Can only use async libraries or 
have to defer to threads. 
● Hard to debug (no stack trace) 
● Harder to test 
● Difficult to build full blown 
websites.
Caveats 
● Low community support 
● The last release is almost two 
years old
Summary 
● Evented I/O offers a cost effective 
way to scale applications 
● EventMachine is a fast, scalable 
and production ready toolbox 
● Write elegant event-driven code 
● It is not the right tool for every 
problem
EM.next? 
<< ['em_synchrony' + Fiber] 
<< ['async_sinatra' + Thin] # Sinatra on EM 
<< ['goliath'] # Non-blocking web framework 
<< [EM.epoll + EM.kqueue] # maximize 
demultiplexer polling limits 
<< [Celluloid + Celluloid.IO] # Actor 
pattern + Evented I/O
EM.stop 
Thank you 
Code examples: github.com/omerisimo/em_underground

Weitere ähnliche Inhalte

Was ist angesagt?

0-60 with Goliath: High performance web services
0-60 with Goliath: High performance web services0-60 with Goliath: High performance web services
0-60 with Goliath: High performance web services
Ilya Grigorik
 
Streams are Awesome - (Node.js) TimesOpen Sep 2012
Streams are Awesome - (Node.js) TimesOpen Sep 2012 Streams are Awesome - (Node.js) TimesOpen Sep 2012
Streams are Awesome - (Node.js) TimesOpen Sep 2012
Tom Croucher
 

Was ist angesagt? (20)

Ruby Proxies for Scale, Performance, and Monitoring - GoGaRuCo - igvita.com
Ruby Proxies for Scale, Performance, and Monitoring - GoGaRuCo - igvita.comRuby Proxies for Scale, Performance, and Monitoring - GoGaRuCo - igvita.com
Ruby Proxies for Scale, Performance, and Monitoring - GoGaRuCo - igvita.com
 
0-60 with Goliath: High performance web services
0-60 with Goliath: High performance web services0-60 with Goliath: High performance web services
0-60 with Goliath: High performance web services
 
Concurrency in Python
Concurrency in PythonConcurrency in Python
Concurrency in Python
 
Why async matters
Why async mattersWhy async matters
Why async matters
 
Complex Made Simple: Sleep Better with TorqueBox
Complex Made Simple: Sleep Better with TorqueBoxComplex Made Simple: Sleep Better with TorqueBox
Complex Made Simple: Sleep Better with TorqueBox
 
Ruby Proxies for Scale, Performance, and Monitoring
Ruby Proxies for Scale, Performance, and MonitoringRuby Proxies for Scale, Performance, and Monitoring
Ruby Proxies for Scale, Performance, and Monitoring
 
WebSockets wiith Scala and Play! Framework
WebSockets wiith Scala and Play! FrameworkWebSockets wiith Scala and Play! Framework
WebSockets wiith Scala and Play! Framework
 
About Node.js
About Node.jsAbout Node.js
About Node.js
 
Node.js - Advanced Basics
Node.js - Advanced BasicsNode.js - Advanced Basics
Node.js - Advanced Basics
 
Streams are Awesome - (Node.js) TimesOpen Sep 2012
Streams are Awesome - (Node.js) TimesOpen Sep 2012 Streams are Awesome - (Node.js) TimesOpen Sep 2012
Streams are Awesome - (Node.js) TimesOpen Sep 2012
 
A complete guide to Node.js
A complete guide to Node.jsA complete guide to Node.js
A complete guide to Node.js
 
TorqueBox: The beauty of Ruby with the power of JBoss. Presented at Devnexus...
TorqueBox: The beauty of Ruby with the power of JBoss.  Presented at Devnexus...TorqueBox: The beauty of Ruby with the power of JBoss.  Presented at Devnexus...
TorqueBox: The beauty of Ruby with the power of JBoss. Presented at Devnexus...
 
Devignition 2011
Devignition 2011Devignition 2011
Devignition 2011
 
Introduction to Python Celery
Introduction to Python CeleryIntroduction to Python Celery
Introduction to Python Celery
 
Async programming and python
Async programming and pythonAsync programming and python
Async programming and python
 
TorqueBox for Rubyists
TorqueBox for RubyistsTorqueBox for Rubyists
TorqueBox for Rubyists
 
Nodejs Explained with Examples
Nodejs Explained with ExamplesNodejs Explained with Examples
Nodejs Explained with Examples
 
How NOT to write in Node.js
How NOT to write in Node.jsHow NOT to write in Node.js
How NOT to write in Node.js
 
Node.js: A Guided Tour
Node.js: A Guided TourNode.js: A Guided Tour
Node.js: A Guided Tour
 
Introduction to node.js
Introduction to node.jsIntroduction to node.js
Introduction to node.js
 

Ähnlich wie Scaling Ruby with Evented I/O - Ruby underground

A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...
Tom Croucher
 
Ruby HTTP clients comparison
Ruby HTTP clients comparisonRuby HTTP clients comparison
Ruby HTTP clients comparison
Hiroshi Nakamura
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
Tom Croucher
 
[Type text]ECET465Project 2Project Assignment 2 Building a Mul.docx
[Type text]ECET465Project 2Project Assignment 2 Building a Mul.docx[Type text]ECET465Project 2Project Assignment 2 Building a Mul.docx
[Type text]ECET465Project 2Project Assignment 2 Building a Mul.docx
hanneloremccaffery
 
Project Assignment 2 Building a Multi-Threaded Web ServerThis pro.docx
Project Assignment 2 Building a Multi-Threaded Web ServerThis pro.docxProject Assignment 2 Building a Multi-Threaded Web ServerThis pro.docx
Project Assignment 2 Building a Multi-Threaded Web ServerThis pro.docx
kacie8xcheco
 
Live Streaming & Server Sent Events
Live Streaming & Server Sent EventsLive Streaming & Server Sent Events
Live Streaming & Server Sent Events
tkramar
 
1)Building a MultiThreaded Web ServerIn this lab we will devel
1)Building a MultiThreaded Web ServerIn this lab we will devel1)Building a MultiThreaded Web ServerIn this lab we will devel
1)Building a MultiThreaded Web ServerIn this lab we will devel
AgripinaBeaulieuyw
 

Ähnlich wie Scaling Ruby with Evented I/O - Ruby underground (20)

A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...
 
A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...
 
No callbacks, No Threads - Cooperative web servers in Ruby 1.9
No callbacks, No Threads - Cooperative web servers in Ruby 1.9No callbacks, No Threads - Cooperative web servers in Ruby 1.9
No callbacks, No Threads - Cooperative web servers in Ruby 1.9
 
Rhebok, High Performance Rack Handler / Rubykaigi 2015
Rhebok, High Performance Rack Handler / Rubykaigi 2015Rhebok, High Performance Rack Handler / Rubykaigi 2015
Rhebok, High Performance Rack Handler / Rubykaigi 2015
 
Node.js
Node.jsNode.js
Node.js
 
Ruby HTTP clients comparison
Ruby HTTP clients comparisonRuby HTTP clients comparison
Ruby HTTP clients comparison
 
Intro to Node
Intro to NodeIntro to Node
Intro to Node
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
 
Rack
RackRack
Rack
 
692015 programming assignment 1 building a multi­threaded w
692015 programming assignment 1 building a multi­threaded w692015 programming assignment 1 building a multi­threaded w
692015 programming assignment 1 building a multi­threaded w
 
[Type text]ECET465Project 2Project Assignment 2 Building a Mul.docx
[Type text]ECET465Project 2Project Assignment 2 Building a Mul.docx[Type text]ECET465Project 2Project Assignment 2 Building a Mul.docx
[Type text]ECET465Project 2Project Assignment 2 Building a Mul.docx
 
8 Minutes On Rack
8 Minutes On Rack8 Minutes On Rack
8 Minutes On Rack
 
Project Assignment 2 Building a Multi-Threaded Web ServerThis pro.docx
Project Assignment 2 Building a Multi-Threaded Web ServerThis pro.docxProject Assignment 2 Building a Multi-Threaded Web ServerThis pro.docx
Project Assignment 2 Building a Multi-Threaded Web ServerThis pro.docx
 
Live Streaming & Server Sent Events
Live Streaming & Server Sent EventsLive Streaming & Server Sent Events
Live Streaming & Server Sent Events
 
Future Decoded - Node.js per sviluppatori .NET
Future Decoded - Node.js per sviluppatori .NETFuture Decoded - Node.js per sviluppatori .NET
Future Decoded - Node.js per sviluppatori .NET
 
Server Side Swift: Vapor
Server Side Swift: VaporServer Side Swift: Vapor
Server Side Swift: Vapor
 
Test driven infrastructure
Test driven infrastructureTest driven infrastructure
Test driven infrastructure
 
Web
WebWeb
Web
 
1)Building a MultiThreaded Web ServerIn this lab we will devel
1)Building a MultiThreaded Web ServerIn this lab we will devel1)Building a MultiThreaded Web ServerIn this lab we will devel
1)Building a MultiThreaded Web ServerIn this lab we will devel
 
Web Server.pdf
Web Server.pdfWeb Server.pdf
Web Server.pdf
 

Kürzlich hochgeladen

Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
VictoriaMetrics
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Medical / Health Care (+971588192166) Mifepristone and Misoprostol tablets 200mg
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
masabamasaba
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
VictorSzoltysek
 

Kürzlich hochgeladen (20)

call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto
 
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
 
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With SimplicityWSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
 
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 

Scaling Ruby with Evented I/O - Ruby underground

  • 1. Scaling :ruby with Evented I/O Omer Gazit [github.com/omerisimo]
  • 2. Scaling Strategies[] << "Machines" << "Processes" << "Threads" << "Reactor pattern"
  • 3. Blocking I/O start wait for I/O [e.g. file,network] complete
  • 4. Non-Blocking I/O start call I/O operation Do something else complete Kernel I/O callback()
  • 5. :sync def sync_io(file_name) file = File.open(file_name) puts "File #{file_name} opened" end
  • 6. :async def async_io(file_name) file = File.async_open(file_name) file.callback do |result| puts "File #{file_name} opened" end end
  • 7. Reactor pattern “The reactor design pattern is an event handling pattern for handling service requests delivered concurrently… The service handler then demultiplexes the incoming requests and dispatches them synchronously to the associated request handlers.” -wikipedia
  • 8. Reactor pattern “The reactor design pattern is an event handling pattern for handling service requests delivered concurrently… The service handler then demultiplexes the incoming requests and dispatches them synchronously to the associated request handlers.” -wikipedia
  • 9. Reactor pattern IO Stream Demultiplexer Event Handler A Event Handler B Event Handler C Event Dispatcher
  • 10. Reactor pattern A reactor is a single thread running an endless loop that reacts to incoming events
  • 11. Reactor pattern A reactor is a single thread running an endless loop that reacts to incoming events
  • 12. event_loop do while reactor_running? expired_timers.each { |timer| timer.process } new_network_io.each { |io| io.process } end
  • 13. Reactor.when? ● Proxies ● Real time data delivery (Websockets) ● Streaming ● Background processing (MQ listener) ● High throughput and mostly I/O bound
  • 14. { javascript: "Node.js", ruby: "EventMachine", perl: "AnyEvent", python: "Twisted", c: ["libev", "libevent"] } implementations=
  • 15. EventMachine A toolkit for writing evented applications in Ruby
  • 16. But node.js is so much faster... Is it really faster?
  • 17. Simple HTTP Server Node.js var http = require('http'); http.createServer(function (request, response) { response.writeHead(200, {'Content-Type': 'text/plain'} ); response.send('Hello Worldn'); }).listen(8080, '0.0.0.0'); console.log('Server running on port 8080');
  • 18. Simple HTTP Server EventMachine EM.run do EM.start_server "0.0.0.0", 8080 do |server| def server.receive_data(data) response = EM::DelegatedHttpResponse .new(self) response.status = 200; response.content_type 'text/plain' response.content = "Hello World n" response.send_response end end end
  • 19. Showdown results = { node: { req_per_sec: 2898, req_time_ms: 35 }, em: { req_per_sec: 6751, req_time_ms: 15 } } ab -n 1000 -c 100 "http://localhost:8080/" * executed on my MacBook Air
  • 20. RabbitMQ Processor Node.js var amqp = require('amqp'); var connection = amqp.createConnection(); connection.on( 'ready', function() { connection.queue( 'my_queue' , function(queue) { queue.subscribe( function(payload) { console.log("Received message: " + payload.body); } }); var exchange = connection.exchange(); exchange.publish( 'my_queue' , { body: 'Hello World!' }); });
  • 21. RabbitMQ Processor EventMachine require 'amqp' EM.run do connection = AMQP.connect(host: '0.0.0.0') channel = AMQP::Channel .new(connection) queue = channel.queue( "my_queue" ) queue.subscribe do |metadata, payload| puts "Received message: #{payload}." end exchange = channel.default_exchange exchange.publish "Hello world!" ,routing_key : "my_queue" end
  • 22. Showdown average_time_ms = { node: 4285, em: 3488 } send and receive 10k messages * executed on my MacBook Air
  • 23. EM can be really fast If used correctly!
  • 24. Never Block the Event Loop
  • 25. Never Block Blocking Non-Blocking EM.run do puts "Started EM" sleep 2.0 puts "Shutting down EM" EM.stop end EM.run do puts "Started EM" EM.add_periodic_timer( 1.0) do puts "Tick" end EM.add_timer( 2.0) do puts "Shutting down EM" EM.stop end end
  • 26. Never Block Blocking Non-Blocking require 'net/http' EM.run do response = Net::HTTP.get(URL) puts "Completed HTTP request" EM.stop end require 'em-http' EM.run do http = EM::HttpRequest .new(URL).get http.callback do |response| puts "Completed HTTP request" EM.stop end end
  • 27. module NonBlock << "igrigorik/em-http-request" # Asynchronous HTTP Client << "eventmachine/evma_httpserver" # HTTP Server << "igrigorik/em-websocket" # WebSockets server << "igrigorik/em-proxy" # High-performance transparent proxies << "brianmario/mysql2" # Make sure to use with :async => true << "royaltm/ruby-em-pg-client" # PostgreSQL EM client << "bcg/em-mongo" # EM MongoDB driver (based off of RMongo) << "simulacre/em-ssh" # EM compatible Net::SSH << "pressly/uber-s3" # S3 client with asynchronous I/O adapters << "tmm1/amqp" # AMQP client for EM * See full list of protocols at: github.com/eventmachine/eventmachine/wiki/Protocol-Implementations
  • 28. module NonBlock << "igrigorik/em-http-request" << "eventmachine/evma_httpserver" << "igrigorik/em-websocket" << "igrigorik/em-proxy" << "brianmario/mysql2" << "royaltm/ruby-em-pg-client" << "bcg/em-mongo" << "simulacre/em-ssh" << "pressly/uber-s3" << "tmm1/amqp" * See full list of protocols at: github.com/eventmachine/eventmachine/wiki/Protocol-Implementations
  • 29. Never Block the Event Loop
  • 30. EM.defer Defer blocking code to a thread EM.run do long_operation = proc { sleep(1.0) "result" } callback = proc {|result| puts "Received #{result}" EM.stop } EM.defer(long_operation, callback) end
  • 31. EM.next_tick Postpone execution to the next iteration Blocking Non-Blocking EM.run do (1..10000).each do |index| puts "Processing #{index}" end EM.stop end EM.run do index = 0 process_index = proc { if index < 10000 puts "Processing #{index}" index += 1 EM.next_tick &process_index else EM.stop end } EM.next_tick &process_index end
  • 33. EM::Deferrable EM::Deferrable != EM.defer class DeferrableTimer include EM::Deferrable def wait EM.add_timer( 1.0) do succeed "result" end self end end EM.run do timer = DeferrableTimer .new.wait timer.callback do |result| puts "1 second has passed!" EM.stop end end
  • 34. EM::Connection class EchoServer < EM::Connection def post_init puts "Client connecting" end def receive_data (data) puts "Client sending data #{data}" send_data ">> #{data}" end def unbind puts "Client disconnecting" end end EM.run do EM.start_server( "0.0.0.0", 9000, EchoServer ) # Listen on TCP socket end
  • 35. EM::Queue A cross thread, reactor scheduled, linear queue EM.run do queue = EM::Queue.new queue_handler = proc { |message| puts "Handling message #{message}" EM.next_tick{ queue.pop( &queue_handler) } } EM.next_tick{ queue.pop( &queue_handler) } EM.add_periodic_timer( 1.0) do message = Time.now.to_s puts "Pushing message ' #{message}' to queue" queue.push(message) end end
  • 36. EM::Channel Provides a simple thread-safe way to transfer data between (typically)long running tasks EM.run do channel = EM::Channel.new handler_1 = proc { | message| puts "Handler 1 message #{message}" } handler_2 = proc { | message| puts "Handler 2 message #{message}" } channel.subscribe &handler_1 channel.subscribe &handler_2 EM.add_periodic_timer( 1.0) do message = Time.now.to_s puts "Sending message ' #{message}' to channel" channel << message end end
  • 37. EM::Primitives << EM::Queue # A cross thread, reactor scheduled, linear queue << EM::Channel # Simple thread-safe way to transfer data between (typically)long running tasks << EM::Iterator # A simple iterator for concurrent asynchronous work << EM.System() # Run external commands without blocking
  • 38. EM.run do EM.add_timer( 1) do json = nil begin data = JSON.parse(json) puts "Parsed Json data: #{data}" rescue StandardException => e puts "Error: #{e.message}" end EM.stop end end Error Handling
  • 39. Error Handling EM.run do EM.add_timer( 1) do http = EM::HttpRequest .new(BAD_URI).get http.callback do puts "Completed HTTP request" EM.stop end http.errback do |error| puts "Error: #{error.error }" EM.stop end end end
  • 40. EM::Synchrony Fiber aware EventMachine clients and convenience classes github.com/igrigorik/em-synchrony
  • 41. EM::Synchrony em-synchrony/em-http require 'em-synchrony' require 'em-synchrony/em-http' EM.synchrony do res = EM::HttpRequest .new(URL).get puts "Response: #{res.response }" EM.stop end em-http-request require 'eventmachine' require 'em-http' EM.run do http = EM::HttpRequest .new(URL).get http.callback do puts "Completed HTTP request" EM.stop end end
  • 43. EM::Spec require 'em-spec/rspec' describe LazyCalculator do include EM::SpecHelper default_timeout( 2.0) it "divides x by y" do em do calc = LazyCalculator .new.divide(6,3) calc.callback do |result| expect(result).to eq 2 done end end end end class LazyCalculator include EM::Deferrable def divide(x, y) EM.add_timer( 1.0) do if(y == 0) fail ZeroDivisionError .new else result = x/y succeed result end end self end end
  • 44. EM::Spec require 'em-spec/rspec' describe LazyCalculator do include EM::SpecHelper default_timeout( 2.0) it "fails when dividing by zero" do em do calc = LazyCalculator .new.divide(6,0) calc.errback do |error| expect(error).to be_a ZeroDivisionError done end end end end class LazyCalculator include EM::Deferrable def divide(x, y) EM.add_timer( 1.0) do if(y == 0) fail ZeroDivisionError .new else result = x/y succeed result end end self end end
  • 45. RSpec::EM::FakeClock require 'rspec/em' describe LazyCalculator do include RSpec::EM::FakeClock before { clock.stub } after { clock.reset } it "divides x by y" do calc = LazyCalculator .new.divide(6,3) expect(calc).to receive(: succeed).with 2 clock.tick( 1) end it "fails when dividing by zero" do calc = LazyCalculator .new.divide(6,0) expect(calc).to receive(: fail).with(kind_of( ZeroDivisionError )) clock.tick( 1) end end
  • 46. Project Demo A proxy for Google Geocode API
  • 47. Limitations ● Can only use async libraries or have to defer to threads. ● Hard to debug (no stack trace) ● Harder to test ● Difficult to build full blown websites.
  • 48. Caveats ● Low community support ● The last release is almost two years old
  • 49. Summary ● Evented I/O offers a cost effective way to scale applications ● EventMachine is a fast, scalable and production ready toolbox ● Write elegant event-driven code ● It is not the right tool for every problem
  • 50. EM.next? << ['em_synchrony' + Fiber] << ['async_sinatra' + Thin] # Sinatra on EM << ['goliath'] # Non-blocking web framework << [EM.epoll + EM.kqueue] # maximize demultiplexer polling limits << [Celluloid + Celluloid.IO] # Actor pattern + Evented I/O
  • 51. EM.stop Thank you Code examples: github.com/omerisimo/em_underground

Hinweis der Redaktion

  1. Been around for over 10 years Widely used in production by many companies Postrank (purchased by Google) Github Heroku Engine Yard For example Thin web server is implemented using EventMachine
  2. Demo
  3. Show demo