Redis学习笔记:数据结构

Redis的对象

Redis对象包含字符串对象、列表对象、哈希对象、集合对象和有序集合对象这五种类型的对象,针对不同的使用场景,为对象设置多种不同的数据结构实现,从而优化对象在不同场景下的使用效率。

除此之外,Redis的对象系统还实现了基于引用计数技术的内存回收机制,当程序不再使用某个对象的时候,这个对象所占用的内存就会被自动释放;另外,Redis还通过引用计数技术实现了对象共享机制,这一机制可以在适当的条件下,通过让多个数据库键共享同一个对象来节约内存。

实现

Redis中的每个对象都由一个redisObject结构表示,该结构中和保存数据有关的三个属性分别是type属性、encoding属性和ptr属性:

cpp 复制代码
typedef struct redisObject{
    //  类型
    unsigned type:4;
    //  编码
    unsigned encoding:4;
    //  指向底层实现数据结构的指针
    void *ptr;
    //  ...
} robj;

type:对象的type属性记录了对象的类型,对于Redis数据库保存的键值对来说,键总是一个字符串对象,而值则可以是字符串对象、列表对象、哈希对象、集合对象或者有序集合对象的其中一种。

encoding:通过encoding属性来设定对象所使用的编码,而不是为特定类型的对象关联一种固定的编码,极大地提升了Redis的灵活性和效率,因为Redis可以根据不同的使用场景来为一个对象设置不同的编码,从而优化对象在某一场景下的效率。

ptr:对象的ptr指针指向对象的底层实现数据结构,而这些数据结构由对象的encoding属性决定。encoding属性记录了对象所使用的编码,也即是说这个对象使用了什么数据结构作为对象的底层实现。

以下是Redis对象不同编码时对应的数据结构,以及使用的场景:

|--------|------------|-----------------------|----------------|
| 对象 | 编码 | 数据结构 | 使用场景 |
| 字符串对象 | int | long类型 | long字符串 |
| 字符串对象 | embstr | embstr类型的简单动态字符串(SDS) | 32字节以内短字符串 |
| 字符串对象 | raw | 简单动态字符串(SDS) | 大于32字节的字符串 |
| 列表对象 | ziplist | 压缩列表 | 列表项少且元素短 |
| 列表对象 | linkedlist | 双端链表 | 列表项多或元素长 |
| 哈希对象 | ziplist | 压缩列表 | 键值对少且元素短 |
| 哈希对象 | hashtable | 字典 | 键值对多或元素长 |
| 集合对象 | intset | 整数集合 | 元素都是整数且不超过512个 |
| 集合对象 | hashtable | 字典 | 元素不都是整数或超过512个 |
| 有序集合对象 | ziplist | 压缩列表 | 元素少且短 |
| 有序集合对象 | skiplist | 跳跃表+字典 | 元素多或长 |

embstr编码是专门用于保存短字符串的一种优化编码方式,这种编码和raw编码一样,都使用redisObject结构和sdshdr结构来表示字符串对象,但raw编码会调用两次内存分配函数来分别创建redisObject结构和sdshdr结构,而embstr编码则通过调用一次内存分配函数来分配一块连续的空间。由于内存中找到一块小的连续空间更容易,所有embstr编码更适合保存短字符串。embstr编码的优势是字符串对象的创建或清理时,内存分配或释放函数只需调用一次,而且连续的内存空间能够更好地利用缓存带来的优势。

可以通过TYPE命令查看键对应的值对象的类型,OBJECT ENCODING命令查看值对象的编码。

编码转换

随着对象增删改的操作的进行,当对象满足编码转换的条件时,Redis会进行编码转换,修改底层的数据结构,以适应新的环境,一般这种转换只会由优化类型转换为通用类型,而不会反过来,比如:int或embstr转换为raw,ziplist转换为linkedlist等。编码转换的条件可以通过参数修改。

内存回收

因为C语言并不具备自动内存回收功能,所以Redis在自己的对象系统中构建了一个引用计数技术实现的内存回收机制,通过这一机制,程序可以通过跟踪对象的引用计数信息,在适当的时候自动释放对象并进行内存回收。

对象共享

对象的引用计数属性还带有对象共享的作用。Redis会在初始化服务器时,创建值为0到9999的字符串对象,当需要用到这些对象时,会将对将被共享的值对象的引用计数加一,而不是新创建对象。Redis只会共享整数字符串对象,因为判断其它对象是否相等的成本更高。

对象的空转时长

对象的空转时长是指对象有多久没被访问,对象会记录自己的最后一次被访问的时间,这个时间可以用于计算对象的空转时间。服务器内存不足时空转时间较长的对像会被优先释放。

参考

《Redis设计与实现》

相关推荐
摇滚侠1 天前
Redis 秒杀功能 超卖问题 一人一单问题 分布式锁 精彩!精彩!
redis·分布式·bootstrap
Emily呀1 天前
【无标题】
redis
愈努力俞幸运1 天前
function calling与mcp
android·数据库·redis
IronMurphy1 天前
Redis拷打第一讲
数据库·redis·缓存
楠枬1 天前
Redis 事务
数据库·redis·缓存
摇滚侠1 天前
Redis 查询接口加缓存 缓存雪崩 缓存穿透 缓存击穿 精彩!精彩!
redis·缓存
Mr. zhihao2 天前
[特殊字符] 从 Redis 缓存穿透到布隆过滤器,再到布谷鸟过滤器:一次穿透防护的进化之旅
数据库·redis·缓存
@小匠2 天前
Redis 7 持久化机制
数据库·redis·缓存
phltxy2 天前
Redis 核心数据类型之 String 详解
数据库·redis·bootstrap
码哥字节2 天前
开多个 Agent 后 Claude Code 账单翻了 4 倍,一个配置解决了
redis·性能