对象的类型和编码
Redis使用对象来表示数据库中的键和值,每当我们创建一个键值对,至少创建两个对象
每个对象都由一个redisObject结构表示
类型
键总是一个字符串对象
编码和底层实现
encoding属性记录了对象所使用的编码,也就是这个对象使用了什么数据结构作为对象的底层实现
字符串对象
字符串对象的编码可以是int、raw或者embstr
如果字符串对象保存的是整数值,并且这个整数值可以用long类型来表示,那么字符串对象会将整数值保存在字符串对象结构的ptr属性里,并将字符串对象的编码设置为int
如果保存的是字符串值,并且这个字符串值的长度大于32字节,字符串对象将使用一个简单动态字符串(SDS)保存这个字符串值,并且编码设置为raw
如果保存的是一个小等于32字节的字符串值,那么字符串对象将使用embstr编码的方式来保存这个字符串值
raw编码会调用两次内存分配函数来分别创建redisObject结构和sdshdr结构
embstr编码则通过一次内存分配函数来分配一块连续的空间
使用embstr编码的字符串对象保存短字符串值的好处
long double类型的浮点数在Redis中也是作为字符串值来保存的
编码的转换
int和embstr编码的字符串,条件满足,转换为raw编码
embstr编码的字符串实际上是只读的,修改就会变成raw编码
字符串命令的实现
列表对象
编码可以是ziplist或者linkedlist
ziplist编码的列表使用压缩列表作为底层实现,每个压缩列表节点保存了一个列表元素
linkedlist编码的列表对象使用双端链表作为底层实现,每个双端链表节点都保存了一个字符串对象,而每个字符串对象都保存了一个列表元素
双端链表结构中包含了多个字符串对象,字符串对象是Redis五种类型对象中唯一一种会被其它四种类型对象嵌套的对象
编码转换
上限值可以修改
对于使用ziplist编码的列表对象,任何一个条件不被满足时,就会执行转换操作
列表命令的实现
哈希对象
哈希对象可以是ziplist或者hashtable
hashtable编码的哈希对象使用字典作为底层实现
编码转换
任意一个不被满足就会转换编码格式
哈希命令的实现
集合对象
编码可以是intset或者hashtable
intset编码的集合对象使用整数集合作为底层实现
hashtable编码的集合对象使用字典作为底层实现
字典的每个键都是一个字符串对象,每个字符串对象包含了一个集合元素,而字典的值全部被设置为NULL
编码的转换
集合命令的实现
有序集合对象
编码使用ziplist或者skiplist
ziplist使用压缩列表作为底层实现,每个集合元素使用两个挨在一起的压缩列表节点来保存,第一个节点保存元素的成员,第二个元素则保存元素的分值
压缩列表内的集合元素按分值从小到大进行排序
skiplist编码的有序集合对象使用zset结构作为底层实现
一个zset结构同时包含一个字典和一个跳跃表
zsl跳跃表按分值从小到大保存了所有集合元素,每个跳跃表节点都保存了一个集合元素:
Object属性保存了元素的成员,score属性保存了元素的分值,通过跳跃表可以进行范围型操作
dict字典为有序集合创建了一个从成员到分值的映射,字典中的每个键值对都保存了一个集合元素,键是元素的成员,值是元素的分值。
通过这个字典,O(1)的复杂度查找给定成员的分值
有序集合每个元素的成员都是一个字符串对象,每个元素的分值都是一个double类型的浮点数
跳跃表和字典通过指针来共享相同元素的成员和分值,所以不会产生任何重复成员或者分值,也不会因此而浪费额外的内存
编码的转换
有序集合命令的实现
类型检查与命令多态
Redis中用于操作键的命令基本上可以分为两种类型
一种是可以对任何类型的键执行,比如DEL命令、EXPIRE命令、RENAME命令、TYPE命令、OBJECT命令
另一种命令只能对特定类型的键执行
类型检查的实现
类型特定命令所进行的类型检查是通过redisObject结构的type属性来实现的
多态命令的实现
除了根据值对象的类型判断是否执行命令,还会根据值对象的编码方式,选择正确的命令
比如LLEN命令是多态的,如果对象的编码是ziplist,就要用ziplistLen函数返回长度
如果对象的编码是linkedlist,就要用listLength函数来返回双端链表的长度
实际上,我们可以将DEL、EXPIRE、TYPE等命令也成为多态命令
内存回收
Redis构建了引用计数技术实现的内存回收机制
对象共享
对象的引用计数属性还带有对象共享的作用
Redis会共享值为0到9999的字符串对象
共享对象不单单只有字符串键可以使用,那些在数据结构中嵌套了字符串对象的对象也可以使用
对象的空转时长
最后一个属性lru,记录了对象最后一次被命令程序访问的时间:
OBJECT IDLETIME命令可以打印出给定键的空转时长,这一空转时长就是通过将当前时间减去键的值对象的lru时间计算得出的