Slide 1

Slide 1 text

Ruby Theater The Actor model for Concurrent Applications Friday, March 22, 13

Slide 2

Slide 2 text

starring MARCOS MATOS @ marcosccm Friday, March 22, 13

Slide 3

Slide 3 text

developer at THOUGHTWORKS Friday, March 22, 13

Slide 4

Slide 4 text

Concurrency Friday, March 22, 13

Slide 5

Slide 5 text

Doing multiple things simultaneously Friday, March 22, 13

Slide 6

Slide 6 text

concurrency parallelism Friday, March 22, 13

Slide 7

Slide 7 text

How do you deal with it? Friday, March 22, 13

Slide 8

Slide 8 text

“My app is super concurrent! I use Unicorn!” (or Thin, Rainbows, Puma, Passenger...) Friday, March 22, 13

Slide 9

Slide 9 text

To most rubyists, concurrency stops at the choosing of an application server Friday, March 22, 13

Slide 10

Slide 10 text

That mindset can lead to slow or unscalable apps Friday, March 22, 13

Slide 11

Slide 11 text

Whatever, I can just spin more Dynos Friday, March 22, 13

Slide 12

Slide 12 text

Why we are still treating concurrency as a secondary concern? Friday, March 22, 13

Slide 13

Slide 13 text

Concurrency remembers us of Threads Friday, March 22, 13

Slide 14

Slide 14 text

No sane person likes Threads Friday, March 22, 13

Slide 15

Slide 15 text

Racing Conditions! Deadlocks! Starvation! Friday, March 22, 13

Slide 16

Slide 16 text

mutex = Mutex.new cv = ConditionVariable.new a = Thread.new { mutex.synchronize { sleep 200 cv.wait(mutex) sleep 100 } } b = Thread.new { mutex.synchronize { sleep 200 cv.signal sleep 200 } } a.join; b.join Friday, March 22, 13

Slide 17

Slide 17 text

Threads are evil incarnate! Friday, March 22, 13

Slide 18

Slide 18 text

But merely starting a Thread you not leave you in a deadlock hell Friday, March 22, 13

Slide 19

Slide 19 text

things start to break when you have... Friday, March 22, 13

Slide 20

Slide 20 text

Mutable Shared State Friday, March 22, 13

Slide 21

Slide 21 text

Mutable shared state is the root of all evil (together with money, premature optimizations, and semicolons) Friday, March 22, 13

Slide 22

Slide 22 text

We can deal with concurrency issues by controlling mutability Friday, March 22, 13

Slide 23

Slide 23 text

There are many techniques for that Friday, March 22, 13

Slide 24

Slide 24 text

STM Atomic Operations Pure Functions Channels Friday, March 22, 13

Slide 25

Slide 25 text

and also... Friday, March 22, 13

Slide 26

Slide 26 text

Actors Friday, March 22, 13

Slide 27

Slide 27 text

Think of concurrent Objects Friday, March 22, 13

Slide 28

Slide 28 text

All communication is done with async immutable messages Friday, March 22, 13

Slide 29

Slide 29 text

No shared state! Friday, March 22, 13

Slide 30

Slide 30 text

Actor Actor Actor Text message State message message Friday, March 22, 13

Slide 31

Slide 31 text

messages async Actor mailbox mutable state Friday, March 22, 13

Slide 32

Slide 32 text

Each actor acts as a single threaded program, but they exist concurrently Friday, March 22, 13

Slide 33

Slide 33 text

Actors and OO, a long story... Friday, March 22, 13

Slide 34

Slide 34 text

1973 - Actors 1972 - SmallTalk Friday, March 22, 13

Slide 35

Slide 35 text

“OOP means only messaging, local retention and protection and hiding of state processing” Alan Kay Friday, March 22, 13

Slide 36

Slide 36 text

“Actors means only messaging, local retention and protection and hiding of state processing” Me Friday, March 22, 13

Slide 37

Slide 37 text

Actors OO before anyone heard of that! Friday, March 22, 13

Slide 38

Slide 38 text

Popular in functional languages, like Erlang and Scala Friday, March 22, 13

Slide 39

Slide 39 text

what about Ruby? Friday, March 22, 13

