压缩列表(ziplist)是列表键和哈希键的底层实现之一。
当列表键只包含少量列表项,并且每个列表项或者是小整数值,或者是长度比较短的字符串,Redis会使用压缩列表作为列表键的底层实现。
当哈希键只包含少量键值对,并且每个键值对的键和值,要么是小整数值,要么是长度比较短的字符串,Redis会使用压缩列表作为哈希键的底层实现。
压缩列表
压缩列表是Redis为了节约内存而开发的,是由一系列特殊编码的连续内存块组成的顺序型数据结构。一个压缩列表可以包括任意多个节点,每个节点可以保存一个字节数组或者一个整数值。
压缩列表结构:
下图是对压缩列表各个部分的介绍:
如上图所示,压缩列表起始地址的指针为p,zltail为0xb3(十进制为179),即可计算出表尾节点Entry5的地址。
压缩列表节点
节点结构如下
previous_entry_length:记录压缩列表前一个节点的长度。以字节为单位,取值1字节或者5字节。如果前一个字节长度小于254,则previous_entry_length属性的长度为1字节;如果前一个字节长度大于等于254,则previous_entry_length属性的长度为5字节,第一个字节设置为0xFE(十进制254),后四个节点记录前一个节点的长度。
encoding:记录节点content属性所保存数据的类型和长度。
content:保存节点的值。
encoding的取值
- 一字节、两字节或五字节长,值的最高位为00、01或10的是字节数组编码:该编码表示节点的content属性保存着字节数组,数组的长度由编码去除最高两位之后的其他位记录;
- 一字节长,值的最高位以11开头的是整数编码:该编码表示节点的content属性保存着整数值,整数值的类型和长度由编码去除最高两位之后的其他位记录。
连锁更新
特殊场景:在一个压缩列表中,有多个连续的、长度介于250字节到253字节之间的节点e1-eN,如下图所示。
现在,将一个长度大于等于254字节的新节点new设置为头节点,则new节点将成为e1的前置节点,如下图所示。
因为e1节点的previous_entry_length属性为1字节,无法记录新节点new的长度,所以程序将对压缩列表执行空间重分配操作,将previous_entry_length属性从1字节扩展到5字节。
扩展之后e1的长度也大于等于254,e2节点也需要扩展空间,以此类推,直到eN结束。