Big Ruby Conf Bonus tracks

Big Ruby Conf Bonus tracks

A whirlwind tour of Tony Arcieri's Celluloid and Eric Lindvall's Metriks

3ee6a3dd797022da27eb4e4085f13318?s=128

Adam Keys

March 01, 2013
Tweet

Transcript

  1. You should know Celluloid and Metriks Adam Keys http://therealadam.com @therealadam

    March 2013
  2. Concurrent objects in Ruby http://celluloid.io

  3. What’s an actor model? Actor "daryl" Object ralph ... ...

    frob frob grok Thread 1 Actor "larry" Object B ... frob frob grok grok Thread 2
  4. Celluloid actors require 'redis' require 'celluloid' class RedisAdapter include Celluloid

    def initialize(redis) @redis = redis end def record(path) redis.incr("stats:#{path}") end def fetch(path) redis.get("stats:#{path}") end protected attr_reader :redis end
  5. Celluloid actors require 'celluloid' require 'json' class Stats include Celluloid

    def handle(msg) log msg case msg when %r{^VISIT (.*)$} path = $1 # regex globals :( redis.async.record(path) "OK\n" when %r{^STATS (.*)$} path = $1 # regex globals :( stats = redis.fetch(path) JSON.dump(stats: {path => stats}) else "ERR\n" end end def log(msg) Celluloid.logger.info(msg) end def redis Celluloid::Actor[:redis] end end
  6. Reliability and Supervision Groups class Collector < Celluloid::SupervisionGroup supervise Stats,

    as: :stats supervise RedisAdapter, as: :redis, args: [Redis.new] supervise Listener, as: :listener, args: ["0.0.0.0", 4000] end if __FILE__ == $0 collector = Collector.run! trap("INT") { collector.terminate; exit } sleep end
  7. I/O actors require 'celluloid/io' class Listener include Celluloid::IO def initialize(host,

    port) log "Starting on #{host}:#{port}" @server = TCPServer.new(host, port) async.run end def finalize return unless @server @server.close end def run loop { async.handle_connection(@server.accept) } end def handle_connection(socket) _, host, port = socket.peeraddr log "#{host}: #{port} connected" msg = socket.readpartial(4096) response = stats.handle(msg) socket.write(response) socket.close rescue EOFError log "#{host}: #{port} disconnected" socket.close end def log(msg) puts msg end def stats Celluloid::Actor[:stats] end end
  8. More reading •Erlang - http://erlang.org •D-Cell - https://github.com/celluloid/dcell •On Ruby

    concurrency: •http://therealadam.com/2012/06/19/getting- started-with-ruby-concurrency-using-two- simple-classes/ •http://therealadam.com/2012/07/05/protect- that-state-locks-monitors-and-atomics/ •http://therealadam.com/2012/09/10/designing- for-concurrency/ •Java Concurrency in Practice
  9. Knowing your production systems https://github.com/eric/metriks

  10. All arguments are shallow given numbers

  11. Counters, stats, et. al. require 'metrics' $api_hits = Metriks.counter('api_hits') $api_hits.increment

    require 'metriks/reporter/logger' reporter = Metriks::Reporter::Logger(logger: Logger.new('log/metrics.log')) reporter.start $api_stats = Metriks.timer('api_stats') $api_stats.time do # … work … end
  12. 1. Logfiles I, [2013-02-18T07:00:00.006093 #50406] INFO -- : metriks: time=1361192400

    name=stats type=timer count=92440 one_minute_rate=434.4299373735234 five_minute_rate= 220.682764284654 fifteen_minute_rate=90.15828364936169 mean_rate=423.37823163275544 min=0.000362023 max=0.070315041 mean=0.0007417273702509757 stddev=2.4841137753254027e-06 median=0.000614221 95th_percentile=0.0011458962499999996 I, [2013-02-18T07:00:00.009590 #50406] INFO -- : metriks: time=1361192400 name=api_stats type=timer count=92440 one_minute_rate=434.4299373735234 five_minute_rate=220.682764284654 fifteen_minute_rate=90.15828364936169 mean_rate=423.3715240226875 min=0.000300078 max=0.070015888 mean=0.0006167874175681445 stddev=2.4013694294628166e-06 median=0.000505336 95th_percentile=0.0009915237499999996
  13. 2. Convert to CSV #!/usr/bin/env ruby require 'csv' columns =

    %w{name time mean_rate 95th_percentile} out = CSV.generate do |csv| csv << columns.to_a ARGF.each_line do |l| fields = l.split next if fields[0] != 'I,' metrics = fields.slice(7..-1).inject({}) do |hsh, str| name, value = str.split('=') hsh.update(name => value) end csv << columns.inject([]) { |row, name| row << metrics[name] } end end puts out
  14. 3. Spreadsheets!

  15. Dashboard services

  16. More reading •Metrics, the original library - http:// metrics.codahale.com •Metrics

    everywhere, the slides - http:// codahale.com/codeconf-2011-04-09-metrics- metrics-everywhere.pdf •Metrics everywhere, the talk - http:// www.youtube.com/watch?v=czes-oa0yik
  17. Thanks!