Slide 40

Slide 40 text

Ruby has a somewhat shaky relationship with concurrency Friday, March 22, 13

Slide 41

Slide 41 text

“Ruby does not scale! Parallelism is impossible! NodeJS is so much faster” The Internet Friday, March 22, 13

Slide 42

Slide 42 text

Well, not really! It’s complicated Friday, March 22, 13

Slide 43

Slide 43 text

Recent emphasis on concurrency, specially by alternative implementations Friday, March 22, 13

Slide 44

Slide 44 text

many different Actors implementations for Ruby Friday, March 22, 13

Slide 45

Slide 45 text

Celluloid Actors.rb Girl-Friday Friday, March 22, 13

Slide 46

Slide 46 text

Celluloid Friday, March 22, 13

Slide 47

Slide 47 text

Concurrency + Object Orientation Friday, March 22, 13

Slide 48

Slide 48 text

class MyActor include Celluloid def hard_work sleep 100 “job done!” end end Friday, March 22, 13

Slide 49

Slide 49 text

“Wait a sec! It’s just a normal looking class!” Friday, March 22, 13

Slide 50

Slide 50 text

Give me my Mailbox! Friday, March 22, 13

Slide 51

Slide 51 text

The secret is the use of Proxies and Futures Friday, March 22, 13

Slide 52

Slide 52 text

Normal Call actor = MyActor.new => # # new gets you a proxy object actor.hard_work (100s later...) => “job done!” # that answers normally to method # calls Friday, March 22, 13

Slide 53

Slide 53 text

Normal Call another Proxy mailbox Actor mailbox Friday, March 22, 13

Slide 54

Slide 54 text

actor.async.hard_work (instantaneous) => nil # Proxy fires the message immediately # and returns nil Async Call Friday, March 22, 13

Slide 55

Slide 55 text

Async Call another Proxy mailbox Actor mailbox Nil Friday, March 22, 13

Slide 56

Slide 56 text

future = actor.future.hard_work (instantaneous) => # # Proxy returns a future object future.value (blocking call) => “job done!” # only blocks when value is called Calls with Future Friday, March 22, 13

Slide 57

Slide 57 text

Calls with Future another Actor mailbox Proxy Future Friday, March 22, 13

Slide 58

Slide 58 text

Everything is underlined by Ruby Fibers and Threads Friday, March 22, 13

Slide 59

Slide 59 text

What if an actor fails? Friday, March 22, 13

Slide 60

Slide 60 text

Fault tolerance model inspired by Erlang Friday, March 22, 13

Slide 61

Slide 61 text

Turn it off and on again! Friday, March 22, 13

Slide 62

Slide 62 text

Linking Supervisor Supervisor Groups Friday, March 22, 13

Slide 63

Slide 63 text

class Worker include Celluloid def initialize(website) @website = website end def work Net::HTTP.get(@website) end end Working with Supervisors Friday, March 22, 13

Slide 64

Slide 64 text

Worker.supervise_as :wk, ‘www.google.com’ =># # returns a supervisor and also boots the # actor worker = Celluloid::Actors[:wk] worker.work # supervisor takes care of restarting # actor in case of exceptions Working with Supervisors Friday, March 22, 13

Slide 65

Slide 65 text

Very cool this Actor thing, but does it makes any difference? Friday, March 22, 13

Slide 66

Slide 66 text

The Sidekiq Case “we replaced 12-15 EC2 medium instances running 4 delayed_job processes each with a single EC2 medium instance running 4 sidekiq workers with 25 concurrency each. The final tally is something like $2500 less per month in EC2 costs.” Friday, March 22, 13

Slide 67

Slide 67 text

concluding Friday, March 22, 13

Slide 68

Slide 68 text

Concurrency is hard Friday, March 22, 13

Slide 69

Slide 69 text

but ignoring it won’t make it go away Friday, March 22, 13

Slide 70

Slide 70 text

There are many available models and solutions Friday, March 22, 13

Slide 71

Slide 71 text

Ruby is lagging behind on that front Friday, March 22, 13

Slide 72

Slide 72 text

Look out of the Box! Friday, March 22, 13

Slide 73

Slide 73 text

The End Friday, March 22, 13