redisObject
大家都知道我们在使用
redis
的时候有五种数据类型可以使用分别是string
,list
,hash
,set
,sorted_set
,但是这五种数据可以看成是已经封装好的数据结构,就像Java里面的ArrayList
,我们使用的是ArrayList
但是它底层使用的数据结构还是数组.所以我们现在需要了解的就是redis
中我们使用的五种数据类型底层是什么数据结构.
首先我们需要知道的是,redis中所有的对象都是用一个同一个对象来表示的,这个对象就是**redisObject
**,它的定义如下
typedef struct redisObject{
//类型,
unsigned type:4;
//编码
unsigned encoding:4;
//指向底层数据结构的指针
void *ptr;
//引用计数,该属性与数据无关
int refcount;
//记录最后一次被程序访问的时间,该属性与数据无关
unsigned lru:22;
}robj
1.type属性
type
字段记录了当前对象的类型,就是我们说的那五种类型string
,list
,hash
,set
,sorted_set
.其实大家要是对redis
的命令比较了解的话,就知道有一个type
命令
其实这个type
命令就是获取当前redisObject
的type属性
2.encoding 和 ptr 属性
ptr
就是指针,指向该对象的底层实现.
encoding
属性表明就是我们这片文章要讲的底层数据类型,类型如下
其实大家对动态字符串
,双端(向)链表
等可能已经比较了解了,但是对压缩列表(ziplist)
等可能不是很了解.为了证明这些底层数据结构的存在我们可以实际的使用redis
来试一下.使用OBJECT ENCODING key
命令就可以找到对应对象的底层实现
大家可以看到,我是使用了string
这种类型,设置了3个键值对,然后调用OBJECT ENCODING key
命令分别查看底层实现,发现都不同,而且这三种在我们上面的表中都出现了.
这说明了一种类型的数据结构底层实现可以有多种.
下面我们就来看看,每种类型分别有哪些不同的实现方式
3.对使用多种数据结构的思考
可以看到,redis
中每种数据类型都有不同底层实现,那么为什么要大费周章的这样做呢? 简单一点不好吗?
在我看来,这是由于redis
的特殊性造成的,redis
是内存数据库,所有的数据都存放在内存中,而内存作为一种十分十分珍贵的计算机资源,我们必须好好的利用它,使得它尽可能多的存储数据
(一)string的底层实现
有上面的图我们可以看到,string
有三种具体的是实现方式分别是int
,embstr
,raw
1.int–使用整数值实现的字符串对象
还记得我们的string
可以实现计数器的功能吗,这就是因为当我们对一个string
类型的数据设置的值为数字的时候Redis就使用int
这种类型来作为它的底层实现,但是我们还是有一点小小的细节需要注意
- 虽然这种类型叫做
int
,但是它底层是用C语言的long来表示的. - 正是因为使用long来存,所以
int
类型表示的数值大小是有限制的,当超过了范围,就会自动转成raw
或者是embstr
下面我们验证一下是否如此(需要注意的是 int 的最大值为 2147483647,long的最大值为 9223372036854775807)
验证第一条规则: 可以看到,我们设置的数值超过了int的最大值(64位机器下),但是结果依然是int
验证第二条规则:我们先设置了long的最大值,发现结果不变,但是我们+1,超过了边界值,就变成了embstr
2.sds-动态字符串
string
底层还有两种实现,不过他们都是基于**sds(simple dynamic string)**来实现的.所以先来了解一下sds
.
1.Redis中的SDS简介
C语言中没有string,但是Redis也没有使用C语言中原生的char数组,而是在此基础上自己构建了一种Simple Dynamic String SDS来表示string.
2.SDS的优越性
上面讲了redis中的string使用的是SDS,那么为什么要构建一种新的SDS来表示String,而不是使用char数组呢?
其实这是为了解决char数组中的一些痛点.那么SDS解决了哪些痛点呢?
- SDS获取string长度的时间复杂度是 O(1),而char数组是 O(N)
- SDS不会造成缓存区溢出问题.
- SDS不仅能保存文本数据,而且可以保存二进制数据
3.SDS底层实现
/* Note: sdshdr5 is never used, we just access the flags byte directly.
* However is here to document the layout of type 5 SDS strings. */
// 注意:sdshdr5从没没有被使用过
struct __attribute__ ((__packed__