我不止一次说过:“学习Redis是程序员花费30分钟最有效的方式。”这句“哲言”阐释了Redis有多么有用,Redis有多么易学——但是,这是真的么?真的能在30分钟内学会,甚至精通Redis么?

让我们来尝试下吧。这一部分,我们将学习“Redis是什么”。下一部分,我们将探讨一些简单的例子。剩下的时间里我们将让你自己搭建和玩转Redis。

Redis简介

Redis经常为描述一个Key/Value存储引擎。这个描述非常准确,但是可能并不像你想象的那样。当然,我想把它看做是一个数据结构引擎会更有帮助一些。Redis支持5种不同的数据结构:字符串(Strings),hash表,集合(sets)和有序集合(sorted sets)。每一种数据结构都自己独特的特性并支持独特的命令。无论哪一种类型,都是用一个key去取一个value。虽然key是以二进制的形式存储,比较复杂,但是你总是可以用一个字符串作为一个key。

让我们看看每一种类型吧。

Strings

Strings是5种数据结构中最简单的了。不幸的是,它的名字起得很糟糕,其实与我们常说的字符串没有任何关系。或许叫做single或者simple更好(译注:一对一映射)。人们在使用Redis或者思考Key Value时,实际上是在思考String结构(但是记住,那只是5种结构中的一种)。正像Key一样,一个string value可以是任何二进制数组。你可以保存一个持续增长的计数器,一个实际的字符串,或者一个二进制序列化后的对象。这些都是很常用的。最常用的string method是GETSET

SET pages:about "about us"
GET pages:about
about us

你可以使用string做很多事情,不但因为它还有其他一些命令(如:INCR或者GETRANGE),还因为我们可以存储其他类型的数据。比如,我们可以使用String结构去管理用户。它的key可以是他们的email,而数值可以是用户序列化之后的对象。

Hashes

hash数据结构和你想象中的hash表、字典是一致的。我们与其直接操作一个key(像string一样),不如操作一个key的多个成员。所以说,我们不是仅get和set一个hash值,而是get和set值的一个成员:

HSET goku power 9001
HGET goku power
9001

和其他Redis中的结构一样,成员和值最终是以二进制数组存储的,所以它们可以是任何类型的数据。尽管field很像key,倾向于使用字符串。问题是什么情况下我们应该使用一个Hash表而不是一个String?比方说,这两者的区别在哪里?(我使用json来表达复杂的值)

SET users:goku {race: 'sayan', power: 9001}
HSET users:goku race sayan
HSET users:goku power 9001

区别出现在当你要修改和查询它的时候。如果你需要控制单独的field,而又不想把整个对象都加载到你的应用中的话,就应该使用hash表。反之,一个String或许就能满足你的需要。(译注:String只能控制一级key/value,而hash可以控制更深层次key/value设置。)

Lists

列表让你将一个数组与单个key相关联。实际上,你可以把它想象成是动态数组。你可以使用insert,append,pop,push,trim等操作。Redis不支持二维索引。你只能通过数据的key来访问数据。

 length = redis.lpush('users:newest', 'user:goku')
 if length > 100
   #trim is to we only keep 100 "newest" users
   redis.rpop('users:newest')
 end

上面的代码保存了一个在列表中最新注册用户的引用。这里我们在运行时维护列表的长度,尽管我们也可以把它移交给一个后台任务。我们如何做到这点?

 # get the 10 newest users
 keys = redis.lrange('users:newest', 0, 10)
 #multi get the actual 10 user objects
 redis.mget(*keys)

习惯上来说,开发者都会避免使用这类重复查询数据库的动作。但是,有了Redis,这种行为是常见而且高效的。

Sets

集合和列表很像,除了它提供的集合特性(不允许重复元素出现在集合中)。你可以使用SDIFF做集合间的差分,SUNION做集合间的并或者SUNIONSTORE将并集存储在一个另一个集合中而不是返回出来,等等。集合是一种你可以用来跟踪好友和标签的数据结构:

