Redis 提供的基础数据结构有五种:

  • 字符串 string
  • 哈希表 hash
  • 列表 list
  • 集合 set
  • 有序集合 zset

全局命令

  • 查看所有键:keys *
    • 会遍历所有键,时间复杂度为 O(n)
    • 如果保存了大量的键,禁止使用
  • 键总数:dbsize
  • 键是否存在:exists key
  • 删除:del key [key ...]
  • 添加过期时间:expire key seconds
    • 返回剩余时间:ttl
  • 键的数据结构:type key

字符串

  • Redis 最基础的数据结构,其它的数据结构都是在字符串之上进行构建
  • 键都是字符串类型
  • 值可以是字符串(包括 JSON、XML)、数字、二进制等等
    • 但不能超过 512 MB

常用命令

  • 设置值:set key value [ex seconds] [px milliseconds] [nx|xx]
    • nx:键必须不存在,才可以设置成功,用于「添加」
    • xx:键必须存在,才可以设置成功,用于「更新」
    • setexsetnx:与 exnx 选项一样
  • 获取值:get key
  • 批量设置值:mset key value [key value ...]
  • 批量获取值:mget key [key ...]

批量操作与 nget 对比:

  • 批量操作:1 次网络时间 + n 次命令时间
  • ngetn 次网络时间 + n 次命令时间

对于值为整数还可以进行自增 incr 和自减 decr 操作。

另外,还有 append 可以追加值(不常用)

1
2
3
4
5
6
> get key
"redis"
> append key world
(integer) 10
> get key
"redisworld"

内部编码结构

字符串内部的数据结构有三种:

  • int:8 个字节的长整形(int64)
  • embstr:小于等于 39 个字节的字符串
  • raw:大于 39 个字节的字符串

可以使用 object encoding key 查看。

经典使用场景

  • 缓存
  • 计数
  • 共享 session
  • 限速

哈希

Redis 的字符串的 key-value 已经很类似常规的哈希了。Redis 的哈希则是值本身又是一个键值对的结构。

常用命令

  • 设置值:hset key field value
    • 成功返回 1,失败返回 0
    • 也有 hsetnx
  • 获取值:hget key field
  • 删除值:hdel key field [field ...]
  • 统计 field 个数:hlen key
  • 判断 field 是否存在:hexists key field
  • 获取所有的 field:hkeys key
  • 批量设置或获取 field-value
    • hmget key field [field ...]
    • hmset key field value [field value ...]

内部编码结构

  • ziplist(压缩列表):元素个数小于 hash-max-ziplist-entries(默认 512),同时所有值长度都小于 hash-max-ziplist-value(默认 64 字节)。ziplist 会比 hashtable 更加紧凑(连续存储),从而节省内存。
  • hashtable:元素多了之后,会使用 hashtable 作为内部实现。但是,hashtable 装载率一般只有一半左右,所以比较耗费内存。

经典使用场景

存储用户信息,例如:用户名、年龄等等。

列表

存储多个有序的字符串。一个列表最多可以存储 2^32-1 个元素。在 Redis 中,可以对列表两端进行插入 pushpop,还可以获取指定范围的元素列表。可以充当栈和队列的角色。

  • lpush + lpop = stack(栈)
  • lpush + rpop = queue(队列)
  • lpush + ltrim = capped collection(有限集合)
  • lpush + brpop = message queue(消息队列)

常用命令

  • 添加:
    • rpush key value [value ...]
    • lpush key value [value ...]
  • 在某个 pivot 元素之前或者之后插入元素:linsert key before|after pivot value
  • 查找指定范围的元素:lrange key start end
  • 获取索引下标的元素;lindex key index
  • 删除:
    • lpop key
    • rpop key
  • 删除指定元素:lrem key count value
    • count > 0:从左往右,删除最多 count 个元素
    • count < 0:从右向左,删除最多 count 绝对值个元素
    • count = 0:删除所有元素
  • 按照索引范围修剪列表:ltrim key start end
  • 修改指定索引下标的元素:lset key index newValue
  • 阻塞式弹出
    • blpop key [key ...] timeout
    • brpop key [key ...] timeout
    • lpoprpop 的阻塞版本
    • 如果列表为空,timeout = 3,客户端要等 3 秒才返回,如果 timeout = 0,那么客户端会一直阻塞等待下去。

