$30 off During Our Annual Pro Sale. View Details »

Achieving zomgscale! With Celluloid & JRuby

Achieving zomgscale! With Celluloid & JRuby

Light up your cores! Learn how to achieve levels of scale hitherto unknown to mere mortals. This talk will cover concurrency and parallelisation for the discerning rubyist. We'll cover why MRI is keeping your CPUs way cooler than they find comfortable and how you can unlock unfound levels of roflscale by spending a little time with celluloid and JRuby.

This talk was given at EuRuKo 2013 in Athens, Greece.

Ben Lovell

June 29, 2013
Tweet

More Decks by Ben Lovell

Other Decks in Programming

Transcript

  1. zomgscale!
    with Celluloid and JRuby
    Ben Lovell
    Saturday, 29 June 13

    View Slide

  2. benlovell
    _j
    Saturday, 29 June 13

    View Slide

  3. Saturday, 29 June 13

    View Slide

  4. queen
    Saturday, 29 June 13

    View Slide

  5. dating platform
    20m members
    10k partner sites
    Saturday, 29 June 13

    View Slide

  6. we’re hiring
    isn’t everyone?
    Saturday, 29 June 13

    View Slide

  7. Moore’s
    Law
    Saturday, 29 June 13

    View Slide

  8. every few years
    CPU clock speed
    has doubled
    Saturday, 29 June 13

    View Slide

  9. but recently
    the growth
    has stalled
    Saturday, 29 June 13

    View Slide

  10. cores
    ++++++++
    Saturday, 29 June 13

    View Slide

  11. the free lunch
    is over
    Herb Sutter
    Saturday, 29 June 13

    View Slide

  12. harness the
    POWER
    in those cores
    Saturday, 29 June 13

    View Slide

  13. ?
    Saturday, 29 June 13

    View Slide

  14. concurrency
    parallelism
    Saturday, 29 June 13

    View Slide

  15. so there’s a
    difference?
    Saturday, 29 June 13

    View Slide

  16. Saturday, 29 June 13

    View Slide

  17. processes
    or
    threads
    Saturday, 29 June 13

    View Slide

  18. processes
    memory constraints
    communication
    x cores == x processes?
    Saturday, 29 June 13

    View Slide

  19. processes
    what about fork(2)
    and CoW friendly GC
    ?
    Saturday, 29 June 13

    View Slide

  20. Saturday, 29 June 13

    View Slide

  21. threads
    sharing state
    locks and granularity
    races
    hard to reason
    Saturday, 29 June 13

    View Slide

  22. zomg! I <3
    multithreaded code
    NOBODY. EVER.
    Saturday, 29 June 13

    View Slide

  23. but there are ways
    to mitigate the madness
    Saturday, 29 June 13

    View Slide

  24. don’t communicate by
    sharing memory...
    ...share memory
    by communicating
    go
    Saturday, 29 June 13

    View Slide

  25. Saturday, 29 June 13

    View Slide

  26. Saturday, 29 June 13

    View Slide

  27. painless
    multithreaded
    programming
    for ruby
    Saturday, 29 June 13

    View Slide

  28. Tony Arcieri
    Tim Carey-Smith
    Ben Langfeld
    @bascule
    @halorgium
    @benlangfeld
    The Maintainers
    Saturday, 29 June 13

    View Slide

  29. a concurrent object oriented
    programming framework which
    lets you build multithreaded
    programs out of concurrent
    objects just as easily as you
    build sequential programs
    out of regular objects
    Saturday, 29 June 13

    View Slide

  30. based upon the
    actor model
    Saturday, 29 June 13

    View Slide

  31. actor model
    first proposed
    way back in 1970
    Saturday, 29 June 13

    View Slide

  32. actor model
    actors are isolated within
    lightweight processes
    Saturday, 29 June 13

    View Slide

  33. actor model
    actors possess
    identity
    Saturday, 29 June 13

    View Slide

  34. actor model
    absolutely
    no shared state
    Saturday, 29 June 13

    View Slide

  35. actor model
    actors don’t need to
    compete for locks
    Saturday, 29 June 13

    View Slide

  36. actor model
    are sent messages
    asynchronously
    Saturday, 29 June 13

    View Slide

  37. actor model
    messages are
    buffered by a mailbox
    Saturday, 29 June 13

    View Slide

  38. actor model
    the actor works off each
    message sequentially
    Saturday, 29 June 13

    View Slide

  39. actor model
    has implementations
    in many languages
    Saturday, 29 June 13

    View Slide

  40. Saturday, 29 June 13

    View Slide

  41. Saturday, 29 June 13

    View Slide

  42. Saturday, 29 June 13

    View Slide

  43. Saturday, 29 June 13

    View Slide

  44. Saturday, 29 June 13

    View Slide

  45. Saturday, 29 June 13

    View Slide

  46. celluloid actors
    automatically
    synchronize state
    Saturday, 29 June 13

    View Slide

  47. 1 class Actor
    2 attr_reader :counter
    3
    4 def initialize
    5 @counter = 0
    6 @mutex = Mutex.new
    7 end
    8
    9 def increment
    10 @mutex.synchronize do
    11 @counter += 1
    12 end
    13 end
    14 end
    Saturday, 29 June 13

    View Slide

  48. with celluloid
    the same example...
    Saturday, 29 June 13

    View Slide

  49. 1 require "celluloid"
    2
    3 class Actor
    4 include Celluloid
    5 attr_reader :counter
    6
    7 def initialize
    8 @counter = 0
    9 end
    10
    11 def increment
    12 @counter += 1
    13 end
    14 end
    Saturday, 29 June 13

    View Slide

  50. Saturday, 29 June 13

    View Slide

  51. celluloid actors
    are active objects
    living within threads
    Saturday, 29 June 13

    View Slide

  52. 1 require "celluloid"
    2
    3 class Actor
    4 include Celluloid
    5 end
    6
    7 actor = Actor.new
    8 actor.inspect
    9 #=>
    10
    11 Thread.main
    12 #=>
    13
    14 actor.thread
    15 #=>
    Saturday, 29 June 13

    View Slide

  53. 1 module Celluloid
    2 module ClassMethods
    3 # Create a new actor
    4 def new(*args, &block)
    5 proxy = Actor.new(allocate, actor_options).proxy
    6 proxy._send_(:initialize, *args, &block)
    7 proxy
    8 end
    9 #...
    10 end
    11 #...
    12 end
    Saturday, 29 June 13

    View Slide

  54. celluloid actors
    messages you send
    are buffered via the
    actor’s mailbox...
    Saturday, 29 June 13

    View Slide

  55. celluloid actors
    ... until the actor is
    ready to act upon them
    Saturday, 29 June 13

    View Slide

  56. ______________
    < ETOOMANYACTS >
    --------------
    \ ^__^
    \ (oo)\_______
    (__)\ )\/\
    ||----w |
    || ||
    Saturday, 29 June 13

    View Slide

  57. celluloid actors
    there is no
    pattern matching
    just regular method calls
    Saturday, 29 June 13

    View Slide

  58. celluloid actors
    poll their mailbox
    via a message loop
    Saturday, 29 June 13

    View Slide

  59. 1 class Actor
    2 # Wrap the given subject with an Actor
    3 def initialize(subject, options = {})
    4 @subject = subject
    5 @mailbox = options[:mailbox] || Mailbox.new
    6 @running = true
    7
    8 @thread = ThreadHandle.new(:actor) do
    9 setup_thread
    10 run
    11 end
    12 #...
    13 end
    14 #...
    15 end
    Saturday, 29 June 13

    View Slide

  60. 1 class Actor
    2 def run
    3 #...
    4 while @running
    5 if message = @mailbox.receive(timeout_interval)
    6 handle_message message
    7 else
    8 # No message indicates a timeout
    9 @timers.fire
    10 @receivers.fire_timers
    11 end
    12 end
    13 #...
    14 shutdown
    15 end
    16 end
    Saturday, 29 June 13

    View Slide

  61. celluloid actors
    act upon messages
    sequentially
    Saturday, 29 June 13

    View Slide

  62. what about ordering?
    no guarantees
    Saturday, 29 June 13

    View Slide

  63. celluloid actors
    dispatch calls
    within fibers
    Saturday, 29 June 13

    View Slide

  64. fibers?
    cooperative
    lightweight
    user space
    some gotchas...
    Saturday, 29 June 13

    View Slide

  65. celluloid actors
    can dispatch
    synchronously
    Saturday, 29 June 13

    View Slide

  66. 1 require "celluloid"
    2
    3 class Actor
    4 include Celluloid
    5
    6 def compute_all_the_things
    7 sleep 2
    8 puts "42"
    9 end
    10 end
    11
    12 actor = Actor.new
    13 actor.compute_all_the_things
    14 puts "done!"
    #=> 42
    #=> done!
    blocking
    Saturday, 29 June 13

    View Slide

  67. celluloid actors
    can dispatch
    asynchronously
    Saturday, 29 June 13

    View Slide

  68. 1 require "celluloid"
    2
    3 class Actor
    4 include Celluloid
    5
    6 def compute_all_the_things
    7 sleep 2
    8 puts "42"
    9 end
    10 end
    11
    12 actor = Actor.new
    13 actor.async.compute_all_the_things
    14 puts "done!"
    15
    16 #=> done!
    17 #=> 42
    returns
    immediately
    Saturday, 29 June 13

    View Slide

  69. celluloid actors
    can perform tasks
    in futures
    Saturday, 29 June 13

    View Slide

  70. 1 require "celluloid"
    2
    3 class Actor
    4 include Celluloid
    5
    6 def compute_all_the_things
    7 sleep 2
    8 "42"
    9 end
    10 end
    11
    12 actor = Actor.new
    13 future = actor.future.compute_all_the_things
    14 puts "done!"
    15 puts future.value
    16
    17 #=> done!
    18 #=> 42
    returns immediately
    blocks until a
    value is yielded
    Saturday, 29 June 13

    View Slide

  71. celluloid actors
    are accessible by
    reference or name
    Saturday, 29 June 13

    View Slide

  72. 1 require "celluloid"
    2
    3 class Actor
    4 include Celluloid
    5
    6 def compute_all_the_things
    7 sleep 2
    8 puts "42"
    9 end
    10 end
    11
    12 actor = Actor.new
    13 Celluloid::Actor[:foo] = actor
    14
    15 actor.inspect
    16 #=>
    17 Celluloid::Actor[:foo].inspect
    18 #=>
    Saturday, 29 June 13

    View Slide

  73. celluloid actors
    are fault tolerant
    ... let it crash!
    Saturday, 29 June 13

    View Slide

  74. 1 require "celluloid/autostart"
    2
    3 class Actor
    4 include Celluloid
    5
    6 def compute_all_the_things
    7 puts "42"
    8 end
    9
    10 def zomg_crash
    11 raise "derp!"
    12 end
    13 end
    14
    15 supervisor = Actor.supervise_as :foo
    16
    17 begin
    18 Celluloid::Actor[:foo].zomg_crash
    19 rescue
    20 puts "whoops"
    21 end
    22
    23 Celluloid::Actor[:foo].compute_all_the_things
    24
    25 #=> whoops
    26 #=> 42
    crash the actor
    fresh actor
    take care of me!
    Saturday, 29 June 13

    View Slide

  75. celluloid actors
    can be arranged
    as pooled workers
    Saturday, 29 June 13

    View Slide

  76. 1 require "celluloid"
    2
    3 class Actor
    4 include Celluloid
    5
    6 def compute_all_the_things
    7 sleep 1
    8 puts "42"
    9 end
    10 end
    11
    12 pool = Actor.pool
    13
    14 4.times { pool.compute_all_the_things }
    15
    16 #=> 42
    17 #=> 42 and so on...
    size*cores
    load up the
    workers
    Saturday, 29 June 13

    View Slide

  77. there’s more
    timers
    links
    supervision groups
    pub/sub
    conditions
    Saturday, 29 June 13

    View Slide

  78. didn’t your proposal
    mention JRuby?
    Saturday, 29 June 13

    View Slide

  79. so what’s wrong with
    MRI?
    Saturday, 29 June 13

    View Slide

  80. well, nothing
    but...
    Saturday, 29 June 13

    View Slide

  81. GLOBAL
    INTERPRETER
    LOCK
    we got this far without a mention
    Saturday, 29 June 13

    View Slide

  82. MRI
    not so bad when you’re
    I/O bound
    Saturday, 29 June 13

    View Slide

  83. MRI
    but what about
    computation?
    Saturday, 29 June 13

    View Slide

  84. JRuby
    has no such lock
    rubinius too!
    Saturday, 29 June 13

    View Slide

  85. that low hanging fruit?
    yeah, about that...
    Saturday, 29 June 13

    View Slide

  86. but there is one tip!
    blocking I/O...
    don’t
    Saturday, 29 June 13

    View Slide

  87. Saturday, 29 June 13

    View Slide

  88. an event-driven IO system for
    building fast, scalable network
    applications that integrate
    directly with celluloid actors
    Saturday, 29 June 13

    View Slide

  89. unlike certain other evented
    I/O systems which limit you to a
    single event loop per process
    Celluloid::IO lets you make
    as many actors as you want
    system resources permitting
    Saturday, 29 June 13

    View Slide

  90. the future of ruby
    concurrency
    and parallelism?
    Saturday, 29 June 13

    View Slide

  91. the future of ruby
    true thread-level
    parallelism is available
    right now!
    Saturday, 29 June 13

    View Slide

  92. Saturday, 29 June 13

    View Slide

  93. the future of ruby
    will MRI reconsider
    the GIL?
    Saturday, 29 June 13

    View Slide

  94. the future of ruby
    ask Matz!
    (title collector)
    Saturday, 29 June 13

    View Slide

  95. thanks!
    @benlovell
    ?
    Saturday, 29 June 13

    View Slide