Skip to content

Instantly share code, notes, and snippets.

@jgaskins
Last active June 25, 2022 14:54
Show Gist options
  • Save jgaskins/ecc0fc90d78cdec63c31e0ce5544faa1 to your computer and use it in GitHub Desktop.
Save jgaskins/ecc0fc90d78cdec63c31e0ce5544faa1 to your computer and use it in GitHub Desktop.
Benchmarking redis gem vs hiredis vs custom Redis client
require 'bundler/inline'
require 'socket'
class MyRedis
CRLF = "\r\n"
def initialize
@connection = TCPSocket.new('localhost', 6379)
@connection.sync = false
end
def get(key)
@connection << "*2\r\n$3\r\nget\r\n$#{key.bytesize}\r\n#{key}\r\n"
@connection.flush
result = @connection.gets
if result.start_with?('$')
value = ''
bytesize = result.tap { |r| r[0] = '' }.to_i
return nil if bytesize < 0 # Key does not exist
@connection.read bytesize + 2, value
value.chomp! CRLF
value
else
raise "idk what to do with this: #{result.inspect}"
end
end
end
gemfile true do
source 'https://rubygems.org'
gem 'redis'
gem 'hiredis'
gem 'benchmark-ips'
end
require 'benchmark'
require 'benchmark/ips'
require 'redis'
require 'hiredis'
redis = Redis.new(driver: :ruby)
hiredis = Redis.new(driver: :hiredis)
myredis = MyRedis.new
key = "foo"
cpu_time_iterations = 100_000
# Quick functionality check on our custom Redis
redis.set key, "test"
if (myredis_value = myredis.get(key)) == (redis_value = redis.get(key))
puts "Cache-hit function check passed"
else
raise "Value mismatch. Redis: #{redis_value.inspect}, MyRedis: #{myredis_value.inspect}"
end
redis.del key
if myredis_value = myredis.get(key).nil?
puts "Cache-miss function check passed"
else
raise "MyRedis cache miss broken: #{myredis_value.inspect}"
end
puts
puts "Cache hit (returns a 2KB string)"
redis.set key, "." * 2048 # 2KB cache entry
Benchmark.ips do |x|
x.report("ruby") { redis.get key }
x.report("hiredis") { hiredis.get key }
x.report("myredis") { myredis.get key }
x.compare!
end
puts
puts "Cache hit CPU time"
puts "ruby : #{Benchmark.measure { cpu_time_iterations.times { redis.get key } }.total}"
puts "hiredis: #{Benchmark.measure { cpu_time_iterations.times { hiredis.get key } }.total}"
puts "myredis: #{Benchmark.measure { cpu_time_iterations.times { myredis.get key } }.total}"
puts
puts "Cache miss (returns nil)"
redis.del key
Benchmark.ips do |x|
x.report("ruby") { redis.get key }
x.report("hiredis") { hiredis.get key }
x.report("myredis") { myredis.get key }
x.compare!
end
puts
puts "Cache miss CPU time"
puts "ruby : #{Benchmark.measure { cpu_time_iterations.times { redis.get key } }.total}"
puts "hiredis: #{Benchmark.measure { cpu_time_iterations.times { hiredis.get key } }.total}"
puts "myredis: #{Benchmark.measure { cpu_time_iterations.times { myredis.get key } }.total}"
Fetching gem metadata from https://rubygems.org/....
Resolving dependencies...
Using benchmark-ips 2.8.4
Using bundler 2.2.3
Using hiredis 0.6.3
Using redis 4.2.5
Cache-hit function check passed
Cache-miss function check passed
Cache hit (returns a 2KB string)
Warming up --------------------------------------
ruby 1.857k i/100ms
hiredis 3.124k i/100ms
myredis 3.184k i/100ms
Calculating -------------------------------------
ruby 22.082k (±14.1%) i/s - 107.706k in 5.021179s
hiredis 31.506k (± 1.7%) i/s - 159.324k in 5.058568s
myredis 31.997k (± 2.8%) i/s - 162.384k in 5.079019s
Comparison:
myredis: 31997.4 i/s
hiredis: 31505.6 i/s - same-ish: difference falls within error
ruby: 22081.8 i/s - 1.45x (± 0.00) slower
Cache hit CPU time
ruby : 3.7590459999999997
hiredis: 1.9650980000000011
myredis: 1.7395270000000007
Cache miss (returns nil)
Warming up --------------------------------------
ruby 2.666k i/100ms
hiredis 3.352k i/100ms
myredis 3.440k i/100ms
Calculating -------------------------------------
ruby 25.796k (± 8.2%) i/s - 127.968k in 5.006173s
hiredis 33.267k (± 1.0%) i/s - 167.600k in 5.038516s
myredis 34.693k (± 2.3%) i/s - 175.440k in 5.059694s
Comparison:
myredis: 34693.1 i/s
hiredis: 33267.0 i/s - 1.04x (± 0.00) slower
ruby: 25795.8 i/s - 1.34x (± 0.00) slower
Cache miss CPU time
ruby : 3.0532809999999984
hiredis: 1.840083
myredis: 1.5741099999999975
Fetching gem metadata from https://rubygems.org/....
Resolving dependencies...
Using bundler 2.2.15
Using hiredis 0.6.3
Using redis 4.2.5
Using benchmark-ips 2.8.4
Cache-hit function check passed
Cache-miss function check passed
Cache hit (returns a 2KB string)
Warming up --------------------------------------
ruby 2.638k i/100ms
hiredis 5.080k i/100ms
myredis 5.741k i/100ms
Calculating -------------------------------------
ruby 35.924k (±12.0%) i/s - 176.746k in 5.013467s
hiredis 52.624k (± 4.7%) i/s - 264.160k in 5.034100s
myredis 59.541k (± 1.1%) i/s - 298.532k in 5.014476s
Comparison:
myredis: 59541.4 i/s
hiredis: 52623.8 i/s - 1.13x (± 0.00) slower
ruby: 35924.1 i/s - 1.66x (± 0.00) slower
Cache hit CPU time
ruby : 1.751384999999999
hiredis: 0.9159620000000004
myredis: 0.6444190000000001
Cache miss (returns nil)
Warming up --------------------------------------
ruby 4.234k i/100ms
hiredis 5.594k i/100ms
myredis 6.340k i/100ms
Calculating -------------------------------------
ruby 42.602k (± 9.1%) i/s - 211.700k in 5.020637s
hiredis 55.257k (± 4.7%) i/s - 279.700k in 5.074557s
myredis 63.400k (± 1.6%) i/s - 317.000k in 5.001319s
Comparison:
myredis: 63399.9 i/s
hiredis: 55256.9 i/s - 1.15x (± 0.00) slower
ruby: 42601.6 i/s - 1.49x (± 0.00) slower
Cache miss CPU time
ruby : 1.417432999999999
hiredis: 0.832987000000001
myredis: 0.5722979999999982
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment