1. 作用
压缩列表是列表键和哈希键的底层实现之一
当一个列表键只包含少量列表项,并且每个列表要么就是小整数值,要么就是长度比较短的字符串,那么使用压缩列表作为底层实现
当一个哈希键只包含少量键值对,而且每个键值对的键和值要么是小整数值要是就是长度比较短的字符串,那么底层实现是压缩列表
2. 数据结构
压缩列表是Redis为了节约内存而开发的,是一系列特殊编码的连续内存块组成的顺序型数据结构,一个压缩列表可以包含任意多个节点,每个节点可保存一个字节数组或一个整数值
属性 |
类型 |
长度 |
用途 |
---|---|---|---|
zlbytes | uint32_t | 4字节 | 记录压缩列表的内存字节数,对压缩列表进行内存重分配或计算zlend时使用 |
zltail | uint32_t | 4字节 | 记录压缩列表表尾节点距压缩列表起始地址有多少字节,程序无须遍历整个压缩列表即可确认表尾节点地址 |
zllen | uint16_t | 2字节 | 记录压缩列表的节点数量,当属性值小于UINT16_MAX(65535)即节点数量,其他情况需遍历才可计算出 |
entryX | 列表节点 | 不定 | 压缩列表包含的各个节点 |
zlend | uint8_t | 1字节 | 标记压缩列表末端 |
因为压缩列表是一块内存,所以无法使用指针来确定entry,只能通过偏移量来确定entry,故zltail为尾节点的偏移量
压缩节点
属性 |
用途 |
---|---|
previous_entry_length | 记录压缩列表前一个节点的长度,压缩列表从表尾向表头遍历由此属性实现 |
encoding | 记录节点保存数据类型和长度 |
content | 负责保存节点的值,可以是字节数组或整数 |
3. 解释
为什么需要previous_entry_length?
首先通过zltail得到节点尾,然后通过该属性则可以算出前一个节点的起始地址
每个压缩节点可以保存一个字节数组或一个整数值
字节数组和整数都为范围现在
一般来说字节数组长度小于2^32-1
整数可以是int64,32,16,3,1字节长整数,4位长0-12无符号整数
previous_entry_length
如果前一个节点长度小于254字节,这个值长度为1字节
如果前一个节点长度大于254,这个值长度为5字节
这就意味着,更新节点和新增节点的同时,有可能造成连锁更新,例如10连续的节点都是253长度,突然前面新增一个255长度的节点,那么最前的节点previous_entry_length将变为5字节,那么总字节长度>254,这样该节点后面的节点都将更新,这将影响效率,所幸出现可能不多
encoding
1,2,5字节长,值最高位00,01,10表示为字节数组
1字节长,值最高位11开头,表示整数
1111xxxx,这种无需content属性,因为0-12可以在encoding种保存
content
字节数组或整数