概要

Redis 对外的数据结构包括:字符串(string)、哈希(hash)、列表(list)、集合(set)以及有序集合(zset)。这些数据结构都有对应的 API 可以在客户端使用。如上每一种数据结构在 Redis 内部又对应不只一种内部编码实现。Redis 根据存储的数据选择比较合适的内部编码以实现内存与性能之间的平衡。

键值的数据类型通过 type 命令查看,内部编码通过 object encoding 命令查看:

127.0.0.1> set a b
OK
127.0.0.1> type a
string 
127.0.0.1> object encoding a
"embstr"

字符串(string)

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

字符串类型的内部编码有 3 种:
int:键值8 个字节的长整型
embstr:键值是小于等于 39 个字节的字符串
raw:键值是大于 39 个字节的字符串

哈希(hash)

哈希类型是指键值本身又是一个键值对,形如:value = {{field1=value1},{field2=value2}}

哈希类型的内部编码有 2 种:
ziplist:当哈希类型的元素个数小于 hash-max-ziplist-entries 配置(默认 512 个),同时所有的值都小于 hash-max-ziplist-value 配置(默认 64 字节)时。ziplist 更加节省内存。
hashtable:当不满足 ziplist 条件,ziplist 的读写效率会下降,此时,使用 hashtable 作为内部编码,hashtable 的读写时间复杂度是 O(1)。

开发提醒:为了节省内存,可以将一个大的哈希拆分成若干小的哈希来满足 ziplist 条件。

列表(list)

列表用来存储多个有序的字符串,列表中的每个字符串称之为一个元素,列表中的元素可以重复,一个列表最多可以存储 2^31 - 1 个元素。
列表类型的内部编码有 3 种:
ziplist:当列表类型的元素个数小于 list-max-zip-entries 配置(默认 512 个),同时列表中的每个元素的值都小于 list-max-ziplist-value 配置(默认 64 字节),ziplist 更加节省内存。
linkedlist:当不满足 ziplist 条件,内部编码使用 linkedlist 实现。
quicklist:是一个以 ziplist 为节点的 linkedlist,结合了 ziplist 和 linkedlist 的优点。从 Redis 3.2 版本开始,新增了这种更加优秀的列表内部编码实现。

开发提醒:
lpush + lpop = Stack(栈)
lpush + rpop = Queue(队列)
lpush + brpop = Message Queue(消息队列)

集合(set)

集合用来存储多个字符串,集合中最多可以存储 2^32 -1 个元素。相比列表,集合是无序且不重复的,可以实现多个集合之间取交集,并集,差集。
集合的内部编码有 2 种:
intset:当集合中的元素都是整数且元素个数小于 set-max-intset-entries 配置(默认 512 个),Redis 使用 intset 作为集合的内部编码实现,intset 更加节省内存。
hashtable:当不满足 intset 条件,Redis 使用 hashtable 作为内部编码实现。

有序集合(zset)

有序集合拥有集合的特性,除此之外,有序集合中的元素可以排序,有序集合通过给元素设置一个分数(score)来作为排序依据。
有序集合的内部编码有 2 种:
ziplist:当有序集合的元素个数小于 zset-max-ziplist-entries 配置(默认 512 个),同时每个元素的值小于 zset-max-ziplist-value 配置(默认 64 字节),ziplist 相对比较节省内存。
skiplist:当 ziplist 条件不满足时,有序集合使用 skiplist 作为内部编码。

总结

了解 Redis 的数据结构和内部编码实现有助于在缓存数据时进行合理的设计,选择合适的数据结构进行数据缓存,同时结合内部编码实现的条件分类,做到相对节省内存。

Redis 这种数据结构和内部编码实现分离的设计有两个好处:第一,每一种数据结构可以对应多个内部编码,根据不同的键值选择更加高效的内部编码;第二,内部编码的升级迭代对外部来说是透明的,客户端无感知。


阿白
6 声望0 粉丝