embracing events
DESCRIPTION
"Embracing Events" session for Railswaycon 2009TRANSCRIPT
![Page 1: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/1.jpg)
Embracing Events
Stop polling … react.
Lourens Naudé, Trade2Win
![Page 2: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/2.jpg)
Bio
http://github.com/methodmissing Ruby contractor General misfit for the current economy Ruby, C#, Java, admin 500 nodes, CSS * deferred payment Currently building out a consumer forex platform @ Trade2Win
Slippage matter.
creator scrooge, mysqlplus_adapter, mri_instrumentation
contributor Rails, mysqlplus, query_memcached, thinking-sphinx,
em-spec
![Page 3: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/3.jpg)
![Page 4: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/4.jpg)
e-vent [i-vent] something that happens or is regarded as happening; an occurrence, esp. one of some importance.
![Page 5: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/5.jpg)
A change in state ...
MySQL server sends results down the wire Connection file descriptor becomes readable
Process results Render results
Ignorance is bliss Never be flooded Only handle events that matter
![Page 6: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/6.jpg)
Talk#to_a
Context switches Scheduling Programming models Frameworks
Eventmachine Neverblock
Operating System Lessons from massively multiplayer online games Testing Q & A ?
![Page 7: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/7.jpg)
Getting Fibers (coroutines) and
Threads
![Page 8: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/8.jpg)
Scenario we all can relate to ...
Quiet weekend day, erratic thoughts from the week before comes together
Sharing space with your better half ... who's being chatty
You're being interrupted at random Let's assume an average "in the zone" startup
threshold of 2 minutes per interruption Deadlock's not an option ...
![Page 9: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/9.jpg)
Multithreading
Let the initial pattern of thought and the interruption be distinct Threads
The interruption's effective right away The context switch is 'expensive' : coding VS
whichever chore's been neglected Preemptive scheduling == constant interruption
![Page 10: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/10.jpg)
Fiber / coroutine pool
Two distinct Fibered contexts Able to defer the interruption Cheap switching : being thick skinned buys time You#resume the interruption if and when there's
time to handle it
![Page 11: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/11.jpg)
Thread
Scheduling Handled by the VM – timesliced @ 10ms by MRI Executes as soon as CPU resources become available
Availability MRI 18: Maps to a single native thread MRI 19: 1 x native thread for each Ruby thread - GIL JRuby: 1 x Java thread for each Ruby thread
Overheads Large initial stack size MRI uses a SIGVTALRM to signal a context switch
![Page 12: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/12.jpg)
Fiber
Scheduling No concurrency – scheduled by application code Never executes right away
Availability MRI 18: Patch by Aman Gupta && Joe Damato MRI 19: Core Fiber class JRuby: Poor Man's Fibers
Overheads Small initial stack size @ 4k Context switches exclusively in user space – very fast
![Page 13: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/13.jpg)
Why Fibers matter
Computes a partial result - generator Yields back to the caller Saves execution state Caller resumes Data exchange
Accept arguments through Fiber#resume Return values through Fiber.yield
![Page 14: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/14.jpg)
Threads as Coroutines
Through a voodo combination of Thread priorities Thread.pass Thread.stop Thread#run (yields CPU) or Thread#wakeup (no CPU)
Poor Man's Fibers piggy backs off a Queue MRI 18 Fibers = Threads – preemptive
scheduling, much like continuations, but with a smaller stack.
Performant, but not as lightweight as Fibers
![Page 15: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/15.jpg)
Cooperative scheduling
Request / response with evented DB access HTTP request wrapped in a Fiber => mysql->fd : SELECT * FROM users WHERE id = 1 Execution paused <= mysql->fd : #<User id: 1 uname: methodmissing> Execution resumed => mysql->fd: SELECT * FROM wishlist WHERE
user_id = 1 Execution paused <= mysql->fd: #<Wishlist id: 20 user_id 1>
![Page 16: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/16.jpg)
Cooperative VS preemptive
Fibered dispatch, query = *, result = +, int = & <GET /orders> * + *+*+*+*+*+*+ <POST /checkout> * + * + *+*+ <DELETE /sessions> *+
Threaded dispatch, interupted every 10ms <GET /orders> * & + *+*+&*+*+*&+*+ <POST /checkout> * + * +& *+*&+ <DELETE /sessions> &*+
![Page 17: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/17.jpg)
Thread 1
Thread 2
active
idle
Schedulingtime
10 ms quanta
Fiber 1
Fiber 2
active
No scheduling timeidle
Run as long as you need
Cooperative VS Preemptive
![Page 18: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/18.jpg)
Event-driven Programming
Program flow determined by events Characterized by an event handler, main
loop or reactor The reactor typically 'owns' the process loop { button.on(:click).dispatch } Binds event handlers to events Deep nesting of callbacks and constructs
eg. Twisted for Python
![Page 19: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/19.jpg)
Batch programming
wysiwig Flow determined by the developer Read → process → output
![Page 20: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/20.jpg)
Event-driven execution,
synchronous API.
![Page 21: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/21.jpg)
class FiberedMysqlConnection def query( sql ) send_query sql Fiber.yield get_result endend
EM.run{ conn.query( 'SELECT SLEEP 1' ) }
Database ...
![Page 22: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/22.jpg)
class UsersController < AC::Base def index @users = User.paginate( :page => 1 ) endend
Thin::Server.start('0.0.0.0', 3000) do
Fiber.new{ AC::Dispatcher.call( env ) }
end
… app server
![Page 23: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/23.jpg)
Frameworks
![Page 24: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/24.jpg)
Eventmachine
Implementation of the Reactor pattern C++ with Ruby Bindings JRuby compatible through jeventmachine High performance event driven IO : epoll
on Linux, kqueue on BSD and derivatives
![Page 25: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/25.jpg)
The Reactor
Maintains a global current loop time Quantum is just under 100ms … adjustable Verifies descriptors through a heartbeat Runs timer events New descriptors dropped onto a different
queue Modified descriptors processed outside loop Stopped with special Loop Break Descriptor
![Page 26: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/26.jpg)
Bindings and Callbacks
A portable signature registry / list, implemented as UUID identifiers
Callback triggers : timer fired connection read connection completed connection accepted connection unbound
![Page 27: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/27.jpg)
Eventable File Descriptors
Nonblocking Notify of read and writability Closed in 3 ways
hard immediate ( when possible, next tick ) after writing ( protocol handlers, serve HTTP page,
close connection
![Page 28: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/28.jpg)
Deferrables
A callback ... specifically a callback for :success or :failure
Immediately pushed to the background and scheduled for future execution
Deferrables should have an associated timeout
![Page 29: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/29.jpg)
Timers
Periodic or oneshot Set a max timer count to avoid flooding the
reactor Can be cancelled
![Page 30: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/30.jpg)
Files
Very fast transfer of < 32k files with EM#send_file_data
File watch API Notified when modified, deleted or moved
fastfilereader extension Memory <=> disk transfer with mmap
![Page 31: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/31.jpg)
Processes
Supports deferrable child processes through pipes
EM#system Process watch API
Notified when forked or exits
![Page 32: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/32.jpg)
Client / Server
module Challenge def post_init send_data 'psw?' end
def receive_data( data ) ( @data ||= '' ) << data endendEM.run{ EM.connect 'localhost', 80, Challenge }
![Page 33: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/33.jpg)
Neverblock
![Page 34: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/34.jpg)
Why ?
Most web apps block on IO Ruby processes has 'high' memory
overheads 60MB RSS blocking 30ms on IO == $$$ Allocated in slabs – 80MB -> 120MB Significantly reduces capacity for
concurrent requests eSpace stepped in
![Page 35: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/35.jpg)
How ?
Fibered connection pool – typically 8 to 12 Attaches to either EM or Rev as main loop Patches for Evented Mongrel && Thin to
wrap requests in Fibers Fibered DB connections for postgres &&
mysql ( with mysqlplus ) Respects transactions - BEGIN ... COMMIT
required to be on the same connection
![Page 36: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/36.jpg)
Connection 2 (idle)
Connection 1 (idle)
Fiber 1(active
)
Fiber 2(inactive)
Fiber 1 is executing
![Page 37: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/37.jpg)
Connection 2 (idle)
Connection 1 (busy)
Fiber 1(inactive
)
Fiber 2(active)
Fiber 1 issues a SQL query and passes control to Fiber 2
SELECT ...
![Page 38: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/38.jpg)
Connection 2 (busy)
Connection 1 (busy)
Fiber 1(inactive
)
Fiber 2(inactiv
e)Fiber 2 issues a SQL query and both fibers are inactive
UPDATE …
![Page 39: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/39.jpg)
Connection 2 (busy)
Connection 1 (idle)
Fiber 1(active)
Fiber 2(inactiv
e)Reactor notices first connection is finished so it resumes Fiber 1
Alfred, 28, …Tamer, 20, …
.
.
![Page 40: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/40.jpg)
Connection 2 (idle)
Connection 1 (idle)
Fiber 1(done)
Fiber 2(active)
Fiber 1 is done and reactor notices second connection is finished so it resumes Fiber 2
3600 rows affected
![Page 41: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/41.jpg)
Patches to Ruby IO Clever redirection to non-blocking methods
IO#read* => IO#read_nonblock IO#write* => IO#write_nonblock
Catches IO errors Errno::EWOULDBLOCK Errno::EAGAIN Errno::EINTR
Rescue attaches to the event loop Requests notification of read / writability Detach on success
![Page 42: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/42.jpg)
Operating System Events
![Page 43: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/43.jpg)
Signals
Software interrupts Portable
Signal.list supported on all host systems
Unobtrusive Caught Signal.trap( 'IO' ){ puts 'readable' } Sent with Process.kill( 'IO', $ )
Can be scoped to a single process or a process group
Daemons: SIGHUP && SIGTERM
![Page 44: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/44.jpg)
Handling Signals
Ignore them – except KILL && STOP Catch with trap('IO'){} Let the default action apply SIGVTALRM is reserved for threading Signals the process every 10ms Flags that it's time to schedule Green threading maps to 1 OS thread, 1
per process, signals scoped per process
![Page 45: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/45.jpg)
Processes
Process groups Leader ? Process#pid == process group identifier Group persist when leader exists as long as there's
some members
![Page 46: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/46.jpg)
Multi-process Quality of Service
Signals to enforce QOS URG: Slow down CONT: Resume normal operation XCPU: Crawl
Monitoring agent sends URG during load spike
Sends CONT when load drops XCPU during extremely high load,
effectively pausing the worker(s)
![Page 47: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/47.jpg)
POSIX Realtime Extensions
Well supported, but implementations differ Linux Kernel 2.6 FreeBSD / Darwin Solaris
Kernel level asynchronous IO Supports thread, signal based or no-op
callbacks Reduces syscall overheads in IO bound
applications
![Page 48: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/48.jpg)
How it works
Control block Struct: fd, buffer, notification, offset, number of bytes
aio_read( '/tmp/file' ) # signal notification with SIGIO
Returns right away, faster than O_NONBLOCK
Kernel signals with SIGIO on completion Handler notification contains pointer to the the original
control block
![Page 49: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/49.jpg)
Why it matters
Parallel execution of aio_read && aio_write lio_listio( LIO_WRITE, list_of_cbs, 90, &list_sig )
A single user to kernel space switch 90 operations, a single signal notification Experimental rb_aio extension AIO.write( { :filename => 'buffer' } )
![Page 50: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/50.jpg)
Project Darkstarhttp://www.projectdarkstar.com
![Page 51: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/51.jpg)
Gaming @ a Rails conf ?
Rails Rack compatibility Middleware + ESI SOA architecture with thin processes +
layers Russian doll pattern
![Page 52: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/52.jpg)
Architecture Overview
Communications Pubsub && direct channels suported
Execution Kernel Stateless execution of tasks
Data storage Transactional storage of serialized objects
![Page 53: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/53.jpg)
Task Execution
Spawned and managed by a task manager Appears monothreaded, executes in parallel Immediate, delayed or periodic Parent <=> child relationships Guaranteed to execute in order Children inherits priority of parent
![Page 54: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/54.jpg)
Task Lifetime
Max execution time is 100ms - configurable Split long running tasks into multiple
smaller tasks
![Page 55: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/55.jpg)
Managed Objects && References
Managed object == a persitable entity References
Encapsulates all interactions with the data store
Retrieval strategies Get with the intention of modifying state Get for read Object#mark_for_update to promote a read only
instance
![Page 56: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/56.jpg)
Listeners
Application listener Initialize: setup any game play items when first booted Login callback: setup per player game state
Client listener Defines methods to repond to client events eg. logout
![Page 57: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/57.jpg)
Testing
![Page 58: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/58.jpg)
Test strategies
Define environments : test / production Ability to switch between an evented and
batched programming model depending on the environment
A desirable side effect of loose coupling Very well suited for integration testing
![Page 59: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/59.jpg)
Block in testing mode
Inject correlation middleware when in the test environment
extend BlockInTest A single event may spawn *data
@broker.collateral_report( 'ACCXXXX' ) => [#<Report:0x202948>, #<Report:0x202234>]
A single event may spawn many others @broker.collateral_report( 'ACCXXXX' )
=> [:acknowledge_reports, :reports]
![Page 60: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/60.jpg)
Event => expectation
Mapping Event X to Reaction *Y : Event IDXXXXXXX => { IDXXXXXXX => [Y,Y,Y] }
Mapping Event X to Data Elements *Z : Event IDXXXXXXX => { IDXXXXXXX => [Z,Z,Z] }
Backbone of integration tests
![Page 61: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/61.jpg)
Existing specs ?
github.com/tmm1/em-spec Bacon and Rspec backends A reactor / event loop for context How ?
Context executes in a Fiber, each expectation yields
Unobtrusive describe 'This is a context' Em.spec 'This is an evented context
![Page 62: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/62.jpg)
Questions ?
![Page 63: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/63.jpg)
Slides + Codehttp://github.com/methodmissing/ra
ilswaycon_events
![Page 64: Embracing Events](https://reader033.vdocument.in/reader033/viewer/2022060109/5555a810d8b42afe5d8b45f2/html5/thumbnails/64.jpg)
Thanks! Fork away.Follow
@methodmissing on Twitter