Skip to content

Instantly share code, notes, and snippets.

@fetep
Created August 4, 2012 03:24
Show Gist options
  • Save fetep/3253952 to your computer and use it in GitHub Desktop.
Save fetep/3253952 to your computer and use it in GitHub Desktop.
non-plaintext statsd updates

over here, https://gist.github.com/3243702, i proposed extending the text protocol by supporting updating a timer with multiple values at once (to help statsd clients that do a bit of batching for efficiency). this makes the update string a bit expensive to parse (especially because you have to get to the end of a potentially long string to even know what kind of update you have).

so here are some thoughts on a different way to encode the statsd update.

if we chose one of these, so we could call this protocol version "2" in our zeromq input (e.g. zmq message payload would be "2;").

#!/usr/bin/env ruby
require 'rubygems'
require 'benchmark'
require 'bson'
require 'json'
require 'msgpack'
N = 1000 # number of parse iterations
T = ENV["T"].to_i # number of timer update values
raise ArgumentError, "specify a valid T=" if T <= 0
# build some sample timer updates w/#{T} values
test_samples = []
T.times { test_samples << (Kernel.rand(1000) + 100) }
# plaintext
sample_update = "app.foo.response_time|#{test_samples.join(',')}|t"
t = Benchmark.realtime do
N.times do
metric, samples, update_type = sample_update.split("|")
samples = samples.split(",").collect { |s| s.to_i }
end
end
puts "plaintext: #{t*1000/N}ms per message (message size: #{sample_update.bytesize} bytes)"
# json
sample_update = {
"m" => "app.foo.response_time",
"t" => "c",
"v" => test_samples,
}.to_json
t = Benchmark.realtime do
N.times do
update = JSON.parse(sample_update)
end
end
puts "json: #{t*1000/N}ms per message (message size: #{sample_update.bytesize} bytes)"
# bson
sample_update = BSON.serialize({
"m" => "app.foo.response_time",
"t" => "c",
"v" => test_samples,
}).to_s
t = Benchmark.realtime do
N.times do
update = BSON.deserialize(sample_update.unpack("C*"))
end
end
puts "bson: #{t*1000/N}ms per message (message size: #{sample_update.bytesize} bytes)"
# msgpack
sample_update = {
"m" => "app.foo.response_time",
"t" => "c",
"v" => test_samples,
}.to_msgpack
t = Benchmark.realtime do
N.times do
update = MessagePack.unpack(sample_update)
end
end
puts "msgpack: #{t*1000/N}ms per message (message size: #{sample_update.bytesize} bytes)"
# ruby-1.9.3-p194 w/json_pure & bson_ext
# timer update with 1 value
plaintext: 0.001540836ms per message (message size: 27 bytes)
json: 0.005271605ms per message (message size: 47 bytes)
bson: 0.007981213ms per message (message size: 58 bytes)
msgpack: 0.0018723490000000001ms per message (message size: 34 bytes)
# timer update with 100 values
plaintext: 0.030364895ms per message (message size: 432 bytes)
json: 0.026350153ms per message (message size: 452 bytes)
bson: 0.050510577ms per message (message size: 841 bytes)
msgpack: 0.003773309ms per message (message size: 314 bytes)
# timer update with 10_000 values
plaintext: 2.844537136ms per message (message size: 40936 bytes)
json: 1.681898258ms per message (message size: 40956 bytes)
bson: 5.274492659ms per message (message size: 98941 bytes)
msgpack: 0.288281959ms per message (message size: 28193 bytes)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment