redis-压缩列表
压缩列表是列表键和哈希键的底层实现之一。当列表和哈希表满足一定条件的时候,底层将采用压缩列表实现,具体将在之后介绍redis对象的时候详细讲解。
压缩列表的定义
压缩列表是Redis为了节约内存的使用而开发的。压缩列表使用一块经过特殊编码的连续内存。压缩列表包括多个节点,每个节点可以是一个字节数组或一个整数值。
图1
图1是压缩列表的组成部分,各个字段解释如下:
属性 | 类型 | 长度 | 用途 |
---|---|---|---|
zlbytes | uint32_t | 4字节 | 记录整个压缩列表占有的字节数 |
zltail | uint32_t | 4字节 | 记录压缩列表表尾节点距离压缩列表起始地址有多少个字节 |
zllen | uint16_t | 2字节 | 记录了压缩列表包含的节点数量:当这个属性值小于65535时,这个值就是包含的节点数量,否则需要遍历列表才能计算包含的节点数量 |
entryX | 列表节点 | 不定 | 压缩列表包含的节点,节点的长度由节点保存的内容决定 |
zlend | uint8_t | 1字节 | 特殊值0xFF(10进制255),用于标记压缩列表的末端 |
压缩列表节点的定义
压缩列表节点可以保存一个字节数组或者一个整数。压缩列表节点的组成部分如图2示。
图2
previous_entry_length表示的是前一个节点长度,以字节为单位。previous_entry_length属性的长度可以是1字节或者5字节。
- 如果前一节点的长度小于254字节,那么previous_entry_length的长度为1字节,前一节点的长度就保存在这1个字节里。例如对于图3,指示前一节点的长度为8字节。
图3
- 如果前一节点的长度大于等于254字节,那么previous_entry_length的长度为5字节,其中第一个字节为0xFE,后四个字节用于保存前一个节点的长度。例如对于图4,指示前一节点的长度为257(0X0101)字节。
图4
因为previous_entry_length记录了前一节点的长度,所以程序可以根据当前节点的指针计算出前一节点的指针,从而可以从尾部向头部遍历。
encoding属性记录了节点content属性所保存数据的类型和长度。
- 值的最高位分别为00、01、10,长度分别是1字节、2字节、5字节,这种编码方式表示content属性记录的是字节数组,字节数组的长度为encoding去除最高2位后的其他位记录(5字节的只有后4个字节用来记录长度)。如下表示:(注:-表示空的,a、b、c、d、x代表实际有效的2进制数字)
编码 编码长度 content保存的值 00bbbbbb 1字节 长度小于等于63的字节数组 01bbbbbb xxxxxxxx 2字节 长度小于等于2^14^-1的字节数组 10—— aaaaaaaa bbbbbbbb cccccccc dddddddd 5字节 长度小于等于2^32^-1的字节数组 - 值的最高位为11开头的是整数编码,整数的类型由编码除去最高二位的其他位记录。如下表示:
编码 编码长度 content保存的值 11000000 1字节 int16_t类型的整数 11010000 1字节 int32_t类型的整数 11100000 1字节 int64_t类型的整数 11110000 1字节 24位有符号整数 11111110 1字节 8位有符号整数 1111xxxx 1字节 这一编码方式没有content属性,xxxx本身就记录了0-15的值 content属性记录实际的节点值,有了encoding编码方式,content属性就很好理解了。举两个例子,图5示一个长度为11的字节数组节点。其中编码方式为00001011。
图5
图6示一个类型为int16_t类型的整数。其中编码方式为11000000。
图6
连锁更新
对于图1,假设节点entry1到entryN的长度都介于250-253字节长度之间,那么所有节点的previous_entry_length的长度都是1个字节。若此时在entry1之前插入一个长度大于等于254字节的节点,因为entry1的previous_entry_length长度只有一个字节,因此程序需要对压缩列表空间进行再分配,并将entry1的previous_entry_length长度从原来的1字节扩展为5字节。
entry1扩展后增加了4个字节,它的长度介于254-257,而entry2的previous_entry_length无法保存该长度的值,这将再一次触发再分配动作。更进一步,将引发雪崩般的效应。此所谓连锁更新。因为每次内存重分配的时间复杂度为O(N),所以连锁更新的时间复杂度为O(N^2^)。
幸运的是,这种情况实际上并不常见,我们可以放心的使用。
参考:
- Redis设计与实现. 黄健宏著