关于redis
前言
我终于找到时间研究Redis了,前一段时间居然去搞前端去了,感觉有点不自在。果然,server端才是自己的前进的方向,Rails,Redis,Mongodb之类的。
redis-rb
redis-rb是[Redis][http://redis.io]的ruby客户端。redis-rb客户端尝试一一匹配Redis的API,并提供地道 的接口。其具备线程安全、客户端分片、管道以及不错的性能。
从2.x升级到3.0, 不过,网站上使用的已经是最新的redis版本了。
起步
2.0的客户端匹配2.0以上的Redis版本。如果想要使用2.0之前的redis实例,可以使用老的客户端(不再开发维护)。
连接Redis需要实例化Redis
类。
require "redis"
redis = Redis.new
这里假设Redis以默认配置启动,即监听localhost
和6379端口。如果需要连接到远程服务器的不同端口,可以
这么做:
redis = Redis.new(:host => "10.0.1.1", :port => 6380, :db => 15)
当然,也可以通过URL来指定连接选项:
redis = Redis.new(:url => "redis://:p4ssw0rd@10.0.1.1:6380/15")
默认情况下,客户端尝试读取REDIS_URL
环境变量,并使用其中的值作为链接的URL。设置环境变量并
以不带参的调用Redis.new
,上述的语句功效是相同的。
可以通过Unix套接字连接Redis的设置,其代码如下:
redis = Redis.new(:path => "/tmp/redis.sock")
连接带密码保护的Redis实例,可以使用:
redis = Redis.new(:password => "mysecret")
Redis类提供的方法与所执行的命令名一致。这些方法接受的参数与命令接受的参数也一致,命令参数 的详细描述参考Redis website
redis.set("mykey", "hello world")
# => "OK"
redis.get("mykey")
# => "hello world"
所有的命令、参数及其返回值都是被文档化的,并且可在 rdoc.info 中查看。
哨兵支持(Sentinel support)
通过使用Redis哨兵,客户端可以自动支持故障转义。
建立哨兵链接的命令如下:
SENTINELS = [{:host => "127.0.0.1", :port => 26380},
{:host => "127.0.0.1", :port => 26381}]
redis = Redis.new(:url => "redis://mymaster", :sentinels => SENTINELS, :role => :master)
- master名指定了主从模型的一组Redis实例(例子中为
mymaster
) - 可指定角色选项,其值可为
master
和slave
。当角色为slave
时,客户端将尝试连接到由特定master指定的随机slave中。 如果没有指定角色,客户端将链接到master上。 - 使用哨兵支持需要指定链接的哨兵列表。列表中不需要枚举出所有的哨兵实例,但是必须确保,一个挂了后还能找到另一个替代 客户端能记住上一个可正确应答的哨兵,并在下次请求时使用该哨兵。
备注: 哨兵支持的redis支持集群的一种形式。Redis 3.0 发布了新的集群支持方案。
对象保存(Storing objects)
Redis只能将字符串存储为值,如果想要保存对象,必须是使用某种序列化的机制,比如JSON:
require "json"
redis.set "foo", [1, 2, 3].to_json
# => OK
JSON.parse(redis.get("foo"))
# => [1, 2, 3]
Ruby中存在一个封送的功能支持。
管道(Pipelining)
当多个命令顺序执行,且彼此依赖时,这叫管道。 这意味着,在发送下一条命令之前,客户端不需要等待 第一条命令的回复。管道的优势是,多条命令一次发送,整体执行更快。
通过调用#pipelined
方法,客户端可以执行管道命令。在代码块执行后,客户端将所有的命令发送给Redis,
然后收集其响应。响应由#pipelined
方法返回。
redis.pipelined do
redis.set "foo", "bar"
redis.incr "baz"
end
# => ["OK", 1]
以原子的方式执行命令
You can use MULTI/EXEC
to run a number of commands in an atomic
fashion. This is similar to executing a pipeline, but the commands are
preceded by a call to MULTI
, and followed by a call to EXEC
. Like
the regular pipeline, the replies to the commands are returned by the
#multi
method.
可以MULTI/EXEC
命令以原子的方式,运行一组命令。 这和执行管道类似,但是,必须以MULTI
作为前置命令,
以EXEC
作为后置命令。与常规的管道,相应命令的功能由#multi
方法提供。
redis.multi do
redis.set "foo", "bar"
redis.incr "baz"
end
# => ["OK", 1]
Futures(未来?)
管道中命令的响应可以通过未来对象来访问(redis-rb 3.0之后)。在管道块中的所有调用都会返回一个
未来对象, 其可调用#value
方法。但管道成功执行时,所有复制的未来对象都可以使用。
注: 我觉得这里就是闭包功能的体现,所以,未来对象的命名感觉很新奇。
redis.pipelined do
@set = redis.set "foo", "bar"
@incr = redis.incr "baz"
end
@set.value
# => "OK"
@incr.value
# => 1
错误处理(Error Handling)
如果,有些事情挂了,你就会得到一个异常。如果不能连接到服务器,就会抛出Redis::CannotConnectError
。
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 to Redis on 10.0.1.1:6380
end
在发生异常时,参考lib/redis/errors.rb
,寻找更多的信息。
ruby代码本身具有极强的可读性,其代码可当作文档来看的。
专家模式选项(Expert-Mode Options)
inherit_socket: true
: disable safety check that prevents a forked child from sharing a socket with its parent; this is potentially useful in order to mitigate connection churn when:- many short-lived forked children of one process need to talk to redis, AND
- your own code prevents the parent process from using the redis connection while a child is alive
inherit_socket
使用不当将会导致错误和不正确的反应。
可选的驱动(Alternate drivers)
默认情况下,redis-rb使用Ruby的套接字库与Redis交互。当然在初始化客户端对象时,指定使用其他 可选的链接库。当前指南仅对redis-rb 3.0有效,想要在redis-rb 2.2使用可选的驱动,请参 考老的README文档。
hiredis
hiredis驱动使用hiredis-rb的连接工厂。换而言之,hiredis-rb是官方hiredis客户端库的绑定。其优化了速度和 内存开销。由于其是C扩展,默认不支持JRuby。
It is best to use hiredis when you have large replies (for example:
LRANGE
, SMEMBERS
, ZRANGE
, etc.) and/or use big pipelines.
当回复数据巨大或使用大管道时,最好使用hiredis,例如在使用LRANGE
, SMEMBERS
, ZRANGE
等命令。
在Gemfile中,按如下的方式包含hiredis:
gem "redis", "~> 3.0.1"
gem "hiredis", "~> 0.4.5"
然后在实例化客户端对象时,指定hiredis:
redis = Redis.new(:driver => :hiredis)
同步(synchrony)
同步驱动添加了对em-synchrony的支持。这使得 redis-rb可以与EventMachine的异步I/O协同工作,而无序改变现有的API。此时,也需要包含hiredis 的gem包,因为同步驱动使用hiredis解析Redis协议。
在Gemfile中,需要包含em-synchrony和hiredis:
gem "redis", "~> 3.0.1"
gem "hiredis", "~> 0.4.5"
gem "em-synchrony"
实例化客户端对象时,需要指定synchrony选项:
redis = Redis.new(:driver => :synchrony)
测试
redis-rb的测试使用的是[Travis],其测试包含了如下的解释器和驱动:
- MRI 1.8.7 (drivers: ruby, hiredis)
- MRI 1.9.2 (drivers: ruby, hiredis, synchrony)
- MRI 1.9.3 (drivers: ruby, hiredis, synchrony)
- MRI 2.0.0 (drivers: ruby, hiredis, synchrony)
- JRuby 1.7 (1.8 mode) (drivers: ruby)
- JRuby 1.7 (1.9 mode) (drivers: ruby)
后记
学到一个git命令: git shortlog -sn
查看项目贡献者的排名。意外的发现,某个项目中,前辈没有提交一行代码,那就是NodeJS的
那个项目。
文档中介绍的两个驱动也是个学习点,以及项目中引入的redis-namespace
(完全为了resque而引入的,为键值引入命名空间),不对,我发现依赖根源了,我需要研究的应该是resque,所以,
我应该去研究resque。
傲娇的使用Disqus