SADD friends:leto ghanima
SADD friends:leto duncan
SADD friends:paul duncan
SADD friends:paul gurney
SINTER friends:leto friends:paul
1) "duncan"

Sorted Sets

比较不同数据结构的好坏是没有意义的,因为它们各自都满足不同场景和不同需求,但是排序集合是非常棒的。一个排序集合和普通集合很相似,除了一点,它的值都关联一个score filed。换句话说,当你将一个值加入一个排序集合时,你必须同时制定一个score。score决定了在集合中值的排列顺序。建立在上一个例子的基础上,我们可以为我们的数据加权:

 ZADD friends:leto 1000 ghanima
 ZADD friends:leto 994 duncan
 ZADD friends:leto 2 farad'n
 ZRANGEBYSCORE friends:leto 500 1000
 1) "duncan"
 2) "ghanima"

上面的代码获取了leto朋友中所有score在500到1000的人。

排序集合不仅仅可以用在管理朋友上。score属性同样可以用来跟踪时间序列(比如使用从1970年到当前时间的毫秒数)或者根据游戏分数来排序玩家。

Redis Querying

在Redis中,数据只能被使用key查询。即使你使用一个hash表,我们不能说找到值为sayan所对应的key。在查看列表时,我们看到自己是如何构建二级索引的。管理你自己的二级索引总是痛苦的,而且有时它会因为太复杂而无法扩展。然而,需要记住两件事。一,你应该玩转它、尝试它,在你真正开始写代码之前,即使面对一个复杂的情况,也没什么大不了的。二,不要害怕重复访问Redis。

除了上文举出的5种数据结构外,Redis还有key的通用命令(称为key-commands),比如DEL,EXISITSRENAME。或许最常用的命令就是KEYS命令了,它接受一个模式然后返回一组找到的key。例如,mogade.com使用一组类似ranks:daily:GAME_ID:20110830的key来管理每天的游戏等级。如果你要删除8月份所有的游戏等级,可以这样做:

 keys = redis.keys("ranks:daily:*:201108*")
 redis.del(*keys)

注意:keys-command线性地搜索所有的key来找到匹配者。这样做会很慢,一般文档建议你在开发或者debug时才使用。

其他需知事项

Redis的安装和维护都非常方便。数据被保存在单个磁盘文件中,这个文件可以简单地通过拷贝来进行备份。它被一个易懂的配置文件驱动。

所有你的数据都会被读入到内存。它同样支持虚拟内存,但是有人说这个特性没有试验成功。虚拟内存的使用可能会再后来版本中被去掉。

Redis支持主从复制(master-slave)。它不会做任何自动的失败备份或者碎片管理。这些可能都是需要你通过比如HAProxy来完成的。Redis Cluster(Redis集群)功能会加入到不久后的release里,用于解决这个问题。我们应该关注近期的relase。(如果你感兴趣,请参考这篇文档

还有更多关于Redis的内容等着我们。它支持事务,有更多的命令、更多的管理特性,支持key的自动过期,甚至是一个分发/订阅者 API。尽管我对技术文档非常挑剔,但仍然被Redis的文档参考所震惊。

Redis比其他许多存储解决方案要更具体。对于复杂的系统来说,正确方式是从一个一个特性入手各个击破,而不是一口气吃成胖子。Redis需要把所有东西都加载到内存,这或许会限制你对它的使用。然而,当一个个特性有个数据模型合适使用Redis的数据结构时,这是一件令人非常高兴的事。Redis非常迅捷,而且API非常简单。我已经将原数百行的查询代码转换成了ZADD ZREVRANGE的调用。

总之,Redis是非常易于学习和理解的。给定一个问题,你或多或少会清楚Redis是否合适。

结论

把Redis想象成一个Key/Value存储工具是错误的。它要更甚于一个Key/Value存储工具。它同样代表一个完全不同的思考数据模型的方式。有时,它不见得有效,但是一旦它有效,啊,那是多么令人高兴!

或许你需要休息下?看看Redis的官网?或者,你可以读一读第二部分

原文链接 :Redis: Zero to Master in 30 minutes - Part 1

本文参与iTran乐译项目。