面试题答案
一键面试Redis压缩列表的存储结构
- 整体结构:压缩列表(ziplist)是Redis为了节约内存而设计的一种线性数据结构,它可以包含多个节点(entry),每个节点可以保存一个字节数组或者一个整数值。它是一个连续内存块,由以下几个部分组成:
- zlbytes:4字节,记录整个压缩列表占用的内存字节数。
- zltail:4字节,记录压缩列表表尾节点距离起始地址的偏移量,通过这个偏移量可以快速定位到表尾节点。
- zllen:2字节,记录压缩列表包含的节点数量,但当节点数量超过
2^16 - 1
时,这个字段会被设置为2^16 - 1
,需要遍历整个压缩列表来获取真实的节点数量。 - entryX:一个或多个节点,每个节点保存实际的数据。
- zlend:1字节,特殊值
0xFF
,用于标记压缩列表的结束。
- 节点结构:每个entry节点由以下几部分组成:
- previous_entry_length:记录前一个节点的长度,根据前一个节点长度不同,占用1字节或者5字节。如果前一个节点长度小于254字节,该字段占用1字节;否则,占用5字节,第一个字节为
0xFE
,后4字节记录前一个节点的长度。这个字段使得可以从后往前遍历压缩列表。 - encoding:编码字段,用于描述当前节点保存的数据类型和长度。如果保存的是字符串,encoding会指示字符串长度;如果保存的是整数,encoding会指示整数类型和长度。
- data:实际保存的数据内容,根据encoding字段来确定其类型和长度。
- previous_entry_length:记录前一个节点的长度,根据前一个节点长度不同,占用1字节或者5字节。如果前一个节点长度小于254字节,该字段占用1字节;否则,占用5字节,第一个字节为
提升存储效率的方式
- 紧凑存储:压缩列表采用连续内存空间存储所有节点,减少了内存碎片。相比链表结构,链表每个节点除了数据还需要额外的指针空间来指向前驱和后继节点,而压缩列表将所有信息紧凑地存储在一块连续内存中,大大减少了额外的内存开销。
- 动态编码:对于不同类型和大小的数据,采用不同的编码方式。例如,对于小整数,会直接使用较少字节数来存储,而不是固定使用大整数的存储空间。对于短字符串,也会采用更紧凑的编码方式,只有当数据较大时才会使用更大的编码空间,这样在存储多种类型数据时能根据数据特点合理分配内存,避免不必要的内存浪费。
不同类型数据的存储特点
- 整数存储:对于不同范围的整数,采用不同的编码方式。例如,对于非常小的整数(如
int8_t
范围内),可能只需要1字节存储;稍大一点的整数,会根据其范围采用合适大小的字节数来存储,如int16_t
、int32_t
等。Redis会根据整数的实际范围选择最小的存储方式,尽可能节约内存。 - 字符串存储:对于短字符串,encoding字段会直接编码字符串的长度,然后紧跟着存储字符串内容。如果字符串长度小于64字节,会采用一种紧凑的编码方式;当字符串长度超过一定阈值,会采用不同的编码来存储更长的字符串,依然是在保证能正确存储字符串的前提下,尽量减少内存占用。