Redis - 底层数据结构
#
简介
Redis 的底层数据结构主要以下几种:
- SDS(Simple Dynamic String, 简单动态字符串)
- ZipList(压缩列表)
- QuickList(快表)
- Dict(字典)
- IntSet(整数集合)
- ZSkipList(跳跃表)
简单动态字符串
在 Redis 中,并不会直接使用 C 语言自带的字符串结构作为实际的存储结构,而只是将字符串作为字面量使用,大多数情况使用自定义的 SDS 来表示字符串。
SDS 主要用于储存 Redis 的默认字符串表示、AOF 模块中的 AOF 缓冲区、客户端状态输入缓冲区。它的定义如下:
struct sdshdr {
int len; // 记录 buf 数组中已使用字节的数量,等于 SDS 所保存的字符串的长度
int alloc; // 记录 buf 数组中未使用字节的数量
char buf[]; // 字节数组,用于保存字符串
};
优点
相对于 C 语言的字符串实现,Redis 实现的 SDS 有以下优点:
- 通过记录
len
属性,实现常数级时间复杂度获取字符串长度 - 通过检查
len
属性,避免字符串在修改时出现缓冲区溢出的情况 - 通过记录
len
属性和alloc
属性,对于修改字符串实现了空间预分配和惰性空间释放 - 实际存储的
buf
是一个字节数组,可以实现 SDS 安全操作二进制数据 - SDS 仍然以
\0
作为字符串结尾的标识,这样可以重用 C 语言字符串的部分函数
空间预分配
当 SDS 修改时需要扩展空间大小,程序不仅会为 SDS 扩展修改所需的空间,还会为 SDS 分配额外的未使用空间。这额外空间一般是 len
的大小,最大不超过 1MB。
这样可以减少连续执行字符串增长操作所需的内存重分配次数。
惰性空间释放
当 SDS 修改时需要缩短空间大小,程序并不会立即将多出来的空间进行空间重分配,而是使用 alloc
属性将这些空间大小记录下来,以待后续使用。
而且 SDS 也提供手动释放未使用空间的方法,这样可以避免浪费内存。
压缩列表
ZipList 实际是由一系列特殊编码的连续内存块组成的顺序型数据结构,是 Hash 类型底层实现的一种方式。
结构
一个 ZipList 结构由 zlbytes
、zltail
、zllen
、entries
、zlend
这些属性组成,这些属性顺序连接在一起组成了 ZipList:
zlbytes
用于记录 ZipList 占用的内存字节数,在对 ZipList 进行内存重分配或者计算 zlend
的位置时使用。
zltail
记录了 ZipList 表尾结点距离 ZipList 的起始地址有多少个字节,Redis 可以通过这个属性快速确定表尾结点的地址。
zllen
记录了 ZipList 包含的结点数量,当这个属性小于 UINT16_MAX
(65535) 时,这个值就是 ZipList 包含的结点数量;这个属性大于 UINT16_MAX
时,则需要遍历整个 ZipList 才能计算得出结点数量。一个 ZipList 可以包含任意多个结点,每个结点可以保存一个字节数组或者一个整数值。
zlend
定义了特殊值 OxFF
用于标记 ZipList 的末端。
优点
ZipList 是一种节省内存的列表结构,对于普通的数组来说,其中每个元素占用的空间大小取决于最大的元素,而 ZipList 解决了这个问题。
因此,ZipList 在设计的时候,尽量让每个元素按照实际的内容大小存储&#
还没有评论,来说两句吧...