Redis底层数据结构

5种基本数据类型

对于每种数据结构,实际上都有自己底层的 内部编码 实现,而且是多种实现。这样 Redis 会在合适的 场景 选择合适的 内部编码,如图所示:

可以看到,每种 数据结构 都有 两种以上 的 内部编码实现。例如 list 数据结构 包含了 linkedlistziplist 两种 内部编码。同时有些 内部编码,例如 ziplist,可以作为多种外部数据结构的内部实现,可以通过 object encoding 命令查询内部编码:

1
2
3
4
127.0.0.1:6379> object encoding hello
"embstr"
127.0.0.1:6379> object encoding mylist
"quicklist"

Redis 这样设计有两个好处:

  • 其一:可以改进内部编码,而对外的数据结构和命令没有影响。例如:Redis3.2 提供的 quicklist,结合了 ziplistlinkedlist 两者的优势,为 列表类型 提供了一种更加高效的内部编码实现。

  • 其二:不同内部编码可以在不同场景下发挥各自的优势。例如 ziplist 比较节省内存,但是在列表元素比较多的情况下,性能会有所下降,这时候Redis会根据配置,将列表类型的内部实现 转换为linkedlist

String底层结构

字符串类型是Redis最基础的数据结构。字符串类型的值实际可以是字符串(简单复杂 的字符串,例如 JSON、XML)、数字(整数、浮点数),甚至是 二进制(图片、音频、视频),但是值最大不能超过 512MB

字符串类型的内部编码有 3 种:

  • int:8个字节的长整型。

  • embstr:小于等于39个字节的字符串。

  • raw:大于39个字节的字符串。

Redis 会根据当前值的 类型长度 决定使用哪种内部编码实现。

Hash底层结构

大部分编程语言都提供了哈希(hash)类型,它们的叫法可能是 哈希字典关联数组。在 Redis 中,哈希类型是指键值本身又是一个键值对结构。

压缩列表(ziplist)

当哈希类型元素个数 小于 hash-max-ziplist-entries 配置(默认 512 个)、同时所有值都小于 hash-max-ziplist-value 配置(默认 64 字节)时,Redis会使用ziplist 作为哈希的内部实现,ziplist使用更加紧凑的结构实现多个元素的连续存储,所以在节省内存方面比hashtable更加优秀.

哈希表(hashtable)

当哈希类型无法满足 ziplist 的条件时,Redis会使用hashtable作为哈希的内部实现,因为此时 ziplist读写效率 会下降,而 hashtable 的读写时间复杂度为 O(1)。

下面的示例演示了哈希类型的内部编码,以及相应的变化。

当field个数比较少,且没有大的value时,内部编码为ziplist

1
2
3
4
127.0.0.1:6379> hmset hashkey f1 v1 f2 v2
OK
127.0.0.1:6379> object encoding hashkey
"ziplist"

当有value大于64字节时,内部编码会由 ziplist 变为 hashtable

1
2
3
4
127.0.0.1:6379> hset hashkey f3 "one string is bigger than 64 byte...忽略..."
OK
127.0.0.1:6379> object encoding hashkey
"hashtable"

当field个数超过 512,内部编码也会由 ziplist 变为hashtable

1
2
3
4
127.0.0.1:6379> hmset hashkey f1 v1 f2 v2 f3 v3 ... f513 v513
OK
127.0.0.1:6379> object encoding hashkey
"hashtable"

List底层结构

列表(list)类型是用来存储多个有序的字符串。在Redis中,可以对列表的两端进行 插入(push)和 弹出(pop)操作,还可以获取 指定范围元素列表、获取 指定索引下标元素 等, 一个列表最多可以存储 2^32 - 1 个元素。

列表是一种比较灵活的数据结构,它可以充当 队列 的角色,在实际开发上有很多应用场景。

列表类型的内部编码有两种:

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

  • linkedlist(链表)
    当列表类型无法满足ziplist的条件时, Redis会使用 linkedlist 作为列表的内部实现。

Set底层结构

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

集合类型的内部编码有两种:

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

参考

深入剖析Redis系列(一) - Redis入门简介与主从搭建

深入剖析Redis系列(二) - Redis哨兵模式与高可用集群

深入剖析Redis系列(三) - Redis集群模式搭建与原理详解

深入剖析Redis系列(四) - Redis数据结构与全局命令概述

深入剖析Redis系列(五) - Redis数据结构之字符串

深入剖析Redis系列(七) - Redis数据结构之列表

深入剖析Redis系列(八) - Redis数据结构之集合