Oh!Coder

Coding Life

Redis-rb Gem简介

| Comments

说好这个星期简单介绍一下redis-rb这个gem,不失言。

功能简介

Redis-rb是对Redis的接口用Ruby语言进行封装的类库。这个Ruby类库尽可能的对Redis的API做了一对一的封装,与此同时,提供一些更符合Ruby语法规则的接口。除此之外,此类库还保证了线程安全的特性,客户端的分片(client-side sharding),管线(pipelining)以及对性能的专注。有一点要提醒一下,这只是一个Ruby语言的类库,距离在Rails上使用还有一点距离。

基本使用

1
2
3
require "redis"

redis = Redis.new

这段代码中,定义的redis实例,使用的是默认的配置,监听的是localhost,端口号是6379。如果想连接远程的redis服务器,可以传入参数进行指定:

1
redis = Redis.new(:host => "10.0.1.1", :port => 6380 :db => 15)

除了这种方式以外,还可以传入一个URL作为参数:

1
redis = Redis.new(:url => "redis://:p4ssw0rd@10.0.1.1:6380/15")

默认情况下,client会尝试读取REDIS_URL环境变量作为URL进行连接。上面的语句相当于对环境变量做了设置,然后调用了不带参数的Redis.new

尝试连接一个使用Unix socket的Redis服务端:

1
redis = Redis.new(:path => "/tmp/redis.sock")

尝试连接一个带有密码保护的实例:

1
redis = Redis.new(:password => "mysecret")

对于Redis的常用命令,例如SETGET命令,可以通过所声明的实例进行调用,比如:

1
2
3
4
5
redis.set("mykey", "hello world")
# => "OK"

redis.get("mykey")
# => "hello world"

类似的,所有的命令以及返回值,都可以通过实例进行方法调用。

Sentinel支持

client可以通过使用Redis Sentinel实现对故障的自动转移。但要确保Redis的版本在2.8+以上。若想使用Sentinel进行连接,使用如下:

1
2
3
SENTINELS = [{:host => "127.0.0.1", :port => 25380},
             {:host => "127.0.0.1", :port => 26381}]
redis = Redis.new(:url => "redis://mymaster", :sentinels => SENTINELS, :role => :master)
  • master的名称标示了一组Redis实例,其中包括一个master,一个或多个slave(例子中mymaster为例)。
  • 尽可能的提供一个角色。可选的角色包括masterslave。当角色中包括slave时,client会随机连接一个slave。如果没有指定角色,client会连接master。
  • 当使用Sentinel功能时,需要提供一个可以进行sentinel的列表。当有slave挂掉的时候,client可以访问最新的Sentinel,并在下一次请求的时候进行正确的回复。

存储

Redis只能存储字符串数值。如果想存储一个对象,可以采取一些序列化的机制进行存储,例如JSON:

1
2
3
4
5
6
7
require "json"

redis.set "foo", [1, 2, 3].to_json
# => OK

JSON.parse(redis.get("foo"))
# => [1, 2, 3]

Pipelining

当需要一次执行多个命令,并且这些命令顺序执行,之间没有依赖时,这种调用称之为pipelined。这意味着client不用等待上一条命令执行完毕再发送下一条命令。

client可以通过使用pipelined方法组织pipeline命令。当方法块儿执行完毕之后,pipelined方法会最终返回一个结果。举例如下:

1
2
3
4
5
redis.pipelined do
  redis.set "foo", "bar"
  redis.incr "baz"
end
# => ["OK", 1]

自动执行命令

可以使用MULTI/EXEC方法自动运行一定数量的命令。有点类似于pipeline,但是命令会先被MULTI执行,紧接着调用EXEC。跟普通的pipeline类似,返回值是multi方法的返回值。举例如下:

1
2
3
4
5
redis.multi do
  redis.set "foo", "bar"
  redis.incr "baz"
end
# => ["OK", 1]

Future

redis-rb 3.0版本开始,所有的命令返回值可以通过future进行访问。所有在同一个pipeline块的命令行,都会返回一个Future对象,此对象提供了一个value方法。当所有pipeline成功执行之后,所有这些返回的future都可以使用。

1
2
3
4
5
6
7
8
9
10
redis.pipelined do
  @set = redis.set "foo", "bar"
  @incr = redis.incr "baz"
end

@set.value
# => "OK"

@incr.value
# => 1

错误处理

通常来说,如果出现错误了,你会得到一个异常。比如说,如果连接不到服务器,会得到一个Redis::CannotConnectError错误。举例如下:

1
2
3
4
5
6
7
8
9
begin
  redis.ping
rescue Exception => e
  e.inspect
# => #<Redis::CannotConnectError: Timed out connecting to Redis on 10.0.1.1:6380>

  e.message
# => Timed out connecting Redis on 10.0.1.1:6380
end

关于可能发生的错误信息,可以参见源码中lib/redis/errors.rb文件。

交替驱动

默认情况下,redis-rb使用Ruby的socket库和Redis通话。当安装client对象的时候对于交替驱动进行指定。这些命令只对redis-rb 3.0有效。

hiredis

hiredis驱动使用hiredis-rb方式进行连接。相对应的,hiredis-rb是一个绑定到官方hiredis的client库。这个库对速度做了优化。因为属于是C扩展,所以默认不支持JRuby。

在有大量repliy的时候(例如:LRANGESMEMBERSZRANGE等等)推荐使用hiredis,可以结合着使用大pipeline。安装方式如下:

1
2
gem "redis", "~> 3.0.1"
gem "hiredis", "~> 0.4.5"

声明对象的时候可以进行指定:

1
redis = Redis.new(:driver => :hiredis)

同步(synchrony)

同步驱动需要em-synchrony的支持。使用这种方法,依然需要hiredis gem,因为同步驱动使用hiredis来解析Redis协议。在Gemfile中,需要包含em-synchrony和hiredis:

1
2
3
gem "redis", "~> 3.0.1"
gem "hiredis", "~> 0.4.5"
gem "em-synchrony"

实例化对象的时候,需要指定同步:

1
redis = Redis.new(:driver => :synchrony)

好啦,关于redis-rb就介绍这么多了,更新更详细的内容,可以直接参见原文档

Comments