EventMachine  EM.run{ awesome_stuff! }                             Christopher Spring
@autonomous
EventMachine
EventMachine
• Mostly IO bound• Handle thousands  concurrent connections• Stream data• Real time data delivery• You’ve got Mad Ruby Ski...
What is EventMachine?• Toolkit for creating evented applications• Implementation of the Reactor Pattern• MRI,YARV, jRuby, ...
Evented?
Evented?puts(1)puts(2)puts(3)
Evented?puts(1)puts(2)puts(3)             puts(1)             work{ puts(3) }             puts(2)
Reactor pattern“Event handling pattern for handling servicerequests delivered concurrently to a servicehandler by one or m...
Http   Keyboard     Udp   etc                   Service handler                    Demultiplexer                   Event d...
Http   Keyboard     Udp   etc                   Service handler                    Demultiplexer                   Event d...
Http   Keyboard     Udp   etc                   Service handler                    Demultiplexer                   Event d...
Benefits• Application code separate from reactor• Non blocking IO• Single process• No threads!
Limitations• Demultiplexing limits• Some others we’ll cover later...
Teh Basics• EM.run• EM.connection• EM.next_tick• EM.defer• EM::Queue• EM::Channel
Teh Basics• EM.run• EM.connection• EM.next_tick• EM.defer• EM::Queue• EM::Channel
require "rubygems"require "eventmachine"EM.run do  # ...  EM.stopend
... don’t do this!• big ass loops  •   1_000_000.times{}  •   while condition?• sleep• blocking IO
Teh Basics• EM.run• EM.connection• EM.next_tick• EM.defer• EM::Queue• EM::Channel
class EchoServer < EM::Connection  def post_init    puts "New connection"  end  def unbind    puts "Connection closed"  en...
class EchoServer < EM::Connection  def post_init    puts "New connection"  end  def unbind    puts "Connection closed"    ...
# TCPEM.run do  EM.start_server(127.0.0.1, 9000, EchoServer)end# UDPEM.run do  EM.open_datagram_socket(127.0.0.1, 9000, Ec...
class EchoClient < EM::Connection  def post_init    puts "Sending stuff to server"    send_data("Why, hello there!")  end ...
class EchoClient < EM::Connection  def post_init    puts "Sending stuff to server"    send_data("Why, hello there!")  end ...
Teh Basics• EM.run• EM.connection• EM.next_tick• EM.defer• EM::Queue• EM::Channel
EM.run do  EM.next_tick do    # ... awesome stuff  endend
Task 1Task 2Task 3
Task 1Task 2Task 3 EM.run{ }
Task 1Task 2Task 3 EM.run{ } EM.next_tick{ }
Teh Basics• EM.run• EM.connection• EM.next_tick• EM.defer• EM::Queue• EM::Channel
EM.run do  EM.defer do    send_email( user1 )  end  EM.defer do    send_email( user2 )  end  EM.defer do    send_email( us...
Email 1Email 2Email 3
Email 1Email 2Email 3 EM.defer{ }
EM.run do  get_stuff = Proc.new do    # ...    long_running_io()  end  use_stuff = Proc.new do |io_results|    # ...  end ...
Teh Basics• EM.run• EM.connection• next_tick; add_timer; add_periodic_timer• EM.defer• EM::Queue• EM::Channel
EM.run do  queue = EM::Queue.new  # ...  queue.push( data1, data2 )  # ...  queue.pop { |data| puts data } # >> data1end
EM.run do  queue = EM::Queue.new  EM.defer do    sleep( 2 )    queue.push( some@email.com )    sleep( 3 )    queue.push( s...
Teh Basics• EM.run• EM.connection• EM.next_tick• EM.defer• EM::Queue• EM::Channel
EM.run do  channel = EM::Channel.new  EM.defer do    channel.subscribe do |msg|      puts "Received #{msg}"    end  end  E...
Deferrable• Light weight concurrency• Delayed execution with triggers • :succeeded • :failed • nil• callback and errback
class LoanRequest  include EM::Deferrable  def initialize( name )    @name = name    callback do |who|      puts "Approved...
class LoanRequest  include EM::Deferrable  def initialize( name )    @name = name    callback do |who|              EM.run...
class LoanRequest  include EM::Deferrable  def initialize( name )    @name = name    callback do |who|              EM.run...
state: nil
state: nilcallback{}callback{}callback{}
state: nilcallback{}                errback{}callback{}                errback{}callback{}
state: succeededcallback{}                      errback{}callback{}                      errback{}callback{}
state: succeededcallback{}callback{}callback{}
state: succeeded
state: failedcallback{}                   errback{}callback{}                   errback{}callback{}
state: failed                errback{}                errback{}
state: failed
class Mailer  include EM::Deferrable  def add_mailing(val)    callback do      sleep 1      puts "Sent #{val}"    end  end...
EM.run do                                m = Mailer.newclass Mailer                                m.add_mailing(1)  inclu...
EM.run do                                m = Mailer.newclass Mailer                                m.add_mailing(1)  inclu...
Gotchas• Inverted flow of control can make  debugging difficult• Synchronous code will slow it down • Use/Write libraries fo...
Worth checking out• EM-Synchrony:  https://github.com/igrigorik/em-synchrony• Goliath:  https://github.com/postrank-labs/g...
Baie Dankie!
Questions?
EventMachine for RubyFuZa   2012
EventMachine for RubyFuZa   2012
EventMachine for RubyFuZa   2012
Upcoming SlideShare
Loading in...5
×

EventMachine for RubyFuZa 2012

2,698

Published on

lighting tour of eventmachines basic structures

Published in: Technology, Business
0 Comments
5 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,698
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
26
Comments
0
Likes
5
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • ScaleConf: Doing anything at scale requires better decisions about the tools you use.\nJust because the fit seemed ok at first, when things get rolling you really want to have the right kind of hammer.\n
  • ... and to achieve dramatic results, you need to orchestrate a specialized set of components\n\ncomplexity is a tradeoff based on the domain of your problem.\n
  • \n
  • \n
  • c10k problem\n
  • c++ reactor: mri, yarv, Rubinius\n\njava reactor for, um, java\n
  • used to sequential code\nevented code stores some block...\nand executes at some later stage\n
  • used to sequential code\nevented code stores some block...\nand executes at some later stage\n
  • \n
  • Input is received concurrently\nEvent dispatch is synchronous\nThe reactor design pattern is an event handling pattern for handling service requests delivered concurrently to a service handler by one or more inputs. The service handler then demultiplexes the incoming requests and dispatches them synchronously to the associated request handlers\n\n
  • Input is received concurrently\nEvent dispatch is synchronous\nThe reactor design pattern is an event handling pattern for handling service requests delivered concurrently to a service handler by one or more inputs. The service handler then demultiplexes the incoming requests and dispatches them synchronously to the associated request handlers\n\n
  • Input is received concurrently\nEvent dispatch is synchronous\nThe reactor design pattern is an event handling pattern for handling service requests delivered concurrently to a service handler by one or more inputs. The service handler then demultiplexes the incoming requests and dispatches them synchronously to the associated request handlers\n\n
  • Input is received concurrently\nEvent dispatch is synchronous\nThe reactor design pattern is an event handling pattern for handling service requests delivered concurrently to a service handler by one or more inputs. The service handler then demultiplexes the incoming requests and dispatches them synchronously to the associated request handlers\n\n
  • Input is received concurrently\nEvent dispatch is synchronous\nThe reactor design pattern is an event handling pattern for handling service requests delivered concurrently to a service handler by one or more inputs. The service handler then demultiplexes the incoming requests and dispatches them synchronously to the associated request handlers\n\n
  • Input is received concurrently\nEvent dispatch is synchronous\nThe reactor design pattern is an event handling pattern for handling service requests delivered concurrently to a service handler by one or more inputs. The service handler then demultiplexes the incoming requests and dispatches them synchronously to the associated request handlers\n\n
  • \n
  • Limitations ito select/epoll and the number of open file descriptors\n\n&amp;#x201C;First, you need to tell EventMachine to use epoll instead of select. Second, you need to prepare your program to use more than 1024 descriptors, an operation that generally requires superuser privileges. Third, you will probably want your process to drop the superuser privileges after you increase your process&amp;#x2019;s descriptor limit.&amp;#x201D; - See: http://eventmachine.rubyforge.org/docs/EPOLL.html\n
  • connection -&gt; servers and clients and shit\nnext_tick -&gt; run code at the next opportunity (always run in main thread)\ndefer -&gt; defer work to run on a thread (green) - 20 by default\nQueue -&gt; data\nChannel -&gt; comms\n
  • next_tick -&gt; run code at the next opportunity (always run in main thread)\ndefer -&gt; defer work to run on a thread (green) - 20 by default\nQueue -&gt; data\nChannel -&gt; comms\n
  • Main reactor is single threaded - similar to while reactor_running?; ... end\nEM.run takes over the process...\nit&amp;#x2019;s blocking\n\n
  • ... anything that blocks the main reactor is a no-no\n\nAnything that takes more than a few millisecond...\nrun on separate thread or broken into smaller blocks...\nand run on next_tick\n
  • Used for creating clients and servers\n
  • EM interchangeable with EventMachine\nreceive_data is unbuffered\nthese methods are the only ones that will be called by the event loop\n\ncan have a module, and it&amp;#x2019;s behaviour will be mixed into an EM:: Connection\n
  • \n
  • EM interchangeable with EventMachine\nreceive_data is unbuffered\n
  • Schedules work to happen on the main thread\non the next iteration of the reactor\n
  • Next tick is a tool for bringing data/work back into the run loop\n\nUm, wtf for? You may find yourself asking...\n
  • Tasks are not broken up into smaller pieces\n... takes really long to complete task 2 and 3\nDo very little work in the main reactor\n
  • Tasks are not broken up into smaller pieces\n... takes really long to complete task 2 and 3\nDo very little work in the main reactor\n
  • Tasks are not broken up into smaller pieces\n... takes really long to complete task 2 and 3\nDo very little work in the main reactor\n
  • Tasks are not broken up into smaller pieces\n... takes really long to complete task 2 and 3\nDo very little work in the main reactor\n
  • Tasks are not broken up into smaller pieces\n... takes really long to complete task 2 and 3\nDo very little work in the main reactor\n
  • Tasks are not broken up into smaller pieces\n... takes really long to complete task 2 and 3\nDo very little work in the main reactor\n
  • Tasks are not broken up into smaller pieces\n... takes really long to complete task 2 and 3\nDo very little work in the main reactor\n
  • Tasks are not broken up into smaller pieces\n... takes really long to complete task 2 and 3\nDo very little work in the main reactor\n
  • Tasks are not broken up into smaller pieces\n... takes really long to complete task 2 and 3\nDo very little work in the main reactor\n
  • Tasks are not broken up into smaller pieces\n... takes really long to complete task 2 and 3\nDo very little work in the main reactor\n
  • Tasks are not broken up into smaller pieces\n... takes really long to complete task 2 and 3\nDo very little work in the main reactor\n
  • Tasks are not broken up into smaller pieces\n... takes really long to complete task 2 and 3\nDo very little work in the main reactor\n
  • Tasks are not broken up into smaller pieces\n... takes really long to complete task 2 and 3\nDo very little work in the main reactor\n
  • Tasks are not broken up into smaller pieces\n... takes really long to complete task 2 and 3\nDo very little work in the main reactor\n
  • Tasks are not broken up into smaller pieces\n... takes really long to complete task 2 and 3\nDo very little work in the main reactor\n
  • Tasks are not broken up into smaller pieces\n... takes really long to complete task 2 and 3\nDo very little work in the main reactor\n
  • schedules work to take place on a different thread\n
  • defer runs on thread in thread pool (20 by default)\n
  • defer allows work to be done on one of the thread pool threads\n
  • defer allows work to be done on one of the thread pool threads\n
  • defer allows work to be done on one of the thread pool threads\n
  • defer allows work to be done on one of the thread pool threads\n
  • get_stuff run in separate thread,\nData is brought back to the main thread\nand passed on to the callback\nCallback executes on the main thread\nKinda like a future\n
  • Ordered message queue\nThread safe\n
  • Popped data is brought back to the main thread\npush/pop scheduled next iteration of the main reactor thread\n
  • Infinite processing - always do work if there is some available\ndata pops off the queue only when data is available (no blocking)\n\n
  • next_tick -&gt; run code at the next opportunity (always run in main thread)\ndefer -&gt; defer work to run on a thread (green) - 20 by default\nQueue -&gt; data\nChannel -&gt; comms\n
  • Pub/Sub mechanism\n
  • :succeeded -&gt; callback\n:failed -&gt; errback\nnil -&gt; reset (slate wiped clean)\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • errbacks are trashed\ncallbacks are executed immediately in the order they were added\n
  • errbacks are trashed\ncallbacks are executed immediately in the order they were added\n
  • errbacks are trashed\ncallbacks are executed immediately in the order they were added\n
  • errbacks are trashed\ncallbacks are executed immediately in the order they were added\n
  • errbacks are trashed\ncallbacks are executed immediately in the order they were added\n
  • callbacks are trashed\nerrbacks are executed immediately in the order they were added\n
  • callbacks are trashed\nerrbacks are executed immediately in the order they were added\n
  • callbacks are trashed\nerrbacks are executed immediately in the order they were added\n
  • callbacks are trashed\nerrbacks are executed immediately in the order they were added\n
  • callbacks are trashed\nerrbacks are executed immediately in the order they were added\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n\n
  • \n
  • \n
  • EventMachine for RubyFuZa 2012

    1. 1. EventMachine EM.run{ awesome_stuff! } Christopher Spring
    2. 2. @autonomous
    3. 3. EventMachine
    4. 4. EventMachine
    5. 5. • Mostly IO bound• Handle thousands concurrent connections• Stream data• Real time data delivery• You’ve got Mad Ruby Skills
    6. 6. What is EventMachine?• Toolkit for creating evented applications• Implementation of the Reactor Pattern• MRI,YARV, jRuby, Rubinius
    7. 7. Evented?
    8. 8. Evented?puts(1)puts(2)puts(3)
    9. 9. Evented?puts(1)puts(2)puts(3) puts(1) work{ puts(3) } puts(2)
    10. 10. Reactor pattern“Event handling pattern for handling servicerequests delivered concurrently to a servicehandler by one or more inputs. The servicehandler then demultiplexes the incomingrequests and dispatches them synchronouslyto the associated request handlers.” http://en.wikipedia.org/wiki/Reactor_pattern
    11. 11. Http Keyboard Udp etc Service handler Demultiplexer Event dispatcherEvent Handler AEvent Handler BEvent Handler CEvent Handler D
    12. 12. Http Keyboard Udp etc Service handler Demultiplexer Event dispatcherEvent Handler AEvent Handler BEvent Handler CEvent Handler D
    13. 13. Http Keyboard Udp etc Service handler Demultiplexer Event dispatcher Thread 1Event Handler A Thread 2Event Handler B ...Event Handler CEvent Handler D Thread 20
    14. 14. Benefits• Application code separate from reactor• Non blocking IO• Single process• No threads!
    15. 15. Limitations• Demultiplexing limits• Some others we’ll cover later...
    16. 16. Teh Basics• EM.run• EM.connection• EM.next_tick• EM.defer• EM::Queue• EM::Channel
    17. 17. Teh Basics• EM.run• EM.connection• EM.next_tick• EM.defer• EM::Queue• EM::Channel
    18. 18. require "rubygems"require "eventmachine"EM.run do # ... EM.stopend
    19. 19. ... don’t do this!• big ass loops • 1_000_000.times{} • while condition?• sleep• blocking IO
    20. 20. Teh Basics• EM.run• EM.connection• EM.next_tick• EM.defer• EM::Queue• EM::Channel
    21. 21. class EchoServer < EM::Connection def post_init puts "New connection" end def unbind puts "Connection closed" end def receive_data(data) send_data ">> #{data}" endendEM.run do EM.start_server(127.0.0.1, 9000, EchoServer) puts "Started server at 127.0.0.1:9000"end
    22. 22. class EchoServer < EM::Connection def post_init puts "New connection" end def unbind puts "Connection closed" # $ telnet localhost 9000 end # Hello # >> Hello def receive_data(data) # Bye send_data ">> #{data}" # >> Bye endendEM.run do EM.start_server(127.0.0.1, 9000, EchoServer) puts "Started server at 127.0.0.1:9000"end
    23. 23. # TCPEM.run do EM.start_server(127.0.0.1, 9000, EchoServer)end# UDPEM.run do EM.open_datagram_socket(127.0.0.1, 9000, EchoServer)end# Unix-domain serverEM.run do EM.start_unix_domain_server(/tmp/sock, nil, EchoServer)end
    24. 24. class EchoClient < EM::Connection def post_init puts "Sending stuff to server" send_data("Why, hello there!") end def unbind puts "Connection closed" end def receive_data(data) puts ">> #{data}" endendEM.run do EM.connect(127.0.0.1, 9000, EchoClient)end
    25. 25. class EchoClient < EM::Connection def post_init puts "Sending stuff to server" send_data("Why, hello there!") end def unbind puts "Connection closed" end def receive_data(data) puts ">> #{data}" endendEM.run do EM.connect(127.0.0.1, 9000, EchoClient)end
    26. 26. Teh Basics• EM.run• EM.connection• EM.next_tick• EM.defer• EM::Queue• EM::Channel
    27. 27. EM.run do EM.next_tick do # ... awesome stuff endend
    28. 28. Task 1Task 2Task 3
    29. 29. Task 1Task 2Task 3 EM.run{ }
    30. 30. Task 1Task 2Task 3 EM.run{ } EM.next_tick{ }
    31. 31. Teh Basics• EM.run• EM.connection• EM.next_tick• EM.defer• EM::Queue• EM::Channel
    32. 32. EM.run do EM.defer do send_email( user1 ) end EM.defer do send_email( user2 ) end EM.defer do send_email( user3 ) endend
    33. 33. Email 1Email 2Email 3
    34. 34. Email 1Email 2Email 3 EM.defer{ }
    35. 35. EM.run do get_stuff = Proc.new do # ... long_running_io() end use_stuff = Proc.new do |io_results| # ... end # ... EM.defer( get_stuff, use_stuff )end
    36. 36. Teh Basics• EM.run• EM.connection• next_tick; add_timer; add_periodic_timer• EM.defer• EM::Queue• EM::Channel
    37. 37. EM.run do queue = EM::Queue.new # ... queue.push( data1, data2 ) # ... queue.pop { |data| puts data } # >> data1end
    38. 38. EM.run do queue = EM::Queue.new EM.defer do sleep( 2 ) queue.push( some@email.com ) sleep( 3 ) queue.push( some@one.com) end welcomer = Proc.new do |email| send_welcome( email ) EM.next_tick( queue.pop(&welcomer) ) end queue.pop(&welcomer);end
    39. 39. Teh Basics• EM.run• EM.connection• EM.next_tick• EM.defer• EM::Queue• EM::Channel
    40. 40. EM.run do channel = EM::Channel.new EM.defer do channel.subscribe do |msg| puts "Received #{msg}" end end EM.add_periodic_timer(1) do channel << Time.now endend
    41. 41. Deferrable• Light weight concurrency• Delayed execution with triggers • :succeeded • :failed • nil• callback and errback
    42. 42. class LoanRequest include EM::Deferrable def initialize( name ) @name = name callback do |who| puts "Approved #{who}!" end errback do |who| puts "Denied #{who}!" end end def approved! # succeed( *args ) set_deferred_status(:succeeded, @name) end def denied! # fail( *args ) set_deferred_status(:failed, @name) endend
    43. 43. class LoanRequest include EM::Deferrable def initialize( name ) @name = name callback do |who| EM.run do puts "Approved #{who}!" s1 = LoanRequest.new(Marc) end s1.approved! errback do |who| s2 = LoanRequest.new(Chris) puts "Denied #{who}!" EM.add_timer(2){ s2.denied! } end end end def approved! # succeed( *args ) set_deferred_status(:succeeded, @name) end def denied! # fail( *args ) set_deferred_status(:failed, @name) endend
    44. 44. class LoanRequest include EM::Deferrable def initialize( name ) @name = name callback do |who| EM.run do puts "Approved #{who}!" s1 = LoanRequest.new(Marc) end s1.approved! errback do |who| s2 = LoanRequest.new(Chris) puts "Denied #{who}!" EM.add_timer(2){ s2.denied! } end end end def approved! # succeed( *args ) set_deferred_status(:succeeded, @name) end # :00 Approved Marc! # :02 Denied Chris! def denied! # fail( *args ) set_deferred_status(:failed, @name) endend
    45. 45. state: nil
    46. 46. state: nilcallback{}callback{}callback{}
    47. 47. state: nilcallback{} errback{}callback{} errback{}callback{}
    48. 48. state: succeededcallback{} errback{}callback{} errback{}callback{}
    49. 49. state: succeededcallback{}callback{}callback{}
    50. 50. state: succeeded
    51. 51. state: failedcallback{} errback{}callback{} errback{}callback{}
    52. 52. state: failed errback{} errback{}
    53. 53. state: failed
    54. 54. class Mailer include EM::Deferrable def add_mailing(val) callback do sleep 1 puts "Sent #{val}" end end def connection_open! puts Open connection succeed end def connection_lost! puts Lost connection set_deferred_status nil endend
    55. 55. EM.run do m = Mailer.newclass Mailer m.add_mailing(1) include EM::Deferrable m.add_mailing(2) m.connection_open! def add_mailing(val) callback do EM.add_timer(1) do sleep 1 m.connection_lost! puts "Sent #{val}" EM.add_timer(2) do end m.add_mailing(3) end m.add_mailing(4) m.connection_open! def connection_open! end puts Open connection end succeed end end def connection_lost! puts Lost connection set_deferred_status nil endend
    56. 56. EM.run do m = Mailer.newclass Mailer m.add_mailing(1) include EM::Deferrable m.add_mailing(2) m.connection_open! def add_mailing(val) callback do EM.add_timer(1) do sleep 1 m.connection_lost! puts "Sent #{val}" EM.add_timer(2) do end m.add_mailing(3) end m.add_mailing(4) m.connection_open! def connection_open! end puts Open connection end succeed end end def connection_lost! # Open connection puts Lost connection # Sent 1 set_deferred_status nil # Sent 2 end # Lost connectionend # Open connection # Sent 3 # Sent 4
    57. 57. Gotchas• Inverted flow of control can make debugging difficult• Synchronous code will slow it down • Use/Write libraries for EM
    58. 58. Worth checking out• EM-Synchrony: https://github.com/igrigorik/em-synchrony• Goliath: https://github.com/postrank-labs/goliath• Async_Sinatra: https://github.com/raggi/async_sinatra
    59. 59. Baie Dankie!
    60. 60. Questions?
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.

    ×