SlideShare a Scribd company logo
1 of 132
Download to read offline
Lin Jen-Shin (godfat) @ Rubyconf.tw/2012
Concurrent
Ruby
Application Servers
Concurrent
Ruby
Application Servers
Lin Jen-Shin (godfat) @ Rubyconf.tw/2012
http://godfat.org/slide/
2012-12-07-concurrent.pdf
http://godfat.org/slide/
2012-12-07-concurrent.pdf
Concurrency?Concurrency?
What We Have?What We Have?
App Servers?App Servers?
Me?
Q?
Concurrency?Concurrency?
What We Have?What We Have?
App Servers?App Servers?
Me?
Q?
Lin Jen-Shin (godfat) @ Rubyconf.tw/2012
•	Programmer at Cardinal Blue•	Programmer at Cardinal Blue
Lin Jen-Shin (godfat) @ Rubyconf.tw/2012
•	Programmer at Cardinal Blue
•	Use Ruby from 2006
•	Programmer at Cardinal Blue
•	Use Ruby from 2006
Lin Jen-Shin (godfat) @ Rubyconf.tw/2012
•	Programmer at Cardinal Blue
•	Use Ruby from 2006
•	Interested in PL and FP (e.g. Haskell)
•	Programmer at Cardinal Blue
•	Use Ruby from 2006
•	Interested in PL and FP (e.g. Haskell)
Lin Jen-Shin (godfat) @ Rubyconf.tw/2012
•	Programmer at Cardinal Blue
•	Use Ruby from 2006
•	Interested in PL and FP (e.g. Haskell)
•	Programmer at Cardinal Blue
•	Use Ruby from 2006
•	Interested in PL and FP (e.g. Haskell)Also concurrency recently
Lin Jen-Shin (godfat) @ Rubyconf.tw/2012
•	Programmer at Cardinal Blue
•	Use Ruby from 2006
•	Interested in PL and FP (e.g. Haskell)
•	https://github.com/godfat
•	Programmer at Cardinal Blue
•	Use Ruby from 2006
•	Interested in PL and FP (e.g. Haskell)
•	https://github.com/godfat
Also concurrency recently
Lin Jen-Shin (godfat) @ Rubyconf.tw/2012
•	Programmer at Cardinal Blue
•	Use Ruby from 2006
•	Interested in PL and FP (e.g. Haskell)
•	https://github.com/godfat
•	https://twitter.com/godfat
•	Programmer at Cardinal Blue
•	Use Ruby from 2006
•	Interested in PL and FP (e.g. Haskell)
•	https://github.com/godfat
•	https://twitter.com/godfat
Also concurrency recently
Lin Jen-Shin (godfat) @ Rubyconf.tw/2012
PicCollagePicCollage
Lin Jen-Shin (godfat) @ Rubyconf.tw/2012
in 7 daysin 7 days
•	~3.1k requests per minute
•	Average response time:
~135 ms
•	Average concurrent
requests per process: ~7
•	Total processes: 18
•	Above data observed from
NewRelic
•	App server: Zbatery with
EventMachine and thread
pool on Heroku Cedar
stack
•	~3.1k requests per minute
•	Average response time:
~135 ms
•	Average concurrent
requests per process: ~7
•	Total processes: 18
•	Above data observed from
NewRelic
•	App server: Zbatery with
EventMachine and thread
pool on Heroku Cedar
stack
PicCollagePicCollage
Lin Jen-Shin (godfat) @ Rubyconf.tw/2012
Recent GemsRecent Gems
•	jellyfish - Pico web
framework for building
API-centric web
applications
•	rib - Ruby-Interactive-
ruBy -- Yet another
interactive Ruby shell
•	rest-core - Modular Ruby
clients interface for REST
APIs
•	rest-more - Various REST
clients such as Facebook
and Twitter built with
rest-core
•	jellyfish - Pico web
framework for building
API-centric web
applications
•	rib - Ruby-Interactive-
ruBy -- Yet another
interactive Ruby shell
•	rest-core - Modular Ruby
clients interface for REST
APIs
•	rest-more - Various REST
clients such as Facebook
and Twitter built with
rest-core
Lin Jen-Shin (godfat) @ Rubyconf.tw/2012
Special ThanksSpecial Thanks
ihower, ET Blue and Cardinal Blueihower, ET Blue and Cardinal Blue
Concurrency?Concurrency?
What We Have?What We Have?
App Servers?App Servers?
Me?
Q?
CaveatsCaveats No disk I/O
No pipelined requests
No chunked encoding
No web sockets
No …
To make things simpler for now.
No disk I/O
No pipelined requests
No chunked encoding
No web sockets
No …
To make things simpler for now.
It's not faster for a userIt's not faster for a userCautionCaution
10 moms can't produce
1 child in 1 month
10 moms can't produce
1 child in 1 month
10 moms can produce
10 children in 10 months
10 moms can produce
10 children in 10 months
Resource mattersResource matters
We might not always have
enough processors
We might not always have
enough processors
Resource mattersResource matters
We might not always have
enough processors
We might not always have
enough processors
Resource mattersResource matters
We need multitaskingWe need multitasking
Imagine 15 children
have to be context switched
amongst 10 moms
Imagine 15 children
have to be context switched
amongst 10 moms
Multitasking is not freeMultitasking is not free
If your program context switches,
then actually it runs slower
If your program context switches,
then actually it runs slower
Multitasking is not freeMultitasking is not free
If your program context switches,
then actually it runs slower
If your program context switches,
then actually it runs slower
Multitasking is not freeMultitasking is not free
But it's more fair for usersBut it's more fair for users
It's more fair if they are all served
equally in terms of waiting time
It's more fair if they are all served
equally in terms of waiting time
I just want a drink!I just want a drink!
#04
#03
#02
#01
#00
#05
Waiting
Processing
Context Switching
Sequential
Time
User ID
To illustrateTo illustrate the overall running time...the overall running time...
#04
#03
#02
#01
#00
#05
Waiting
Processing
Context Switching
Concurrent
Time
User ID
#04
#03
#02
#01
#00
#05
Waiting
Processing
Context Switching
Sequential
Time
User ID
#04
#03
#02
#01
#00
#05
Waiting
Processing
Context Switching
ConcurrentTotal Waiting and
Processing
Time
Time
User ID
#04
#03
#02
#01
#00
#05
Waiting
Processing
Context Switching
SequentialTotal Waiting and
Processing
Time
Time
User ID
Scalable != FastScalable != Fast
Scalable == Less complainingScalable == Less complaining
Rails is not fastRails is not fast
Rails might be scalableRails might be scalable
Scalable != FastScalable != Fast
Scalable == Less complainingScalable == Less complaining
So,So,
When do we want
concurrency?
When do we want
concurrency?
So,So,
When do we want
concurrency?
When do we want
concurrency?
When context switching cost is
much cheaper than a single task
When context switching cost is
much cheaper than a single task
So,So,
When do we want
concurrency?
When do we want
concurrency?
When context switching cost is
much cheaper than a single task
When context switching cost is
much cheaper than a single task
Or if you have much more cores than your
clients (= no need for context switching)
Or if you have much more cores than your
clients (= no need for context switching)
If context switching cost is at about 1 secondIf context switching cost is at about 1 second
If context switching cost is at about 1 second
It's much cheaper than 10 months, so it
might be worth it
If context switching cost is at about 1 second
It's much cheaper than 10 months, so it
might be worth it
#04
#03
#02
#01
#00
#05
#04
#03
#02
#01
#00
#05
Time
User ID
Time
User ID
But if context switching cost is at about
5 months...
But if context switching cost is at about
5 months...
Do kernel threads context switch fast?Do kernel threads context switch fast?
Do kernel threads context switch fast?Do kernel threads context switch fast?
Do user threads context switch fast?Do user threads context switch fast?
Do kernel threads context switch fast?Do kernel threads context switch fast?
Do user threads context switch fast?Do user threads context switch fast?
Do fibers context switch fast?Do fibers context switch fast?
A ton of different concurrency models
then invented
A ton of different concurrency models
then invented
A ton of different concurrency models
then invented
A ton of different concurrency models
then invented
Each of them has different strengths to
deal with different tasks
Each of them has different strengths to
deal with different tasks
A ton of different concurrency models
then invented
A ton of different concurrency models
then invented
Each of them has different strengths to
deal with different tasks
Each of them has different strengths to
deal with different tasks
Also trade off, trading with the ease of
programming and efficiency
Also trade off, trading with the ease of
programming and efficiency
So,So,
How many different types
of tasks are there?
How many different types
of tasks are there?
Two patternsTwo patterns
Linear data dependencyLinear data dependency
of composite tasksof composite tasks
go to resturant
order food order drink
eat drink
order_food -> eat
order_tea -> drink
order_food -> eat
order_tea -> drink
go to resturant
order food order drink
eat drink
go to resturant
order food order spices
mix
eat
Two patternsTwo patterns
Linear data dependencyLinear data dependency Mixed data dependencyMixed data dependency
of composite tasksof composite tasks
order_food -> eat
order_tea -> drink
order_food -> eat
order_tea -> drink
[order_food, order_spices]
-> add_spices -> eat
[order_food, order_spices]
-> add_spices -> eat
prepare to share a photo
to facebook to flickr
save save
prepare to merge photos
from facebook from flickr
merge
save
prepare to share a photo
to facebook to flickr
save save
prepare to merge photos
from facebook from flickr
merge
save
Linear data dependencyLinear data dependency Mixed data dependencyMixed data dependency
prepare to share a photo
to facebook to flickr
save save
prepare to share a photo
to facebook to flickr
save save
CPU
CPU CPU
I/O I/O
CPU IOCPU IOOne single task could be or boundOne single task could be or bound
Linear data dependencyLinear data dependency Mixed data dependencyMixed data dependency
prepare to share a photo
to facebook to flickr
save save
prepare to merge photos
from facebook from flickr
merge
save
prepare to share a photo
to facebook to flickr
save save
prepare to merge photos
from facebook from flickr
merge
save
CPU
CPU CPU
I/O I/O
CPU
CPU
CPU
I/O I/O
CPU IOCPU IOOne single task could be or boundOne single task could be or bound
Linear data dependencyLinear data dependency Mixed data dependencyMixed data dependency
Concurrency?Concurrency?
What We Have?What We Have?
App Servers?App Servers?
Me?
Q?
•	Performance•	Performance
Separation of Concerns
•	Performance
•	Ease of programming
•	Performance
•	Ease of programming
Separation of Concerns
•	Performance (implementation)
•	Ease of programming (interface)
•	Performance (implementation)
•	Ease of programming (interface)
Separation of Concerns
Advantages if interface is
orthogonal to its implementation
•	Change implementation with ease•	Change implementation with ease
•	Change implementation with ease
•	Don't need to know impl detail in
order to use this interface
•	Change implementation with ease
•	Don't need to know impl detail in
order to use this interface
Advantages if interface is
orthogonal to its implementation
interfaceinterface implementationimplementation
blocking threads
callback reactor fibers
CPU
I/O callback reactor
blocking threads
fibers
CPU
I/O
interfaceinterface implementationimplementation
Interface for
Linear data dependency
Interface for
Linear data dependency
blocking threads
callback reactor fibers
CPU
I/O
order_food{ |food|
eat(food)
}
order_tea{ |tea|
drink(tea)
}
order_food{ |food|
eat(food)
}
order_tea{ |tea|
drink(tea)
}
CallbackCallback
callback reactor
blocking threads
fibers
CPU
I/O
blocking threads
callback reactor fibers
CPU
I/O
eat(order_food)
drink(order_tea)
eat(order_food)
drink(order_tea)
If we could control side-effect
and do some static analysis...
If we could control side-effect
and do some static analysis...
callback reactor
blocking threads
fibers
CPU
I/O
blocking threads
callback reactor fibers
CPU
I/O
Not going to happen on Ruby though
Not going to happen on Ruby though
callback reactor
blocking threads
fibers
CPU
I/O
eat(order_food)
drink(order_tea)
eat(order_food)
drink(order_tea)
If we could control side-effect
and do some static analysis...
If we could control side-effect
and do some static analysis...
Interface for
Mixed data dependency
Interface for
Mixed data dependency
If callback is the only thing we have...If callback is the only thing we have...
blocking threads
callback reactor fibers
CPU
I/O callback reactor
blocking threads
fibers
CPU
I/O
# order_food is blocking order_spices
order_food{ |food|
order_spices{ |spices|
eat(add_spices(spices, food))
}
}
# order_food is blocking order_spices
order_food{ |food|
order_spices{ |spices|
eat(add_spices(spices, food))
}
}
We don't want to do this
blocking threads
callback reactor fibers
CPU
I/O callback reactor
blocking threads
fibers
CPU
I/O
food, spices = nil
order_food{ |arrived_food|
food = arrived_food
start_eating(food, spices) if food && spices
}
order_spices{ |arrived_spices|
spices = arrived_spices
start_eating(food, spices) if food && spices
}
##
def start_eating food, spices
superfood = add_spices(spices, food)
eat(superfood)
end
food, spices = nil
order_food{ |arrived_food|
food = arrived_food
start_eating(food, spices) if food && spices
}
order_spices{ |arrived_spices|
spices = arrived_spices
start_eating(food, spices) if food && spices
}
##
def start_eating food, spices
superfood = add_spices(spices, food)
eat(superfood)
end
Tedious, but performs betterTedious, but performs better
blocking threads
callback reactor fibers
CPU
I/O callback reactor
blocking threads
fibers
CPU
I/O
food = order_food
spices = order_spices
superfood = add_spices(spices, food)
eat(superfood)
# or one liner
eat(add_spices(order_spices, order_food))
food = order_food
spices = order_spices
superfood = add_spices(spices, food)
eat(superfood)
# or one liner
eat(add_spices(order_spices, order_food))
Ideally, we could do this with futuresIdeally, we could do this with futures
but how?
ImplementationImplementation
Forget about
data dependency for now
Forget about
data dependency for now
ImplementationImplementation
blocking threads
callback reactor fibers
CPU
I/O callback reactor
blocking threads
fibers
CPU
I/O
Implementation: 2 main choicesImplementation: 2 main choices
blocking threads
callback reactor fibers
CPU
I/O callback reactor
blocking threads
fibers
CPU
I/O
def order_food
Thread.new{
food = order_food_blocking
yield(food)
}
end
def order_food
Thread.new{
food = order_food_blocking
yield(food)
}
end
with a thread
with a thread
If order_food is I/O boundIf order_food is I/O bound
blocking threads
callback reactor fibers
CPU
I/O callback reactor
blocking threads
fibers
CPU
I/O
def order_food
make_request('order_food'){ |food|
yield(food)
}
end
def order_food
make_request('order_food'){ |food|
yield(food)
}
end
with a reactor
with a reactor
If order_food is I/O boundIf order_food is I/O bound
blocking threads
callback reactor fibers
CPU
I/O callback reactor
blocking threads
fibers
CPU
I/O
def order_food
buf = []
reactor = Thread.current[:reactor]
sock = TCPSocket.new('example.
com', 80)
request = "GET / HTTP/1.0rnrn"
reactor.write sock, request do
reactor.read sock do |response|
if response
buf << response
else
yield(buf.join)
ennnnd
def order_food
buf = []
reactor = Thread.current[:reactor]
sock = TCPSocket.new('example.
com', 80)
request = "GET / HTTP/1.0rnrn"
reactor.write sock, request do
reactor.read sock do |response|
if response
buf << response
else
yield(buf.join)
ennnnd
with a very simple reactor
with a very simple reactor
If order_food is I/O boundIf order_food is I/O bound
https://github.com/godfat/ruby-server-exp/blob/
master/sample/reactor.rb
blocking threads
callback reactor fibers
CPU
I/O callback reactor
blocking threads
fibers
CPU
I/O
If order_food is CPU boundIf order_food is CPU bound
def order_food
Thread.new{
food = order_food_blocking
yield(food)
}
end
def order_food
Thread.new{
food = order_food_blocking
yield(food)
}
end
with a thread
with a thread
blocking threads
callback reactor fibers
CPU
I/O callback reactor
blocking threads
fibers
CPU
I/O
def order_food
Thread.new{
food = order_food_blocking
yield(food)
}
end
def order_food
Thread.new{
food = order_food_blocking
yield(food)
}
end
with a thread
with a thread
If order_food is I/O boundIf order_food is I/O bound
You don't have to care whether it's
CPU bound or
I/O bound with a thread
You don't have to care whether it's
CPU bound or
I/O bound with a thread
And you won't want to process a
CPU bound task inside a reactor
blocking other clients.
And you won't want to process a
CPU bound task inside a reactor
blocking other clients.
blocking threads
callback reactor fibers
CPU
I/O callback reactor
blocking threads
fibers
CPU
I/O
SummarySummary
•	Threads for CPU bound task
•	Reactor for I/O bound task
Back to mixed data dependencyBack to mixed data dependency
blocking threads
callback reactor fibers
CPU
I/O callback reactor
blocking threads
fibers
CPU
I/O
If we could have some other interface
than callbacks
If we could have some other interface
than callbacks
blocking threads
callback reactor fibers
CPU
I/O callback reactor
blocking threads
fibers
CPU
I/O
ThreadsThreads
food, spices = nil
t0 = Thread.new{ food = order_food }
t1 = Thread.new{ spices = order_spices }
t0.join
t1.join
superfood = add_spices(spices, food)
eat(superfood)
food, spices = nil
t0 = Thread.new{ food = order_food }
t1 = Thread.new{ spices = order_spices }
t0.join
t1.join
superfood = add_spices(spices, food)
eat(superfood)
We can do it with threads easily
We can do it with threads easily
blocking threads
callback reactor fibers
CPU
I/O callback reactor
blocking threads
fibers
CPU
I/O
what if we still want callbacks, since then
we can pick either threads or reactors as
the implementation detail?
what if we still want callbacks, since then
we can pick either threads or reactors as
the implementation detail?
blocking threads
callback reactor fibers
CPU
I/O callback reactor
blocking threads
fibers
CPU
I/O
food, spices = nil
order_food{ |arrived_food|
food = arrived_food
start_eating(food, spices) if food && spices
}
order_spices{ |arrived_spices|
spices = arrived_spices
start_eating(food, spices) if food && spices
}
##
def start_eating food, spices
superfood = add_spices(spices, food)
eat(superfood)
end
food, spices = nil
order_food{ |arrived_food|
food = arrived_food
start_eating(food, spices) if food && spices
}
order_spices{ |arrived_spices|
spices = arrived_spices
start_eating(food, spices) if food && spices
}
##
def start_eating food, spices
superfood = add_spices(spices, food)
eat(superfood)
end
we could use threads
or fibers to remove
the need for defining
another callback (i.e.
start_eating)
we could use threads
or fibers to remove
the need for defining
another callback (i.e.
start_eating)
instead of writing this...
instead of writing this...
blocking threads
callback reactor fibers
CPU
I/O callback reactor
blocking threads
fibers
CPU
I/O
food, spices = nil
order_food{ |arrived_food|
food = arrived_food
start_eating(food, spices) if food && spices
}
order_spices{ |arrived_spices|
spices = arrived_spices
start_eating(food, spices) if food && spices
}
##
def start_eating food, spices
superfood = add_spices(spices, food)
eat(superfood)
end
food, spices = nil
order_food{ |arrived_food|
food = arrived_food
start_eating(food, spices) if food && spices
}
order_spices{ |arrived_spices|
spices = arrived_spices
start_eating(food, spices) if food && spices
}
##
def start_eating food, spices
superfood = add_spices(spices, food)
eat(superfood)
end
blocking threads
callback reactor fibers
CPU
I/O callback reactor
blocking threads
fibers
CPU
I/O
condv = ConditionVariable.new
mutex = Mutex.new
food, spices = nil
order_food{ |arrived_food|
food = arrived_food
condv.signal if food && spices
}
order_spices{ |arrived_spices|
spices = arrived_spices
condv.signal if food && spices
}
##
mutex.synchronize{ condv.wait(mutex) }
superfood = add_spices(spices, food)
eat(superfood)
condv = ConditionVariable.new
mutex = Mutex.new
food, spices = nil
order_food{ |arrived_food|
food = arrived_food
condv.signal if food && spices
}
order_spices{ |arrived_spices|
spices = arrived_spices
condv.signal if food && spices
}
##
mutex.synchronize{ condv.wait(mutex) }
superfood = add_spices(spices, food)
eat(superfood)
Turn threads callback back to synchronized likeTurn threads callback back to synchronized likeThreadsThreads
blocking threads
callback reactor fibers
CPU
I/O callback reactor
blocking threads
fibers
CPU
I/O
Turn reactor callback to synchronized styleTurn reactor callback to synchronized styleFibersFibers
fiber = Fiber.current
food, spices = nil
order_food{ |arrived_food|
food = arrived_food
fiber.resume if food && spices
}
order_spices{ |arrived_spices|
spices = arrived_spices
fiber.resume if food && spices
}
##
Fiber.yield
superfood = add_spices(spices, food)
eat(superfood)
fiber = Fiber.current
food, spices = nil
order_food{ |arrived_food|
food = arrived_food
fiber.resume if food && spices
}
order_spices{ |arrived_spices|
spices = arrived_spices
fiber.resume if food && spices
}
##
Fiber.yield
superfood = add_spices(spices, food)
eat(superfood)
Threads vs FibersThreads vs Fibers
threads if your request is wrapped
inside a thread (e.g. thread pool
strategy)
threads if your request is wrapped
inside a thread (e.g. thread pool
strategy)
fibers if your request is wrapped
inside a fiber (e.g. reactor + fibers)
fibers if your request is wrapped
inside a fiber (e.g. reactor + fibers)
we're using eventmachine + thread
pool with thread synchronization
we're using eventmachine + thread
pool with thread synchronization
we used to run fibers, but it didn't
work well with other libraries
we used to run fibers, but it didn't
work well with other libraries
e.g. activerecord's connection pool didn't respect
fibers, only threads
e.g. activerecord's connection pool didn't respect
fibers, only threads
also, using fibers we're running a
risk where we might block the event
loop somehow we don't know
also, using fibers we're running a
risk where we might block the event
loop somehow we don't know
so using threads is easier if you
consider thread-safety is easier
than fiber-safety + potential risk of
blocking the reactor
so using threads is easier if you
consider thread-safety is easier
than fiber-safety + potential risk of
blocking the reactor
and we can even go one step
further...
and we can even go one step
further...
...into the futures!...into the futures!
this is also a demonstration that some
interfaces are only available to some
implementations
this is also a demonstration that some
interfaces are only available to some
implementations
food = order_food
spices = order_spices
superfood = add_spices(spices, food)
eat(superfood)
# or one liner
eat(add_spices(order_spices, order_food))
food = order_food
spices = order_spices
superfood = add_spices(spices, food)
eat(superfood)
# or one liner
eat(add_spices(order_spices, order_food))
Who got futures?Who got futures?
•	rest-core for HTTP futures
•	celluloid for general futures
•	also check celluloid-io for replacing
eventmachine
•	rest-core for HTTP futures
•	celluloid for general futures
•	also check celluloid-io for replacing
eventmachine
a more complex (real world)
example
a more complex (real world)
example
•	update friend list from facebook
•	get photo list from facebook
•	download 3 photos from the list
•	detect the dimension of the 3 photos
•	merge above photos
•	upload to facebook
•	update friend list from facebook
•	get photo list from facebook
•	download 3 photos from the list
•	detect the dimension of the 3 photos
•	merge above photos
•	upload to facebook
this example shows a mix model of
linear and mixed data dependencythis example shows a mix model of
linear and mixed data dependency
Concurrency?Concurrency?
What We Have?What We Have?
App Servers?App Servers?
Me?
Q?
Again:
we don't talk about chunked
encoding and web sockets or so for
now; simply plain old HTTP 1.0
Again:
we don't talk about chunked
encoding and web sockets or so for
now; simply plain old HTTP 1.0
Network
concurrency
Network
concurrency
Application
concurrency
Application
concurrency
sockets I/O bound tasks would be
ideal for an event loop to process
them efficiently
sockets I/O bound tasks would be
ideal for an event loop to process
them efficiently
however, CPU bound tasks should
be handled in real hardware core
however, CPU bound tasks should
be handled in real hardware core
nginx, eventmachine,
libev, nodejs, etc.
nginx, eventmachine,
libev, nodejs, etc.
e.g. kernel process/thread
e.g. kernel process/thread
we can abstract the http
server (reverse proxy)
easily, since it only needs
to do one thing and do it
well (unix philosophy)
we can abstract the http
server (reverse proxy)
easily, since it only needs
to do one thing and do it
well (unix philosophy)
that is, using an event loop
to buffer the requeststhat is, using an event loop
to buffer the requests
however, different application does
different things, one strategy might
work well for one application but
not the other
however, different application does
different things, one strategy might
work well for one application but
not the other
we could have an universal
concurrency model which could do
averagely good, but not perfect for
say, *your* application
we could have an universal
concurrency model which could do
averagely good, but not perfect for
say, *your* application
that is why Rainbows provides all
possible concurrency models for you
to choose from
that is why Rainbows provides all
possible concurrency models for you
to choose from
what if we want to make external
requests to outside world?
what if we want to make external
requests to outside world?
it's I/O bound, and could be the most significant
bottleneck, much slower than your favorite
database
it's I/O bound, and could be the most significant
bottleneck, much slower than your favorite
database
e.g. facebooke.g. facebook
before we jump into the detail...before we jump into the detail...
let's see some concurrent popular ruby
application servers
let's see some concurrent popular ruby
application servers
Thin, Puma, Unicorn familyThin, Puma, Unicorn family
Default ThinDefault Thin
eventmachine (event loop)
for buffering requests
eventmachine (event loop)
for buffering requests
no application concurrencyno application concurrency
you can run thin cluster for
application concurrencyyou can run thin cluster for
application concurrency
Threaded ThinThreaded Thin
eventmachine (event loop)
for buffering requests
eventmachine (event loop)
for buffering requests
thread pool to serve
requests
thread pool to serve
requests
you can of course run
cluster for this
you can of course run
cluster for this
PumaPuma
zbatery + ThreadPool
= puma
zbatery + ThreadPool
= puma
UnicornUnicorn
no network concurrencyno network concurrency
worker process
application concurrency
worker process
application concurrency
RainbowsRainbows
another concurrency model
+ unicorn
another concurrency model
+ unicorn
ZbateryZbatery
rainbows with single
unicorn (no fork)
rainbows with single
unicorn (no fork)
saving memories
saving memories
Zbatery +
EventMachine
= default Thin
Zbatery +
EventMachine
= default Thin
Rainbows +
EventMachine
= cluster default
Thin
Rainbows +
EventMachine
= cluster default
Thin
Zbatery +
EventMachine +
TryDefer
(thread pool)
= threaded Thin
Zbatery +
EventMachine +
TryDefer
(thread pool)
= threaded Thin
Each model has its strength to
deal with different task
Each model has its strength to
deal with different task
blocking threads
callback reactor fibers
CPU
I/O callback reactor
blocking threads
fibers
CPU
I/O
Remember? threads for cpu operations,
reactor for I/O operations
Remember? threads for cpu operations,
reactor for I/O operations
What if we want to resize images,
encode videos?
What if we want to resize images,
encode videos?
it's of course CPU bound, and should be
handled in a real core/CPUit's of course CPU bound, and should be
handled in a real core/CPU
What if we want to do both? what
if we first request facebook, and
then encode video, or vice versa?
What if we want to do both? what
if we first request facebook, and
then encode video, or vice versa?
or we need to request facebook and encode
videos and request facebook again?or we need to request facebook and encode
videos and request facebook again?
The reactor could be used for http
concurrency and also making
external requests
The reactor could be used for http
concurrency and also making
external requests
Ultimate solutionUltimate solution
for what i can think of right nowfor what i can think of right now
USE EVERYTHINGUSE EVERYTHING
Rainbows +
EventMachine +
Thread pool +
Futures!
Rainbows +
EventMachine +
Thread pool +
Futures!
And how do we do that in a web application?
We'll need to do the above example in a
concurrent way. i.e.
And how do we do that in a web application?
We'll need to do the above example in a
concurrent way. i.e.
To compare all the
application servers above
To compare all the
application servers above
Thin (default)
Thin (threaded)
Puma
Unicorn
Rainbows
Zbatery
Passenger
Goliath
EventMachine
EventMachine
Thread pool
Worker processes
Worker processes + depends on configurations
Depends on configurations
I/O threads
libev
EventMachine
N/A
Thread pool
Thread pool
Worker processes
Process pool
Process/thread pool
N/A
Rack
Rack
Rack
Rack
Rack
Rack
Rack
Wrapped
Rack
Network Interface Application
Concurrency?Concurrency?
What We Have?What We Have?
App Servers?App Servers?
Me?
Q?

More Related Content

What's hot

Ruby On Google App Engine 2nd Athens Ruby Me
Ruby On Google App Engine 2nd Athens Ruby MeRuby On Google App Engine 2nd Athens Ruby Me
Ruby On Google App Engine 2nd Athens Ruby MePanagiotis Papadopoulos
 
ruby + websocket + haproxy
ruby + websocket + haproxyruby + websocket + haproxy
ruby + websocket + haproxyMathieu Elie
 
Building MapAttack
Building MapAttackBuilding MapAttack
Building MapAttackKyle Drake
 
One Container, Two Container, Three Containers, Four
One Container, Two Container, Three Containers, FourOne Container, Two Container, Three Containers, Four
One Container, Two Container, Three Containers, FourAshley Roach
 
I can haz HTTP - Consuming and producing HTTP APIs in the Ruby ecosystem
I can haz HTTP - Consuming and producing HTTP APIs in the Ruby ecosystemI can haz HTTP - Consuming and producing HTTP APIs in the Ruby ecosystem
I can haz HTTP - Consuming and producing HTTP APIs in the Ruby ecosystemSidu Ponnappa
 
Distributed Queue System using Gearman
Distributed Queue System using GearmanDistributed Queue System using Gearman
Distributed Queue System using GearmanEric Cho
 
Faster PHP apps using Queues and Workers
Faster PHP apps using Queues and WorkersFaster PHP apps using Queues and Workers
Faster PHP apps using Queues and WorkersRichard Baker
 
Introduction to Python Asyncio
Introduction to Python AsyncioIntroduction to Python Asyncio
Introduction to Python AsyncioNathan Van Gheem
 
Why I Love TorqueBox (And Why You Will Too)
Why I Love TorqueBox (And Why You Will Too)Why I Love TorqueBox (And Why You Will Too)
Why I Love TorqueBox (And Why You Will Too)benbrowning
 
Gearman - Job Queue
Gearman - Job QueueGearman - Job Queue
Gearman - Job QueueDiego Lewin
 
Leave end-to-end testing to Capybara
Leave end-to-end testing to CapybaraLeave end-to-end testing to Capybara
Leave end-to-end testing to CapybaraHiroshi SHIBATA
 
Node.js - Advanced Basics
Node.js - Advanced BasicsNode.js - Advanced Basics
Node.js - Advanced BasicsDoug Jones
 
Contribute to rails
Contribute to railsContribute to rails
Contribute to railsmartinsvalin
 
Guillotina: The Asyncio REST Resource API
Guillotina: The Asyncio REST Resource APIGuillotina: The Asyncio REST Resource API
Guillotina: The Asyncio REST Resource APINathan Van Gheem
 
Asynchronous Python A Gentle Introduction
Asynchronous Python A Gentle IntroductionAsynchronous Python A Gentle Introduction
Asynchronous Python A Gentle IntroductionPyData
 
Jruby a Pi and a database
Jruby a Pi and a databaseJruby a Pi and a database
Jruby a Pi and a databasePhilipp Fehre
 
RabbitMQ with python and ruby RuPy 2009
RabbitMQ with python and ruby RuPy 2009RabbitMQ with python and ruby RuPy 2009
RabbitMQ with python and ruby RuPy 2009Paolo Negri
 

What's hot (19)

Ruby On Google App Engine 2nd Athens Ruby Me
Ruby On Google App Engine 2nd Athens Ruby MeRuby On Google App Engine 2nd Athens Ruby Me
Ruby On Google App Engine 2nd Athens Ruby Me
 
From 'Legacy' to 'Edge'
From 'Legacy' to 'Edge'From 'Legacy' to 'Edge'
From 'Legacy' to 'Edge'
 
ruby + websocket + haproxy
ruby + websocket + haproxyruby + websocket + haproxy
ruby + websocket + haproxy
 
Building MapAttack
Building MapAttackBuilding MapAttack
Building MapAttack
 
One Container, Two Container, Three Containers, Four
One Container, Two Container, Three Containers, FourOne Container, Two Container, Three Containers, Four
One Container, Two Container, Three Containers, Four
 
I can haz HTTP - Consuming and producing HTTP APIs in the Ruby ecosystem
I can haz HTTP - Consuming and producing HTTP APIs in the Ruby ecosystemI can haz HTTP - Consuming and producing HTTP APIs in the Ruby ecosystem
I can haz HTTP - Consuming and producing HTTP APIs in the Ruby ecosystem
 
Queue your work
Queue your workQueue your work
Queue your work
 
Distributed Queue System using Gearman
Distributed Queue System using GearmanDistributed Queue System using Gearman
Distributed Queue System using Gearman
 
Faster PHP apps using Queues and Workers
Faster PHP apps using Queues and WorkersFaster PHP apps using Queues and Workers
Faster PHP apps using Queues and Workers
 
Introduction to Python Asyncio
Introduction to Python AsyncioIntroduction to Python Asyncio
Introduction to Python Asyncio
 
Why I Love TorqueBox (And Why You Will Too)
Why I Love TorqueBox (And Why You Will Too)Why I Love TorqueBox (And Why You Will Too)
Why I Love TorqueBox (And Why You Will Too)
 
Gearman - Job Queue
Gearman - Job QueueGearman - Job Queue
Gearman - Job Queue
 
Leave end-to-end testing to Capybara
Leave end-to-end testing to CapybaraLeave end-to-end testing to Capybara
Leave end-to-end testing to Capybara
 
Node.js - Advanced Basics
Node.js - Advanced BasicsNode.js - Advanced Basics
Node.js - Advanced Basics
 
Contribute to rails
Contribute to railsContribute to rails
Contribute to rails
 
Guillotina: The Asyncio REST Resource API
Guillotina: The Asyncio REST Resource APIGuillotina: The Asyncio REST Resource API
Guillotina: The Asyncio REST Resource API
 
Asynchronous Python A Gentle Introduction
Asynchronous Python A Gentle IntroductionAsynchronous Python A Gentle Introduction
Asynchronous Python A Gentle Introduction
 
Jruby a Pi and a database
Jruby a Pi and a databaseJruby a Pi and a database
Jruby a Pi and a database
 
RabbitMQ with python and ruby RuPy 2009
RabbitMQ with python and ruby RuPy 2009RabbitMQ with python and ruby RuPy 2009
RabbitMQ with python and ruby RuPy 2009
 

Similar to Concurrent Ruby Application Servers

Test driven infrastructure development (2 - puppetconf 2013 edition)
Test driven infrastructure development (2 - puppetconf 2013 edition)Test driven infrastructure development (2 - puppetconf 2013 edition)
Test driven infrastructure development (2 - puppetconf 2013 edition)Tomas Doran
 
GGX 2014 Lari Hotari Modular Monoliths with Spring Boot and Grails 3
GGX 2014 Lari Hotari Modular Monoliths with Spring Boot and Grails 3GGX 2014 Lari Hotari Modular Monoliths with Spring Boot and Grails 3
GGX 2014 Lari Hotari Modular Monoliths with Spring Boot and Grails 3Lari Hotari
 
The Ember.js Framework - Everything You Need To Know
The Ember.js Framework - Everything You Need To KnowThe Ember.js Framework - Everything You Need To Know
The Ember.js Framework - Everything You Need To KnowAll Things Open
 
JUC Europe 2015: Continuous Integration and Distribution in the Cloud with DE...
JUC Europe 2015: Continuous Integration and Distribution in the Cloud with DE...JUC Europe 2015: Continuous Integration and Distribution in the Cloud with DE...
JUC Europe 2015: Continuous Integration and Distribution in the Cloud with DE...CloudBees
 
Microservices, Events, and Breaking the Data Monolith with Kafka
Microservices, Events, and Breaking the Data Monolith with KafkaMicroservices, Events, and Breaking the Data Monolith with Kafka
Microservices, Events, and Breaking the Data Monolith with KafkaVMware Tanzu
 
Free The Enterprise With Ruby & Master Your Own Domain
Free The Enterprise With Ruby & Master Your Own DomainFree The Enterprise With Ruby & Master Your Own Domain
Free The Enterprise With Ruby & Master Your Own DomainKen Collins
 
Phoenix for Rubyists
Phoenix for RubyistsPhoenix for Rubyists
Phoenix for RubyistsDoug Goldie
 
Games for the Masses (Jax)
Games for the Masses (Jax)Games for the Masses (Jax)
Games for the Masses (Jax)Wooga
 
Cloud Foundry - An Open Innovation Platform
Cloud Foundry - An Open Innovation PlatformCloud Foundry - An Open Innovation Platform
Cloud Foundry - An Open Innovation PlatformAll Things Open
 
Better and Faster: A Journey Toward Clean Code and Enjoyment
Better and Faster: A Journey Toward Clean Code and EnjoymentBetter and Faster: A Journey Toward Clean Code and Enjoyment
Better and Faster: A Journey Toward Clean Code and EnjoymentChris Holland
 
Operations for databases – The DevOps journey
Operations for databases – The DevOps journey Operations for databases – The DevOps journey
Operations for databases – The DevOps journey Eduardo Piairo
 
Software that eats the world! - PerformDay Brussels
Software that eats the world! - PerformDay BrusselsSoftware that eats the world! - PerformDay Brussels
Software that eats the world! - PerformDay BrusselsKlaus Enzenhofer
 
Oracle WebLogic Server 12.2.1 Do More with Less
Oracle WebLogic Server 12.2.1 Do More with LessOracle WebLogic Server 12.2.1 Do More with Less
Oracle WebLogic Server 12.2.1 Do More with LessEd Burns
 
JavaOne 2014 BOF4241 What's Next for JSF?
JavaOne 2014 BOF4241 What's Next for JSF?JavaOne 2014 BOF4241 What's Next for JSF?
JavaOne 2014 BOF4241 What's Next for JSF?Edward Burns
 
Deployment is the new build
Deployment is the new buildDeployment is the new build
Deployment is the new buildAndrew Phillips
 
Notes (2012-06-08)
Notes (2012-06-08)Notes (2012-06-08)
Notes (2012-06-08)Chris Pitt
 
Evoloution of Ideas
Evoloution of IdeasEvoloution of Ideas
Evoloution of IdeasWooga
 
Your Goat Antifragiled My Snowflake!: Demystifying DevOps Jargon - ChefConf 2015
Your Goat Antifragiled My Snowflake!: Demystifying DevOps Jargon - ChefConf 2015Your Goat Antifragiled My Snowflake!: Demystifying DevOps Jargon - ChefConf 2015
Your Goat Antifragiled My Snowflake!: Demystifying DevOps Jargon - ChefConf 2015Chef
 
Subverting the monolith!
Subverting the monolith!Subverting the monolith!
Subverting the monolith!Sophia Russell
 

Similar to Concurrent Ruby Application Servers (20)

Test driven infrastructure development (2 - puppetconf 2013 edition)
Test driven infrastructure development (2 - puppetconf 2013 edition)Test driven infrastructure development (2 - puppetconf 2013 edition)
Test driven infrastructure development (2 - puppetconf 2013 edition)
 
GGX 2014 Lari Hotari Modular Monoliths with Spring Boot and Grails 3
GGX 2014 Lari Hotari Modular Monoliths with Spring Boot and Grails 3GGX 2014 Lari Hotari Modular Monoliths with Spring Boot and Grails 3
GGX 2014 Lari Hotari Modular Monoliths with Spring Boot and Grails 3
 
The Ember.js Framework - Everything You Need To Know
The Ember.js Framework - Everything You Need To KnowThe Ember.js Framework - Everything You Need To Know
The Ember.js Framework - Everything You Need To Know
 
JUC Europe 2015: Continuous Integration and Distribution in the Cloud with DE...
JUC Europe 2015: Continuous Integration and Distribution in the Cloud with DE...JUC Europe 2015: Continuous Integration and Distribution in the Cloud with DE...
JUC Europe 2015: Continuous Integration and Distribution in the Cloud with DE...
 
Microservices, Events, and Breaking the Data Monolith with Kafka
Microservices, Events, and Breaking the Data Monolith with KafkaMicroservices, Events, and Breaking the Data Monolith with Kafka
Microservices, Events, and Breaking the Data Monolith with Kafka
 
Free The Enterprise With Ruby & Master Your Own Domain
Free The Enterprise With Ruby & Master Your Own DomainFree The Enterprise With Ruby & Master Your Own Domain
Free The Enterprise With Ruby & Master Your Own Domain
 
Phoenix for Rubyists
Phoenix for RubyistsPhoenix for Rubyists
Phoenix for Rubyists
 
Games for the Masses (Jax)
Games for the Masses (Jax)Games for the Masses (Jax)
Games for the Masses (Jax)
 
Cloud Foundry - An Open Innovation Platform
Cloud Foundry - An Open Innovation PlatformCloud Foundry - An Open Innovation Platform
Cloud Foundry - An Open Innovation Platform
 
Better and Faster: A Journey Toward Clean Code and Enjoyment
Better and Faster: A Journey Toward Clean Code and EnjoymentBetter and Faster: A Journey Toward Clean Code and Enjoyment
Better and Faster: A Journey Toward Clean Code and Enjoyment
 
Operations for databases – The DevOps journey
Operations for databases – The DevOps journey Operations for databases – The DevOps journey
Operations for databases – The DevOps journey
 
Software that eats the world! - PerformDay Brussels
Software that eats the world! - PerformDay BrusselsSoftware that eats the world! - PerformDay Brussels
Software that eats the world! - PerformDay Brussels
 
Oracle WebLogic Server 12.2.1 Do More with Less
Oracle WebLogic Server 12.2.1 Do More with LessOracle WebLogic Server 12.2.1 Do More with Less
Oracle WebLogic Server 12.2.1 Do More with Less
 
JavaOne 2014 BOF4241 What's Next for JSF?
JavaOne 2014 BOF4241 What's Next for JSF?JavaOne 2014 BOF4241 What's Next for JSF?
JavaOne 2014 BOF4241 What's Next for JSF?
 
Deployment is the new build
Deployment is the new buildDeployment is the new build
Deployment is the new build
 
Notes (2012-06-08)
Notes (2012-06-08)Notes (2012-06-08)
Notes (2012-06-08)
 
Evoloution of Ideas
Evoloution of IdeasEvoloution of Ideas
Evoloution of Ideas
 
Your Goat Antifragiled My Snowflake!: Demystifying DevOps Jargon - ChefConf 2015
Your Goat Antifragiled My Snowflake!: Demystifying DevOps Jargon - ChefConf 2015Your Goat Antifragiled My Snowflake!: Demystifying DevOps Jargon - ChefConf 2015
Your Goat Antifragiled My Snowflake!: Demystifying DevOps Jargon - ChefConf 2015
 
Pinto+Stratopan+Love
Pinto+Stratopan+LovePinto+Stratopan+Love
Pinto+Stratopan+Love
 
Subverting the monolith!
Subverting the monolith!Subverting the monolith!
Subverting the monolith!
 

More from Lin Jen-Shin

Server Development Workflow For PicCollage
Server Development Workflow For PicCollageServer Development Workflow For PicCollage
Server Development Workflow For PicCollageLin Jen-Shin
 
The Architecture of PicCollage Server
The Architecture of PicCollage ServerThe Architecture of PicCollage Server
The Architecture of PicCollage ServerLin Jen-Shin
 
2012 05-08-lambda-draft
2012 05-08-lambda-draft2012 05-08-lambda-draft
2012 05-08-lambda-draftLin Jen-Shin
 
2010 04-24-cerealize
2010 04-24-cerealize2010 04-24-cerealize
2010 04-24-cerealizeLin Jen-Shin
 
2008-12-21 Rubinius
2008-12-21 Rubinius2008-12-21 Rubinius
2008-12-21 RubiniusLin Jen-Shin
 
2010-04-13 Reactor Pattern & Event Driven Programming 2
2010-04-13 Reactor Pattern & Event Driven Programming 22010-04-13 Reactor Pattern & Event Driven Programming 2
2010-04-13 Reactor Pattern & Event Driven Programming 2Lin Jen-Shin
 
2010-02-09 Reactor Pattern & Event Driven Programming
2010-02-09 Reactor Pattern & Event Driven Programming2010-02-09 Reactor Pattern & Event Driven Programming
2010-02-09 Reactor Pattern & Event Driven ProgrammingLin Jen-Shin
 
2008-01-25 Tangible Value
2008-01-25 Tangible Value2008-01-25 Tangible Value
2008-01-25 Tangible ValueLin Jen-Shin
 
2007-06-24 The Lost Piece
2007-06-24 The Lost Piece2007-06-24 The Lost Piece
2007-06-24 The Lost PieceLin Jen-Shin
 

More from Lin Jen-Shin (9)

Server Development Workflow For PicCollage
Server Development Workflow For PicCollageServer Development Workflow For PicCollage
Server Development Workflow For PicCollage
 
The Architecture of PicCollage Server
The Architecture of PicCollage ServerThe Architecture of PicCollage Server
The Architecture of PicCollage Server
 
2012 05-08-lambda-draft
2012 05-08-lambda-draft2012 05-08-lambda-draft
2012 05-08-lambda-draft
 
2010 04-24-cerealize
2010 04-24-cerealize2010 04-24-cerealize
2010 04-24-cerealize
 
2008-12-21 Rubinius
2008-12-21 Rubinius2008-12-21 Rubinius
2008-12-21 Rubinius
 
2010-04-13 Reactor Pattern & Event Driven Programming 2
2010-04-13 Reactor Pattern & Event Driven Programming 22010-04-13 Reactor Pattern & Event Driven Programming 2
2010-04-13 Reactor Pattern & Event Driven Programming 2
 
2010-02-09 Reactor Pattern & Event Driven Programming
2010-02-09 Reactor Pattern & Event Driven Programming2010-02-09 Reactor Pattern & Event Driven Programming
2010-02-09 Reactor Pattern & Event Driven Programming
 
2008-01-25 Tangible Value
2008-01-25 Tangible Value2008-01-25 Tangible Value
2008-01-25 Tangible Value
 
2007-06-24 The Lost Piece
2007-06-24 The Lost Piece2007-06-24 The Lost Piece
2007-06-24 The Lost Piece
 

Recently uploaded

Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 

Recently uploaded (20)

Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 

Concurrent Ruby Application Servers

  • 1. Lin Jen-Shin (godfat) @ Rubyconf.tw/2012 Concurrent Ruby Application Servers Concurrent Ruby Application Servers
  • 2. Lin Jen-Shin (godfat) @ Rubyconf.tw/2012 http://godfat.org/slide/ 2012-12-07-concurrent.pdf http://godfat.org/slide/ 2012-12-07-concurrent.pdf
  • 3. Concurrency?Concurrency? What We Have?What We Have? App Servers?App Servers? Me? Q?
  • 4. Concurrency?Concurrency? What We Have?What We Have? App Servers?App Servers? Me? Q?
  • 5. Lin Jen-Shin (godfat) @ Rubyconf.tw/2012 • Programmer at Cardinal Blue• Programmer at Cardinal Blue
  • 6. Lin Jen-Shin (godfat) @ Rubyconf.tw/2012 • Programmer at Cardinal Blue • Use Ruby from 2006 • Programmer at Cardinal Blue • Use Ruby from 2006
  • 7. Lin Jen-Shin (godfat) @ Rubyconf.tw/2012 • Programmer at Cardinal Blue • Use Ruby from 2006 • Interested in PL and FP (e.g. Haskell) • Programmer at Cardinal Blue • Use Ruby from 2006 • Interested in PL and FP (e.g. Haskell)
  • 8. Lin Jen-Shin (godfat) @ Rubyconf.tw/2012 • Programmer at Cardinal Blue • Use Ruby from 2006 • Interested in PL and FP (e.g. Haskell) • Programmer at Cardinal Blue • Use Ruby from 2006 • Interested in PL and FP (e.g. Haskell)Also concurrency recently
  • 9. Lin Jen-Shin (godfat) @ Rubyconf.tw/2012 • Programmer at Cardinal Blue • Use Ruby from 2006 • Interested in PL and FP (e.g. Haskell) • https://github.com/godfat • Programmer at Cardinal Blue • Use Ruby from 2006 • Interested in PL and FP (e.g. Haskell) • https://github.com/godfat Also concurrency recently
  • 10. Lin Jen-Shin (godfat) @ Rubyconf.tw/2012 • Programmer at Cardinal Blue • Use Ruby from 2006 • Interested in PL and FP (e.g. Haskell) • https://github.com/godfat • https://twitter.com/godfat • Programmer at Cardinal Blue • Use Ruby from 2006 • Interested in PL and FP (e.g. Haskell) • https://github.com/godfat • https://twitter.com/godfat Also concurrency recently
  • 11. Lin Jen-Shin (godfat) @ Rubyconf.tw/2012 PicCollagePicCollage
  • 12. Lin Jen-Shin (godfat) @ Rubyconf.tw/2012 in 7 daysin 7 days • ~3.1k requests per minute • Average response time: ~135 ms • Average concurrent requests per process: ~7 • Total processes: 18 • Above data observed from NewRelic • App server: Zbatery with EventMachine and thread pool on Heroku Cedar stack • ~3.1k requests per minute • Average response time: ~135 ms • Average concurrent requests per process: ~7 • Total processes: 18 • Above data observed from NewRelic • App server: Zbatery with EventMachine and thread pool on Heroku Cedar stack PicCollagePicCollage
  • 13. Lin Jen-Shin (godfat) @ Rubyconf.tw/2012 Recent GemsRecent Gems • jellyfish - Pico web framework for building API-centric web applications • rib - Ruby-Interactive- ruBy -- Yet another interactive Ruby shell • rest-core - Modular Ruby clients interface for REST APIs • rest-more - Various REST clients such as Facebook and Twitter built with rest-core • jellyfish - Pico web framework for building API-centric web applications • rib - Ruby-Interactive- ruBy -- Yet another interactive Ruby shell • rest-core - Modular Ruby clients interface for REST APIs • rest-more - Various REST clients such as Facebook and Twitter built with rest-core
  • 14. Lin Jen-Shin (godfat) @ Rubyconf.tw/2012 Special ThanksSpecial Thanks ihower, ET Blue and Cardinal Blueihower, ET Blue and Cardinal Blue
  • 15. Concurrency?Concurrency? What We Have?What We Have? App Servers?App Servers? Me? Q?
  • 16. CaveatsCaveats No disk I/O No pipelined requests No chunked encoding No web sockets No … To make things simpler for now. No disk I/O No pipelined requests No chunked encoding No web sockets No … To make things simpler for now.
  • 17. It's not faster for a userIt's not faster for a userCautionCaution
  • 18. 10 moms can't produce 1 child in 1 month 10 moms can't produce 1 child in 1 month
  • 19. 10 moms can produce 10 children in 10 months 10 moms can produce 10 children in 10 months
  • 21. We might not always have enough processors We might not always have enough processors Resource mattersResource matters
  • 22. We might not always have enough processors We might not always have enough processors Resource mattersResource matters We need multitaskingWe need multitasking
  • 23. Imagine 15 children have to be context switched amongst 10 moms Imagine 15 children have to be context switched amongst 10 moms
  • 24. Multitasking is not freeMultitasking is not free
  • 25. If your program context switches, then actually it runs slower If your program context switches, then actually it runs slower Multitasking is not freeMultitasking is not free
  • 26. If your program context switches, then actually it runs slower If your program context switches, then actually it runs slower Multitasking is not freeMultitasking is not free But it's more fair for usersBut it's more fair for users
  • 27.
  • 28. It's more fair if they are all served equally in terms of waiting time It's more fair if they are all served equally in terms of waiting time
  • 29.
  • 30. I just want a drink!I just want a drink!
  • 31. #04 #03 #02 #01 #00 #05 Waiting Processing Context Switching Sequential Time User ID To illustrateTo illustrate the overall running time...the overall running time...
  • 33. #04 #03 #02 #01 #00 #05 Waiting Processing Context Switching ConcurrentTotal Waiting and Processing Time Time User ID #04 #03 #02 #01 #00 #05 Waiting Processing Context Switching SequentialTotal Waiting and Processing Time Time User ID
  • 34. Scalable != FastScalable != Fast Scalable == Less complainingScalable == Less complaining
  • 35. Rails is not fastRails is not fast Rails might be scalableRails might be scalable Scalable != FastScalable != Fast Scalable == Less complainingScalable == Less complaining
  • 36. So,So, When do we want concurrency? When do we want concurrency?
  • 37. So,So, When do we want concurrency? When do we want concurrency? When context switching cost is much cheaper than a single task When context switching cost is much cheaper than a single task
  • 38. So,So, When do we want concurrency? When do we want concurrency? When context switching cost is much cheaper than a single task When context switching cost is much cheaper than a single task Or if you have much more cores than your clients (= no need for context switching) Or if you have much more cores than your clients (= no need for context switching)
  • 39. If context switching cost is at about 1 secondIf context switching cost is at about 1 second
  • 40. If context switching cost is at about 1 second It's much cheaper than 10 months, so it might be worth it If context switching cost is at about 1 second It's much cheaper than 10 months, so it might be worth it
  • 41. #04 #03 #02 #01 #00 #05 #04 #03 #02 #01 #00 #05 Time User ID Time User ID But if context switching cost is at about 5 months... But if context switching cost is at about 5 months...
  • 42. Do kernel threads context switch fast?Do kernel threads context switch fast?
  • 43. Do kernel threads context switch fast?Do kernel threads context switch fast? Do user threads context switch fast?Do user threads context switch fast?
  • 44. Do kernel threads context switch fast?Do kernel threads context switch fast? Do user threads context switch fast?Do user threads context switch fast? Do fibers context switch fast?Do fibers context switch fast?
  • 45. A ton of different concurrency models then invented A ton of different concurrency models then invented
  • 46. A ton of different concurrency models then invented A ton of different concurrency models then invented Each of them has different strengths to deal with different tasks Each of them has different strengths to deal with different tasks
  • 47. A ton of different concurrency models then invented A ton of different concurrency models then invented Each of them has different strengths to deal with different tasks Each of them has different strengths to deal with different tasks Also trade off, trading with the ease of programming and efficiency Also trade off, trading with the ease of programming and efficiency
  • 48. So,So, How many different types of tasks are there? How many different types of tasks are there?
  • 49. Two patternsTwo patterns Linear data dependencyLinear data dependency of composite tasksof composite tasks go to resturant order food order drink eat drink order_food -> eat order_tea -> drink order_food -> eat order_tea -> drink
  • 50. go to resturant order food order drink eat drink go to resturant order food order spices mix eat Two patternsTwo patterns Linear data dependencyLinear data dependency Mixed data dependencyMixed data dependency of composite tasksof composite tasks order_food -> eat order_tea -> drink order_food -> eat order_tea -> drink [order_food, order_spices] -> add_spices -> eat [order_food, order_spices] -> add_spices -> eat
  • 51. prepare to share a photo to facebook to flickr save save prepare to merge photos from facebook from flickr merge save prepare to share a photo to facebook to flickr save save prepare to merge photos from facebook from flickr merge save Linear data dependencyLinear data dependency Mixed data dependencyMixed data dependency
  • 52. prepare to share a photo to facebook to flickr save save prepare to share a photo to facebook to flickr save save CPU CPU CPU I/O I/O CPU IOCPU IOOne single task could be or boundOne single task could be or bound Linear data dependencyLinear data dependency Mixed data dependencyMixed data dependency
  • 53. prepare to share a photo to facebook to flickr save save prepare to merge photos from facebook from flickr merge save prepare to share a photo to facebook to flickr save save prepare to merge photos from facebook from flickr merge save CPU CPU CPU I/O I/O CPU CPU CPU I/O I/O CPU IOCPU IOOne single task could be or boundOne single task could be or bound Linear data dependencyLinear data dependency Mixed data dependencyMixed data dependency
  • 54. Concurrency?Concurrency? What We Have?What We Have? App Servers?App Servers? Me? Q?
  • 57. • Performance (implementation) • Ease of programming (interface) • Performance (implementation) • Ease of programming (interface) Separation of Concerns
  • 58. Advantages if interface is orthogonal to its implementation • Change implementation with ease• Change implementation with ease
  • 59. • Change implementation with ease • Don't need to know impl detail in order to use this interface • Change implementation with ease • Don't need to know impl detail in order to use this interface Advantages if interface is orthogonal to its implementation
  • 61. blocking threads callback reactor fibers CPU I/O callback reactor blocking threads fibers CPU I/O interfaceinterface implementationimplementation
  • 62. Interface for Linear data dependency Interface for Linear data dependency
  • 63. blocking threads callback reactor fibers CPU I/O order_food{ |food| eat(food) } order_tea{ |tea| drink(tea) } order_food{ |food| eat(food) } order_tea{ |tea| drink(tea) } CallbackCallback callback reactor blocking threads fibers CPU I/O
  • 64. blocking threads callback reactor fibers CPU I/O eat(order_food) drink(order_tea) eat(order_food) drink(order_tea) If we could control side-effect and do some static analysis... If we could control side-effect and do some static analysis... callback reactor blocking threads fibers CPU I/O
  • 65. blocking threads callback reactor fibers CPU I/O Not going to happen on Ruby though Not going to happen on Ruby though callback reactor blocking threads fibers CPU I/O eat(order_food) drink(order_tea) eat(order_food) drink(order_tea) If we could control side-effect and do some static analysis... If we could control side-effect and do some static analysis...
  • 66. Interface for Mixed data dependency Interface for Mixed data dependency
  • 67. If callback is the only thing we have...If callback is the only thing we have...
  • 68. blocking threads callback reactor fibers CPU I/O callback reactor blocking threads fibers CPU I/O # order_food is blocking order_spices order_food{ |food| order_spices{ |spices| eat(add_spices(spices, food)) } } # order_food is blocking order_spices order_food{ |food| order_spices{ |spices| eat(add_spices(spices, food)) } } We don't want to do this
  • 69. blocking threads callback reactor fibers CPU I/O callback reactor blocking threads fibers CPU I/O food, spices = nil order_food{ |arrived_food| food = arrived_food start_eating(food, spices) if food && spices } order_spices{ |arrived_spices| spices = arrived_spices start_eating(food, spices) if food && spices } ## def start_eating food, spices superfood = add_spices(spices, food) eat(superfood) end food, spices = nil order_food{ |arrived_food| food = arrived_food start_eating(food, spices) if food && spices } order_spices{ |arrived_spices| spices = arrived_spices start_eating(food, spices) if food && spices } ## def start_eating food, spices superfood = add_spices(spices, food) eat(superfood) end Tedious, but performs betterTedious, but performs better
  • 70. blocking threads callback reactor fibers CPU I/O callback reactor blocking threads fibers CPU I/O food = order_food spices = order_spices superfood = add_spices(spices, food) eat(superfood) # or one liner eat(add_spices(order_spices, order_food)) food = order_food spices = order_spices superfood = add_spices(spices, food) eat(superfood) # or one liner eat(add_spices(order_spices, order_food)) Ideally, we could do this with futuresIdeally, we could do this with futures
  • 73. Forget about data dependency for now Forget about data dependency for now ImplementationImplementation
  • 74. blocking threads callback reactor fibers CPU I/O callback reactor blocking threads fibers CPU I/O Implementation: 2 main choicesImplementation: 2 main choices
  • 75. blocking threads callback reactor fibers CPU I/O callback reactor blocking threads fibers CPU I/O def order_food Thread.new{ food = order_food_blocking yield(food) } end def order_food Thread.new{ food = order_food_blocking yield(food) } end with a thread with a thread If order_food is I/O boundIf order_food is I/O bound
  • 76. blocking threads callback reactor fibers CPU I/O callback reactor blocking threads fibers CPU I/O def order_food make_request('order_food'){ |food| yield(food) } end def order_food make_request('order_food'){ |food| yield(food) } end with a reactor with a reactor If order_food is I/O boundIf order_food is I/O bound
  • 77. blocking threads callback reactor fibers CPU I/O callback reactor blocking threads fibers CPU I/O def order_food buf = [] reactor = Thread.current[:reactor] sock = TCPSocket.new('example. com', 80) request = "GET / HTTP/1.0rnrn" reactor.write sock, request do reactor.read sock do |response| if response buf << response else yield(buf.join) ennnnd def order_food buf = [] reactor = Thread.current[:reactor] sock = TCPSocket.new('example. com', 80) request = "GET / HTTP/1.0rnrn" reactor.write sock, request do reactor.read sock do |response| if response buf << response else yield(buf.join) ennnnd with a very simple reactor with a very simple reactor If order_food is I/O boundIf order_food is I/O bound https://github.com/godfat/ruby-server-exp/blob/ master/sample/reactor.rb
  • 78. blocking threads callback reactor fibers CPU I/O callback reactor blocking threads fibers CPU I/O If order_food is CPU boundIf order_food is CPU bound def order_food Thread.new{ food = order_food_blocking yield(food) } end def order_food Thread.new{ food = order_food_blocking yield(food) } end with a thread with a thread
  • 79. blocking threads callback reactor fibers CPU I/O callback reactor blocking threads fibers CPU I/O def order_food Thread.new{ food = order_food_blocking yield(food) } end def order_food Thread.new{ food = order_food_blocking yield(food) } end with a thread with a thread If order_food is I/O boundIf order_food is I/O bound
  • 80. You don't have to care whether it's CPU bound or I/O bound with a thread You don't have to care whether it's CPU bound or I/O bound with a thread
  • 81. And you won't want to process a CPU bound task inside a reactor blocking other clients. And you won't want to process a CPU bound task inside a reactor blocking other clients.
  • 82. blocking threads callback reactor fibers CPU I/O callback reactor blocking threads fibers CPU I/O SummarySummary • Threads for CPU bound task • Reactor for I/O bound task
  • 83. Back to mixed data dependencyBack to mixed data dependency blocking threads callback reactor fibers CPU I/O callback reactor blocking threads fibers CPU I/O
  • 84. If we could have some other interface than callbacks If we could have some other interface than callbacks
  • 85. blocking threads callback reactor fibers CPU I/O callback reactor blocking threads fibers CPU I/O ThreadsThreads food, spices = nil t0 = Thread.new{ food = order_food } t1 = Thread.new{ spices = order_spices } t0.join t1.join superfood = add_spices(spices, food) eat(superfood) food, spices = nil t0 = Thread.new{ food = order_food } t1 = Thread.new{ spices = order_spices } t0.join t1.join superfood = add_spices(spices, food) eat(superfood) We can do it with threads easily We can do it with threads easily
  • 86. blocking threads callback reactor fibers CPU I/O callback reactor blocking threads fibers CPU I/O what if we still want callbacks, since then we can pick either threads or reactors as the implementation detail? what if we still want callbacks, since then we can pick either threads or reactors as the implementation detail?
  • 87. blocking threads callback reactor fibers CPU I/O callback reactor blocking threads fibers CPU I/O food, spices = nil order_food{ |arrived_food| food = arrived_food start_eating(food, spices) if food && spices } order_spices{ |arrived_spices| spices = arrived_spices start_eating(food, spices) if food && spices } ## def start_eating food, spices superfood = add_spices(spices, food) eat(superfood) end food, spices = nil order_food{ |arrived_food| food = arrived_food start_eating(food, spices) if food && spices } order_spices{ |arrived_spices| spices = arrived_spices start_eating(food, spices) if food && spices } ## def start_eating food, spices superfood = add_spices(spices, food) eat(superfood) end we could use threads or fibers to remove the need for defining another callback (i.e. start_eating) we could use threads or fibers to remove the need for defining another callback (i.e. start_eating) instead of writing this... instead of writing this...
  • 88. blocking threads callback reactor fibers CPU I/O callback reactor blocking threads fibers CPU I/O food, spices = nil order_food{ |arrived_food| food = arrived_food start_eating(food, spices) if food && spices } order_spices{ |arrived_spices| spices = arrived_spices start_eating(food, spices) if food && spices } ## def start_eating food, spices superfood = add_spices(spices, food) eat(superfood) end food, spices = nil order_food{ |arrived_food| food = arrived_food start_eating(food, spices) if food && spices } order_spices{ |arrived_spices| spices = arrived_spices start_eating(food, spices) if food && spices } ## def start_eating food, spices superfood = add_spices(spices, food) eat(superfood) end
  • 89. blocking threads callback reactor fibers CPU I/O callback reactor blocking threads fibers CPU I/O condv = ConditionVariable.new mutex = Mutex.new food, spices = nil order_food{ |arrived_food| food = arrived_food condv.signal if food && spices } order_spices{ |arrived_spices| spices = arrived_spices condv.signal if food && spices } ## mutex.synchronize{ condv.wait(mutex) } superfood = add_spices(spices, food) eat(superfood) condv = ConditionVariable.new mutex = Mutex.new food, spices = nil order_food{ |arrived_food| food = arrived_food condv.signal if food && spices } order_spices{ |arrived_spices| spices = arrived_spices condv.signal if food && spices } ## mutex.synchronize{ condv.wait(mutex) } superfood = add_spices(spices, food) eat(superfood) Turn threads callback back to synchronized likeTurn threads callback back to synchronized likeThreadsThreads
  • 90. blocking threads callback reactor fibers CPU I/O callback reactor blocking threads fibers CPU I/O Turn reactor callback to synchronized styleTurn reactor callback to synchronized styleFibersFibers fiber = Fiber.current food, spices = nil order_food{ |arrived_food| food = arrived_food fiber.resume if food && spices } order_spices{ |arrived_spices| spices = arrived_spices fiber.resume if food && spices } ## Fiber.yield superfood = add_spices(spices, food) eat(superfood) fiber = Fiber.current food, spices = nil order_food{ |arrived_food| food = arrived_food fiber.resume if food && spices } order_spices{ |arrived_spices| spices = arrived_spices fiber.resume if food && spices } ## Fiber.yield superfood = add_spices(spices, food) eat(superfood)
  • 92. threads if your request is wrapped inside a thread (e.g. thread pool strategy) threads if your request is wrapped inside a thread (e.g. thread pool strategy) fibers if your request is wrapped inside a fiber (e.g. reactor + fibers) fibers if your request is wrapped inside a fiber (e.g. reactor + fibers)
  • 93. we're using eventmachine + thread pool with thread synchronization we're using eventmachine + thread pool with thread synchronization we used to run fibers, but it didn't work well with other libraries we used to run fibers, but it didn't work well with other libraries e.g. activerecord's connection pool didn't respect fibers, only threads e.g. activerecord's connection pool didn't respect fibers, only threads
  • 94. also, using fibers we're running a risk where we might block the event loop somehow we don't know also, using fibers we're running a risk where we might block the event loop somehow we don't know so using threads is easier if you consider thread-safety is easier than fiber-safety + potential risk of blocking the reactor so using threads is easier if you consider thread-safety is easier than fiber-safety + potential risk of blocking the reactor
  • 95. and we can even go one step further... and we can even go one step further...
  • 97. this is also a demonstration that some interfaces are only available to some implementations this is also a demonstration that some interfaces are only available to some implementations food = order_food spices = order_spices superfood = add_spices(spices, food) eat(superfood) # or one liner eat(add_spices(order_spices, order_food)) food = order_food spices = order_spices superfood = add_spices(spices, food) eat(superfood) # or one liner eat(add_spices(order_spices, order_food))
  • 98. Who got futures?Who got futures? • rest-core for HTTP futures • celluloid for general futures • also check celluloid-io for replacing eventmachine • rest-core for HTTP futures • celluloid for general futures • also check celluloid-io for replacing eventmachine
  • 99. a more complex (real world) example a more complex (real world) example • update friend list from facebook • get photo list from facebook • download 3 photos from the list • detect the dimension of the 3 photos • merge above photos • upload to facebook • update friend list from facebook • get photo list from facebook • download 3 photos from the list • detect the dimension of the 3 photos • merge above photos • upload to facebook this example shows a mix model of linear and mixed data dependencythis example shows a mix model of linear and mixed data dependency
  • 100.
  • 101. Concurrency?Concurrency? What We Have?What We Have? App Servers?App Servers? Me? Q?
  • 102. Again: we don't talk about chunked encoding and web sockets or so for now; simply plain old HTTP 1.0 Again: we don't talk about chunked encoding and web sockets or so for now; simply plain old HTTP 1.0
  • 104. sockets I/O bound tasks would be ideal for an event loop to process them efficiently sockets I/O bound tasks would be ideal for an event loop to process them efficiently however, CPU bound tasks should be handled in real hardware core however, CPU bound tasks should be handled in real hardware core nginx, eventmachine, libev, nodejs, etc. nginx, eventmachine, libev, nodejs, etc. e.g. kernel process/thread e.g. kernel process/thread
  • 105. we can abstract the http server (reverse proxy) easily, since it only needs to do one thing and do it well (unix philosophy) we can abstract the http server (reverse proxy) easily, since it only needs to do one thing and do it well (unix philosophy) that is, using an event loop to buffer the requeststhat is, using an event loop to buffer the requests
  • 106. however, different application does different things, one strategy might work well for one application but not the other however, different application does different things, one strategy might work well for one application but not the other
  • 107. we could have an universal concurrency model which could do averagely good, but not perfect for say, *your* application we could have an universal concurrency model which could do averagely good, but not perfect for say, *your* application
  • 108. that is why Rainbows provides all possible concurrency models for you to choose from that is why Rainbows provides all possible concurrency models for you to choose from
  • 109. what if we want to make external requests to outside world? what if we want to make external requests to outside world? it's I/O bound, and could be the most significant bottleneck, much slower than your favorite database it's I/O bound, and could be the most significant bottleneck, much slower than your favorite database e.g. facebooke.g. facebook
  • 110. before we jump into the detail...before we jump into the detail... let's see some concurrent popular ruby application servers let's see some concurrent popular ruby application servers
  • 111. Thin, Puma, Unicorn familyThin, Puma, Unicorn family
  • 112. Default ThinDefault Thin eventmachine (event loop) for buffering requests eventmachine (event loop) for buffering requests no application concurrencyno application concurrency you can run thin cluster for application concurrencyyou can run thin cluster for application concurrency
  • 113. Threaded ThinThreaded Thin eventmachine (event loop) for buffering requests eventmachine (event loop) for buffering requests thread pool to serve requests thread pool to serve requests you can of course run cluster for this you can of course run cluster for this
  • 114. PumaPuma zbatery + ThreadPool = puma zbatery + ThreadPool = puma
  • 115. UnicornUnicorn no network concurrencyno network concurrency worker process application concurrency worker process application concurrency
  • 116. RainbowsRainbows another concurrency model + unicorn another concurrency model + unicorn
  • 117. ZbateryZbatery rainbows with single unicorn (no fork) rainbows with single unicorn (no fork) saving memories saving memories
  • 118. Zbatery + EventMachine = default Thin Zbatery + EventMachine = default Thin
  • 119. Rainbows + EventMachine = cluster default Thin Rainbows + EventMachine = cluster default Thin
  • 120. Zbatery + EventMachine + TryDefer (thread pool) = threaded Thin Zbatery + EventMachine + TryDefer (thread pool) = threaded Thin
  • 121. Each model has its strength to deal with different task Each model has its strength to deal with different task
  • 122. blocking threads callback reactor fibers CPU I/O callback reactor blocking threads fibers CPU I/O Remember? threads for cpu operations, reactor for I/O operations Remember? threads for cpu operations, reactor for I/O operations
  • 123. What if we want to resize images, encode videos? What if we want to resize images, encode videos? it's of course CPU bound, and should be handled in a real core/CPUit's of course CPU bound, and should be handled in a real core/CPU
  • 124. What if we want to do both? what if we first request facebook, and then encode video, or vice versa? What if we want to do both? what if we first request facebook, and then encode video, or vice versa? or we need to request facebook and encode videos and request facebook again?or we need to request facebook and encode videos and request facebook again?
  • 125. The reactor could be used for http concurrency and also making external requests The reactor could be used for http concurrency and also making external requests
  • 126. Ultimate solutionUltimate solution for what i can think of right nowfor what i can think of right now
  • 128. Rainbows + EventMachine + Thread pool + Futures! Rainbows + EventMachine + Thread pool + Futures!
  • 129. And how do we do that in a web application? We'll need to do the above example in a concurrent way. i.e. And how do we do that in a web application? We'll need to do the above example in a concurrent way. i.e.
  • 130. To compare all the application servers above To compare all the application servers above
  • 131. Thin (default) Thin (threaded) Puma Unicorn Rainbows Zbatery Passenger Goliath EventMachine EventMachine Thread pool Worker processes Worker processes + depends on configurations Depends on configurations I/O threads libev EventMachine N/A Thread pool Thread pool Worker processes Process pool Process/thread pool N/A Rack Rack Rack Rack Rack Rack Rack Wrapped Rack Network Interface Application
  • 132. Concurrency?Concurrency? What We Have?What We Have? App Servers?App Servers? Me? Q?