Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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.

146e52d49d361f85c0945487452fc6a0?s=128

Ben Lovell

June 29, 2013
Tweet

Transcript

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

    13
  2. benlovell _j Saturday, 29 June 13

  3. Saturday, 29 June 13

  4. queen Saturday, 29 June 13

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

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

  7. Moore’s Law Saturday, 29 June 13

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

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

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

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

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

  13. ? Saturday, 29 June 13

  14. concurrency parallelism Saturday, 29 June 13

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

  16. Saturday, 29 June 13

  17. processes or threads Saturday, 29 June 13

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

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

    29 June 13
  20. Saturday, 29 June 13

  21. threads sharing state locks and granularity races hard to reason

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

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

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

    Saturday, 29 June 13
  25. Saturday, 29 June 13

  26. Saturday, 29 June 13

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

  28. Tony Arcieri Tim Carey-Smith Ben Langfeld @bascule @halorgium @benlangfeld The

    Maintainers Saturday, 29 June 13
  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
  30. based upon the actor model Saturday, 29 June 13

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

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

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

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

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

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

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

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

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

    13
  40. Saturday, 29 June 13

  41. Saturday, 29 June 13

  42. Saturday, 29 June 13

  43. Saturday, 29 June 13

  44. Saturday, 29 June 13

  45. Saturday, 29 June 13

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

  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
  48. with celluloid the same example... Saturday, 29 June 13

  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
  50. Saturday, 29 June 13

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

    June 13
  52. 1 require "celluloid" 2 3 class Actor 4 include Celluloid

    5 end 6 7 actor = Actor.new 8 actor.inspect 9 #=> <Celluloid::ActorProxy(Actor:0x3feaecbb38e0)> 10 11 Thread.main 12 #=> <Thread:0x007f86290b8ce8 run> 13 14 actor.thread 15 #=> <Thread:0x007f862ad27a78 sleep> Saturday, 29 June 13
  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
  54. celluloid actors messages you send are buffered via the actor’s

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

    upon them Saturday, 29 June 13
  56. ______________ < ETOOMANYACTS > -------------- \ ^__^ \ (oo)\_______ (__)\

    )\/\ ||----w | || || Saturday, 29 June 13
  57. celluloid actors there is no pattern matching just regular method

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

    29 June 13
  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
  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
  61. celluloid actors act upon messages sequentially Saturday, 29 June 13

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

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

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

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

  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
  67. celluloid actors can dispatch asynchronously Saturday, 29 June 13

  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
  69. celluloid actors can perform tasks in futures Saturday, 29 June

    13
  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
  71. celluloid actors are accessible by reference or name Saturday, 29

    June 13
  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 #=> <Celluloid::ActorProxy(Actor:0x3feb3ec11308)> 17 Celluloid::Actor[:foo].inspect 18 #=> <Celluloid::ActorProxy(Actor:0x3feb3ec11308)> Saturday, 29 June 13
  73. celluloid actors are fault tolerant ... let it crash! Saturday,

    29 June 13
  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
  75. celluloid actors can be arranged as pooled workers Saturday, 29

    June 13
  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
  77. there’s more timers links supervision groups pub/sub conditions Saturday, 29

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

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

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

  81. GLOBAL INTERPRETER LOCK we got this far without a mention

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

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

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

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

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

    June 13
  87. Saturday, 29 June 13

  88. an event-driven IO system for building fast, scalable network applications

    that integrate directly with celluloid actors Saturday, 29 June 13
  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
  90. the future of ruby concurrency and parallelism? Saturday, 29 June

    13
  91. the future of ruby true thread-level parallelism is available right

    now! Saturday, 29 June 13
  92. Saturday, 29 June 13

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

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

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