This project was started because I needed an authenticating and routable
proxy for Redis. The main feature is a high performance, eventable, pure Ruby,
implementation of the complete Redis wire protocol using the same interface as
hiredis/reader.
In the worst possible scenario of very small payloads, I was benching 30k GETs
per second with pure ruby and 40k/s with hiredis/reader. With larger payloads,
the performance gap narrows to zero.
Ruby Gem:
gem install ruby-redis
Server:
Runs a server that looks and feels like the C redis-server
bin/ruby-redis
Run the TCL test suite from C Redis against the Ruby server
src/redis-test
Client example:
require 'redis'
EventMachine.run {
redis = EventMachine.connect '127.0.0.1', 6379, Redis::Client
Subscribe and publish messages will call here
redis.on_pubsub do |message|
# case message[0]
# when 'psubscribe' ...
end
All commands implemented uniformly with method_missing
Returns instance of Redis::Command < EventMachine::Deferrable
Pipelining is implicit
redis.set :pi, 3.14159
redis.get('pi') do |result|
p result
end
redis.blpop('mylist', 1).callback do |result|
p result
EM.stop
end.errback do |e|
EM.stop
raise e
end
}
Using hiredis/reader (only affects clients):
require it before you connect
require 'hiredis/reader'
Fibers; compatible with em-synchrony:
require 'redis/synchrony'
Redis.synchrony {
Be sure to pipeline commands when you can
redis = EventMachine.connect '127.0.0.1', 6379, Redis::Client
synchronized requests will return result or raise exception
sync = redis.synchrony
repeat transaction until success
reply = check = nil
until reply
redis.watch 'mykey'
x = sync.get('mykey').to_i
redis.multi
redis.set 'mykey', x + 1
redis.badcmd
redis.get('mykey') {|result| check=result}
reply = sync.exec
end
redis.close
EM.stop
p reply, check # ["OK", #, "4"], "4"
}
Ruby to Redis type conversions:
String === Status reply
RuntimeError === Error reply
String === Bulk reply
Integer === Integer reply
Array === Multi-bulk reply
Hash === Multi-bulk reply to hgetall
NilClass === Nil element or nil multi-bulk
TrueClass === :1
FalseClass === :0