文章目录
基于内存实现
由于是存储在内存中的数据库, 不会被磁盘 IO 影响到数据读写的效率, 也就是说减少了磁盘 IO 的开销
高效的数据结构
SDS
1. 字符串长度处理
存储了 len 这个字段以快速获取长度
2. 内存重新分配
-
空间预分配
分配必须的空间之外, 还会额外分配未使用空间
len < 1M, 额外分配 len 长度的空间
len > 1M, 额外分配 1M 长度的空间
-
惰性空间释放
使用完毕的空间, 不会直接进行回收, 而是使用 free 字段将多余的空间存储下来, 后续使用空间可以先从 free 中获取, 减少内存分配
3. 不需要处理二进制安全 ‘\0’
根据 len 来判断 字符串 结束, 不需要额外的处理来判断字符串结束
双端链表
1. 前后节点
listNode 中存储 prev 和 next 加快获取前后节点的速度
2. 头尾节点
list 中存储 head 和 tail 方便正序或者逆序遍历链表
同时双端节点的处理时间降至 O(1)
3. 链表长度
同 SDS 的 len, O(1) 获取长度
压缩列表
优化链表存储时, 每次都需要存储是都需要保存一些重复的信息, 如头节点, 前后节点, 这样会浪费空间, 反复申请释放也容易导致内存碎片化
而压缩列表操作是通过指针与解码出的偏移量进行的, 效率更高
同时内存是连续分布的, 遍历速度快
字典
哈希表原理, O(1)时间查找和插入
跳表
多级索引加快效率
合理的数据编码
embstr 和 raw 的区别
embstr: 保存比较短的字符串, 只需要申请一次内存分配函数, 因为在创建 RedisObject 和 sdshdr 时是直接一起创建的连续内存, 释放一次内存
raw: 保存比较长的字符串, 使用时需要为 RedisObject 和 sdshdr 都申请一次内存分配函数, 需要释放两次内存
Redis 中 embstr 和 raw 编码的界限
1. 结论
在 redis 4.0 之前, 代码创建的逻辑是与REDIS_ENCODING_EMBSTR_SIZE_LIMIT = 39
进行比较,如果小于 39 的话创建的是 embstr ,否则为 raw
但在 5.0 中 修改成了当小于 44 个字节的时候使用 embstr,大于 44 的时候为 raw
2. 原因创建 stringObject 的逻辑
redisObject, 需要占据 16 个字节
typedef struct redisObject {
unsigned type:4; //对象类型(4位=0.5字节)
unsigned encoding:4; //编码(4位=0.5字节)