内部编码结构

  • ziplist(压缩列表):当列表的元素个数小于 list-max-ziplist-entries 配置(默认512个),同时列表中每个元素的值都小于 list-max-ziplist-value 配置时(默认64字节),Redis 会选用 ziplist 来作为列表的内部实现来减少内存的使用。
  • linkedlist(链表):当列表类型无法满足 ziplist 的条件时,Redis 会使用 linkedlist 作为列表的内部实现。

经典使用场景

  • 消息队列
  • 文章列表

集合

集合(set)类型也是用来保存多个的字符串元素,但和列表类型不一样的是,集合中 不允许有重复元素 ,并且集合中的元素是无序的,不能通过索引下标获取元素。

Redis 除了支持集合内的增删改查,同时还支持多个集合取交集、并集、差集,合理地使用好集合类型,

常用命令

  • 添加元素:sadd key element [element ...],返回成功添加的元素个数
  • 删除元素:srem key element [element ...]
  • 计算元素个数:scard key(内置变量,时间复杂度为 O(1))
  • 判断元素是否在集合中:sismember key element,存在返回 1,否则返回 0
  • 随机从集合中返回指定个数的元素:srandmember key [count],不写数量默认为 1
  • 随机弹出元素:spop key
  • 获取所有元素:smembers key

集合之间的操作:

  • 多个集合之间的交集:sinter key [key ...]
  • 多个集合之间的并集:sunion key [key ...]
  • 多个集合之间的差集:sdiff key [key ...]

将交集、并集、差集的结果保存:

  • sinterstore destination key [key ...]
  • sunionstore destination key [key ...]
  • sdiffstore destination key [key ...]

内部编码结构

  • intset(整数集合):当集合中的元素都是整数且元素个数小于 set-max-intset-entries 配置(默认512个)时,Redis 会选用 intset 来作为集合的内部实现,从而减少内存的使用。
  • hashtable(哈希表):当集合类型无法满足 intset 的条件时,Redis 会使用 hashtable 作为集合的内部实现

经典使用场景

标签(tag)

有序集合

保留了集合不能有重复成员的特性,但不同的是,有序集合中的元素可以排序。它给每个元素设置一个分数(score)作为排序的依据。

数据结构 是否允许重复 是否有序 有序的实现 场景
列表 索引下标 时间轴、消息队列等
集合 标签、社交等
有序集合 分值 排行榜系统、社交

常用命令

  • 添加成员:zadd key score member [score member ...]
    • nx:添加
    • xx:更新
    • ch:返回此次操作后,集合元素和分数变化的个数
    • incr:对 score 做增加,相当于 zincrby

由于增加了排序字段,zadd 的复杂度为 O(log(n))

  • 计算某个成员的分数:zscore key member
  • 计算成员的排名:zrank key member(从低到高),zrevrank 则从高到低
  • 删除成员:zrem key member [member ...]
  • 增加成员的分数:zincrby key increment member
  • 返回指定排名范围的成员:
    • zrange key start end [withscores]
    • zrevrange key start end [withscores]
    • 加上 withscores 会同时返回成员的分数
  • 返回指定分数范围的成员
    • zrangebyscore key min max [withscores] [limit offset count]
    • zrevrangebyscore key max min [withscores] [limit offset count]
  • 返回指定分数的范围的成员个数:zcount key min max
    • minmax 可以使用 -inf+inf 代表无穷小和无穷大
  • 删除指定分数范围的成员:zremrangebyscore key min max

内部编码结构

  • ziplist(压缩列表):当有序集合的元素个数小于 zset-max-ziplist-entries 配置(默认128个),同时每个元素的值都小于 zset-max-ziplist-value 配置(默认64字节)时,Redis 会用 ziplist 来作为有序集合的内部实现,ziplist 可以有效减少内存的使用。
  • skiplist(跳表):当 ziplist 条件不满足时,有序集合会使用 skiplist 作为内部实现,因为此时 ziplist 的读写效率会下降。

经典使用场景

  • 排行榜系统

参考资料

  1. Redis 命令手册
  2. 付磊, 张益军著.Redis开发与运维.机械工业出版社.2017

小结

就是简单复习一下 Redis 的数据结构。