redis有五种主要的数据类型,还有几个特殊的数据类型,redis为了保证效率与安全等各方面性能,每一种数据类型底层都由多种编码格式构成,可以互相转换

字符串对象 STRING

Redis 字符串命令用于管理 Redis 中的字符串值。字符串对象的encoding有三种格式:

分别是int、raw、embstr。

如果一个字符串对象保存的是整数值,并且这个整数可以用long类型标识,那么字符串对象会将整数值保存在ptr属性中,并将encoding设置为int。如:

127.0.0.1:6379> set number 1234
OK
127.0.0.1:6379> object encoding number
"int"
127.0.0.1:6379>

 如果字符串保存的是一个字符串值,并且这个字符串的长度大于44字节,那么字符串对象将使用一个简单动态字符串(SDS)来保存这个字符串值,并将对象的编码设置为raw。

简单动态字符串(SDS):redis底层是由C语言实现,但是redis并没有选择使用传统的C语言字符串而是自己创建了一种性能更为优秀的名为简单动态字符串(SDS)的抽象类型。

对比 C 语言字符串,SDS 具有如下优点:

  1. 常数复杂度获取字符串长度。
  2. 杜绝缓冲区溢出。
  3. 减少修改字符串长度时所需的内存重分配次数。
  4. 二进制安全。
  5. 兼容部分 C 字符串函数。

 下边这个例子是45个字节:

127.0.0.1:6379> set str "Spring Boot lets you externalize your configu"
OK
127.0.0.1:6379> strlen str    (查看字符串长度)
(integer) 45
127.0.0.1:6379> object encoding str   
"raw"
127.0.0.1:6379>

 如果这个字符串小于45字节,那么字符串对象将使用embstr编码的方式来保存这个字符串值了。

我这里字符编码格式还是raw的原因是3.2版本之前是大于39字节为raw,我的版本是3.2版本之前的,但是确实可以看到embstr这种编码格式。

127.0.0.1:6379> set str "Spring Boot lets you externalize your config"
OK
127.0.0.1:6379> strlen str
(integer) 44
127.0.0.1:6379> object encoding str
"raw"
127.0.0.1:6379> set str "a"
OK
127.0.0.1:6379> strlen str
(integer) 1
127.0.0.1:6379>  object encoding str
"embstr"
127.0.0.1:6379>

embstr 编码是专门用于保存短字符串的一种优化编码方式,它具有如下优点:

  • embstr 编码将创建字符串对象所需的内存分配次数从 raw 编码的两次降低为一次
  • 释放 embstr 编码的字符串对象只需要调用一次内存释放函数,而释放 raw 编码的字符串对象需要调用两次内存释放函数
  • 因为 embstr 编码的字符串对象的所有数据都保存在一块连续的内存里面,所以这种编码的字符串对象比起 raw 编码的字符串对象能够更好地利用缓存带来的优势

哈希对象 HASH 

Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。

每个哈希键中可以存储多达 40 亿个字段值对。

哈希对象的编码有两种,分别是:ziplist、hashtable。

当哈希对象保存的键值对数量小于 512,并且所有键值对的长度都小于 64 字节时,使用压缩列表存储;否则使用 hashtable 存储。这两个条件是可以修改的。见 hash-max-ziplist-value 和 hash-max-ziplist-entries。

ziplist:ziplist 是一个经过特殊编码的双向链表,它的设计目标就是为了提高存储效率。ziplist 可以用于存储字符串或整数,其中整数是按真正的二进制表示进行编码的,而不是编码成字符串序列。它能以 O(1) 的时间复杂度在表的两端提供 pus h和 pop 操作。其实就是个双向链表。

 我们可以看到当字节数大于64之后,编码格式变为了hashtable,没使用极端情况64字节演示,可以自行实验。而且当键值对数量大于512之后编码格式也会变成hashtable。

HEX redis 中存数据变成了 redis存储数据格式_HEX redis 中存数据变成了

列表对象 LIST

Redis 列表是按插入顺序排序的字符串列表。可以在列表的头部(左边)或尾部(右边)添加元素。

列表可以包含超过 40 亿 个元素 ( 232 - 1 )

列表对象的编码有两种: ziplist 和 linkedlist。

当列表对象可以同时满足以下两个条件时,列表对象使用 ziplist 编码:

  1. 列表对象保存的所有字符串元素的长度都小于 64 字节
  2. 列表对象保存的元素数量小于 512 个
  3. 如果不能同时满足这两个条件,列表对象则使用 linkedlist

以上两个条件的是可以修改的,见 list-max-ziplist-value 和 list-max-ziplist-entries。


集合对象 SET

Redis 的 Set 是 string 类型的无序集合。

集合成员是唯一的,这就意味着集合中没有重复的数据。

在 Redis 中,添加、删除和查找的时间复杂都是 O(1)(不管 Set 中包含多少元素)。

集合中最大的成员数为 232 – 1 (4294967295), 每个集合可存储 40 多亿个成员。

集合对象的编码有两种:intset 和 hashtable。

当集合对象可以同时满足一下两个条件时,对象使用 intset 编码:

  1. 集合对象保存的所有元素都是整数值
  2. 集合对象保存的元素数量不超过 512 个

如果不能满足这两个条件的集合对象需要使用 hashtable 编码。其中第二条件可以修改配置文件修改:set-max-intset-entries。


有序集合对象 ZSET

Redis 有序集合和集合一样也是 string 类型元素的集合,且不允许重复的成员。

不同的是每个元素都会关联一个 double 类型的分数。Redis 正是通过分数来为集合中的成员进行从小到大的排序。

有序集合的成员是唯一的,但分数 ( score ) 却可以重复。

大概使用方式就是这样:

HEX redis 中存数据变成了 redis存储数据格式_redis_02

 

集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。

集合中最大的成员数为 232 – 1 ( 4294967295 ) , 每个集合可存储 40 多亿个成员。

有序集合的编码也有两种:ziplist 和 skiplist(跳跃表)。

当有序集合对象可以同时满足以下两个条件,对象使用 ziplist 编码:

  1. 有序集合保存的元素数量小于 128 个
  2. 有序集合保存的所有元素成员的长度都小于 64 字节

不能同时满足以上两个条件的有序集合将使用 skiplist 编码。且上述两个条件可以通过配置文件修改,参数见:zset-max-ziplist-entries 和 zset-max-ziplist-value