Redis的一个特点就是处理基本字符串,还支持多种数据结构,包括Hash,List,Set,SortedSet。本章主要介绍Redis的数据结构和基本操作,并给出一些典型的使用场景。
感谢《Redis 命令参考》中文版对本文的指导!
1. 字符串String
字符串操作是Redis最基础的操作。是二进制安全的。无需担心特殊字符是否可用,没有限制,底层是二进制存储。从内部实现来看,其实String可以看作byte数组,所以Redis的String可以包含任何数据:字符串、序列化对象或文件。
Redis的其他类型List、Set、Sorted Set 、Hash,它们包含的元素本质上都是string类型。
基本结构
一个String类型的key、value最大上限均是512M。其基本结构如下:
基本语法
Redis中字符串的基本操作如下表所示。
操作 | 语法 | 说明 |
---|---|---|
APPEND | APPEND key value | 如果 key 已经存在并且是一个字符串, APPEND 命令将 value 追加到 key 原来的值的末尾。如果 key 不存在, APPEND 就简单地将给定 key 设为 value ,就像执行 SET key value 一样。 |
BITCOUNT | BITCOUNT key [start] [end] | 计算给定字符串中,被设置为 1 的比特位的数量 |
BITOP | BITOP operation destkey key [key …] | 对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上。 |
DECR | DECR key | 将 key 中储存的数字值减一。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECR 操作。如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。 |
DECRBY | DECRBY key decrement | 将 key 所储存的值减去减量 decrement 。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECRBY 操作。如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。 |
GET | GET key | 返回 key 所关联的字符串值。如果 key 不存在那么返回特殊值 nil 。假如 key 储存的值不是字符串类型,返回一个错误,因为 GET 只能用于处理字符串值。 |
GETBIT | GETBIT key offset | 对 key 所储存的字符串值,获取指定偏移量上的位(bit)。当 offset 比字符串值的长度大,或者 key 不存在时,返回 0 。 |
INCR | INCR key | 将 key 中储存的数字值增一。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。 |
INCRBY | INCRBY key increment | 将 key 所储存的值加上增量 increment 。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCRBY 命令。如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。 |
INCRBYFLOAT | INCRBYFLOAT key increment | 为 key 中所储存的值加上浮点数增量 increment |
MGET | MGET key [key …] | 返回所有(一个或多个)给定 key 的值。如果给定的 key 里面,有某个 key 不存在,那么这个 key 返回特殊值 nil 。因此,该命令永不失败。 |
MGET | MGET key [key …] | 返回所有(一个或多个)给定 key 的值。如果给定的 key 里面,有某个 key 不存在,那么这个 key 返回特殊值 nil 。因此,该命令永不失败。 |
MSET | MSET key value [key value …] | 同时设置一个或多个 key-value 对。MSET 是一个原子性(atomic)操作 |
MSETNX | MSETNX key value [key value …] | 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在。即使只有一个给定 key 已存在, MSETNX 也会拒绝执行所有给定 key 的设置操作。 |
PSETEX | PSETEX key milliseconds value | 这个命令和 SETEX 命令相似,但它以毫秒为单位设置 key 的生存时间,而不是像 SETEX 命令那样,以秒为单位。 |
SET | SET key value [EX seconds] [PX milliseconds] [NX/XX] | 将字符串值 value 关联到 key 。如果 key 已经持有其他值, SET 就覆写旧值,无视类型。对于某个原本带有生存时间(TTL)的键来说, 当 SET 命令成功在这个键上执行时, 这个键原有的 TTL 将被清除。 |
SETBIT | SETBIT key offset value | 设置偏移量值,对使用大的 offset 的 SETBIT 操作来说,内存分配可能造成 Redis 服务器被阻塞。 |
SETEX | SETEX key seconds value | 将值 value 关联到 key ,并将 key 的生存时间设为 seconds (以秒为单位)。 |
SETNX | SETNX key value | SET if Not Exist |
SETRANGE | SETRANGE key offset value | 用 value 参数覆写(overwrite)给定 key 所储存的字符串值,从偏移量 offset 开始。 当生成一个很长的字符串时,Redis 需要分配内存空间,该操作有时候可能会造成服务器阻塞(block)。 |
STRLEN | STRLEN key | 返回 key 所储存的字符串值的长度。当 key 储存的不是字符串值时,返回一个错误。 |
举一些例子:
- MGET & MSET
- 1
- 2
- 3
- 4
- 5
- 6
- SETEX
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- STRLEN
- 1
- 2
- 3
- 4
- 5
- 6
- 7
使用场景-统计用户上线天数
Bitmap 对于一些特定类型的计算非常有效。
假设现在我们希望记录自己网站上的用户的上线频率,比如说,计算用户 A 上线了多少天,用户 B 上线了多少天,诸如此类,以此作为数据,从而决定让哪些用户参加 beta 测试等活动 —— 这个模式可以使用 SETBIT 和 BITCOUNT 来实现。
比如说,每当用户在某一天上线的时候,我们就使用 SETBIT ,以用户名作为 key ,将那天所代表的网站的上线日作为 offset 参数,并将这个 offset 上的为设置为 1 。
举个例子,如果今天是网站上线的第 100 天,而用户 peter 在今天阅览过网站,那么执行命令 SETBIT peter 100 1 ;如果明天 peter 也继续阅览网站,那么执行命令 SETBIT peter 101 1 ,以此类推。
当要计算 peter 总共以来的上线次数时,就使用 BITCOUNT 命令:执行 BITCOUNT peter ,得出的结果就是 peter 上线的总天数。
2. 列表List
list类型其实就是一个每个子元素都是string类型的双向链表。我们可以通过push,pop操作从链表的头部或者尾部添加删除元素。这使得list既可以用作栈,也可以用作队列。
基本结构
基本语法
操作 | 语法 | 说明 |
---|---|---|
BLPOP | BLPOP key [key …] timeout | BLPOP 是列表的阻塞式(blocking)弹出原语.它是 LPOP 命令的阻塞版本,当给定列表内没有任何元素可供弹出的时候,连接将被 BLPOP 命令阻塞. |
BRPOP | BRPOP key [key …] timeout | 它是 RPOP 命令的阻塞版本,当给定列表内没有任何元素可供弹出的时候,连接将被 BRPOP 命令阻塞. |
BRPOPLPUSH | BRPOPLPUSH source destination timeout | BRPOPLPUSH 是 RPOPLPUSH 的阻塞版本,当给定列表 source 不为空时, BRPOPLPUSH 的表现和 RPOPLPUSH 一样。当列表 source 为空时, BRPOPLPUSH 命令将阻塞连接,直到等待超时,或有另一个客户端对 source 执行 LPUSH 或 RPUSH 命令为止。 |
LINDEX | LINDEX key index | 返回列表 key 中,下标为 index 的元素。 |
LINSERT | LINSERT key BEFORE/AFTER pivot value | 将值 value 插入到列表 key 当中,位于值 pivot 之前或之后。当 pivot 不存在于列表 key 时,不执行任何操作。当 key 不存在时, key 被视为空列表,不执行任何操作。如果 key 不是列表类型,返回一个错误。 |
LLEN | LLEN key | 返回列表 key 的长度。 |
LPOP | LPOP key | 移除并返回列表 key 的头元素。 |
LPUSH | LPUSH key value [value …] | 将一个或多个值 value 插入到列表 key 的表头 |
LPUSHX | LPUSHX key value | 将值 value 插入到列表 key 的表头,当且仅当 key 存在并且是一个列表 |
LRANGE | LRANGE key start stop | 返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定 |
LREM | LREM key count value | 根据参数 count 的值,移除列表中与参数 value 相等的元素 |
LSET | LSET key index value | 将列表 key 下标为 index 的元素的值设置为 value |
LTRIM | LTRIM key start stop | 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。举个例子,执行命令 LTRIM list 0 2 ,表示只保留列表 list 的前三个元素,其余元素全部删除。 |
RPOP | RPOP key | 移除并返回列表 key 的尾元素 |
RPOPLPUSH | RPOPLPUSH source destination | 命令 RPOPLPUSH 在一个原子时间内,执行以下两个动作:将列表 source 中的最后一个元素(尾元素)弹出,并返回给客户端。将 source 弹出的元素插入到列表 destination ,作为 destination 列表的的头元素。 |
RPUSH | RPUSH key value [value …] | 将一个或多个值 value 插入到列表 key 的表尾(最右边) |
RPUSHX | RPUSHX key value | 将值 value 插入到列表 key 的表尾,当且仅当 key 存在并且是一个列表。和 RPUSH 命令相反,当 key 不存在时, RPUSHX 命令什么也不做。 |
举一些例子:
- 栈
- 1
- 2
- 3
- 4
- 队列
- 1
- 2
- 3
- 4
- 5
- BLPOP
- 1
- 2
- 3
- 4
- 5
- LINDEX
- 1
- 2
- 3
- 4
使用场景-事件提醒
有时候,为了等待一个新元素到达数据中,需要使用轮询的方式对数据进行探查。
另一种更好的方式是,使用系统提供的阻塞原语,在新元素到达时立即进行处理,而新元素还没到达时,就一直阻塞住,避免轮询占用资源。
对于 Redis ,我们似乎需要一个阻塞版的 SPOP 命令,但实际上,使用 BLPOP 或者 BRPOP 就能很好地解决这个问题。
使用元素的客户端(消费者)可以执行类似以下的代码:
- 1
- 2
- 3
- 4
- 5
- 6
添加元素的客户端(消费者)则执行以下代码:
- 1
- 2
- 3
- 4
3. 哈希表Hash
存储的是一个field与value的映射表,即存储的是一个Map,每一条数据可以看做是key-field-value的格式,field-value对应的是Map的一个键值对。
基本结构
基本语法
操作 | 语法 | 说明 |
---|---|---|
HDEL | HDEL key field [field …] | 删除哈希表 key 中的一个或多个指定域,不存在的域将被忽略 |
HEXISTS | HEXISTS key field | 查看哈希表 key 中,给定域 field 是否存在 |
HGET | HGET key field | 返回哈希表 key 中给定域 field 的值。 |
HGETALL | HGETALL key | 返回哈希表 key 中,所有的域和值 |
HINCRBY | HINCRBY key field increment | 为哈希表 key 中的域 field 的值加上增量 increment |
HINCRBYFLOAT | HINCRBYFLOAT key field increment | 为哈希表 key 中的域 field 加上浮点数增量 increment |
HKEYS | HKEYS key | 返回哈希表 key 中的所有域Field |
HLEN | HLEN key | 返回哈希表 key 中域的数量 |
HMGET | HMGET key field [field …] | 返回哈希表 key 中,一个或多个给定域的值 |
HMSET | HMSET key field value [field value …] | 同时将多个 field-value (域-值)对设置到哈希表 key 中 |
HSET | HSET key field value | 将哈希表 key 中的域 field 的值设为 value |
HSETNX | HSETNX key field value | 将哈希表 key 中的域 field 的值设置为 value ,当且仅当域 field 不存在。 |
HVALS | HVALS key | 返回哈希表 key 中所有域的值 |
HSCAN | SCAN key cursor [MATCH pattern] [COUNT count] | SCAN 命令及其相关的 SSCAN 命令、 HSCAN 命令和 ZSCAN 命令都用于增量地迭代(incrementally iterate)一集元素(a collection of elements) |
举个例子
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
使用场景-存储社交关系
比如新浪的关注列表, 粉丝列表都是由hash实现的。
4. 集合Set
set是string类型的无序集合,集合中最大可以包含(2的32次方-1)个元素。set可以看做是value为空的hash结构,所以不会出现重复的元素。set提供集合的并集(union)、交集(intersection)、差集(difference)的方法,通过这些操作可以很容易的实现sns中的好友推荐和blog的tag功能。
基本结构
基本语法
操作 | 语法 | 说明 |
---|---|---|
SADD | SADD key member [member …] | 将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略. |
SCARD | SCARD key | 返回集合 key 的基数(集合中元素的数量). |
SDIFF | SDIFF key [key …] | 返回一个集合的全部成员,该集合是所有给定集合之间的差集. |
SDIFFSTORE | SDIFFSTORE destination key [key …] | 这个命令的作用和 SDIFF 类似,但它将结果保存到 destination 集合,而不是简单地返回结果集. |
SINTER | SINTER key [key …] | 返回一个集合的全部成员,该集合是所有给定集合的交集. |
SINTERSTORE | SINTERSTORE destination key [key …] | 这个命令类似于 SINTER 命令,但它将结果保存到 destination 集合,而不是简单地返回结果集. |
SISMEMBER | SISMEMBER key member | 判断 member 元素是否集合 key 的成员. |
SMEMBERS | SMEMBERS key | 返回集合 key 中的所有成员. |
SMOVE | SMOVE source destination member | 将 member 元素从 source 集合移动到 destination 集合. |
SPOP | SPOP key | 移除并返回集合中的一个随机元素. |
SRANDMEMBER | SRANDMEMBER key [count] | 如果 count 为正数,且小于集合基数,那么命令返回一个包含 count 个元素的数组,数组中的元素各不相同。如果 count 大于等于集合基数,那么返回整个集合。如果 count 为负数,那么命令返回一个数组,数组中的元素可能会重复出现多次,而数组的长度为 count 的绝对值. |
SREM | SREM key member [member …] | 移除集合 key 中的一个或多个 member 元素,不存在的 member 元素会被忽略. |
SUNION | SUNION key [key …] | 返回一个集合的全部成员,该集合是所有给定集合的并集. |
SUNIONSTORE | SUNIONSTORE destination key [key …] | 这个命令类似于 SUNION 命令,但它将结果保存到 destination 集合,而不是简单地返回结果集. |
SSCAN | SSCAN key cursor [MATCH pattern] [COUNT count] | 详细信息请参考 SCAN 命令. |
举一些例子
- 差集
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 并集
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 交集
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
使用场景-共同好友
- 共同好友、二度好友
- 利用唯一性,可以统计访问网站的所有独立 IP
- 好友推荐的时候,根据 tag 求交集,大于某个 threshold 就可以推荐
5. 有序集合SortedSet
和set一样sorted set也是string类型元素的集合,不同的是每个元素都会关联一个double类型的score,所以sorted set是一个有序的集合。
基本结构
基本语法
操作 | 语法 | 说明 |
---|---|---|
ZADD | ZADD key score member [[score member] [score member] …] | 将一个或多个 member 元素及其 score 值加入到有序集 key 当中. |
ZCARD | ZCARD key | 返回有序集 key 的基数. |
ZCOUNT | ZCOUNT key min max | 返回有序集 key 中, score 值在 min 和 max 之间(默认包括 score 值等于 min 或 max )的成员的数量. |
ZINCRBY | ZINCRBY key increment member | 为有序集 key 的成员 member 的 score 值加上增量 increment. |
ZRANGE | ZRANGE key start stop [WITHSCORES] | 返回有序集 key 中,指定区间内的成员。其中成员的位置按 score 值递增(从小到大)来排序. |
ZRANGEBYSCORE | ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count] | 返回有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。有序集成员按 score 值递增(从小到大)次序排列。 |
ZRANK | ZRANK key member | 返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递增(从小到大)顺序排列。 |
ZREMRANGEBYRANK | ZREMRANGEBYRANK key start stop | 移除有序集 key 中,指定排名(rank)区间内的所有成员。 |
ZREMRANGEBYSCORE | ZREMRANGEBYSCORE key min max | 移除有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。 |
ZREVRANGEBYSCORE | ZREVRANGE key start stop [WITHSCORES] | 返回有序集 key 中, score 值介于 max 和 min 之间(默认包括等于 max 或 min )的所有的成员。有序集成员按 score 值递减(从大到小)的次序排列。 |
ZREVRANK | ZREVRANK key member | 返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递减(从大到小)排序。 |
ZSCORE | ZSCORE key member | 返回有序集 key 中,成员 member 的 score 值。 |
ZUNIONSTORE | ZUNIONSTORE destination numkeys key [key …] [WEIGHTS weight [weight …]] [AGGREGATE SUM/MIN/MAX] | 计算给定的一个或多个有序集的并集,其中给定 key 的数量必须以 numkeys 参数指定,并将该并集(结果集)储存到 destination 。默认情况下,结果集中某个成员的 score 值是所有给定集下该成员 score 值之 和。 |
ZINTERSTORE | ZINTERSTORE destination numkeys key [key …] [WEIGHTS weight [weight …]] [AGGREGATE SUM/MIN/MAX] | 计算给定的一个或多个有序集的交集,其中给定 key 的数量必须以 numkeys 参数指定,并将该交集(结果集)储存到 destination 。默认情况下,结果集中某个成员的 score 值是所有给定集下该成员 score 值之和. |
ZSCAN | ZSCAN key cursor [MATCH pattern] [COUNT count] | 详细信息请参考 SCAN 命令. |
举一些例子
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
使用场景-用户得分排行榜
和Sets相比,Sorted Sets是将 Set 中的元素增加了一个权重参数 score,使得集合中的元素能够按 score 进行有序排列,比如一个存储全班同学成绩的 Sorted Sets,其集合 value 可以是同学的学号,而 score 就可以是其考试得分,这样在数据插入集合的时候,就已经进行了天然的排序。另外还可以用 Sorted Sets 来做带权重的队列,比如普通消息的 score 为1,重要消息的 score 为2,然后工作线程可以选择按 score 的倒序来获取工作任务。让重要的任务优先执行。
带有权重的元素,比如一个游戏的用户得分排行榜