ziplist结构
ziplist即压缩列表,其本质是字节数组。该数组元素可以是字节数组或者整数。
ziplist的结构可以分成五个部分:
- zlbytes:记录了整个ziplist的长度,占4个字节,因此压缩列表最长(2^32)-1字节;
- zltail:记录了ziplist结束的位置,即相对于起始位置的偏移量,占4个字节;
- zllen:记录了压缩列表的元素数目,占两个字节;当压缩列表的元素数目超过了(2^16)-1,即两个字节能够容纳的最大数量。此时需要遍历整个压缩列表才能获取到元素的数目;
- entry:记录了ziplist中的实际元素;
- zlend:记录了ziplist的结尾,占一个字节;
ziplist中的entry结构如下:
- previous_entry_length:记录了压缩列表前一个节点的长度,该属性根据前一个节点的大小不同可以是1个字节或者5个字节;
- encoding:记录了压缩列表的编码方式;
- content: 记录系欸但的值
特点
- 结构紧凑:这是一把双刃剑,访问效率高,同时更新效率低。且数据量较大时,可能导致大量的内存复制(当然数据量太大的时候,redis不会使用ziplist)
- 逆向遍历:由于entry头部previous_entry_length,导致ziplist只能逆向遍历。但是插入数据还是在表头插入。
- 连锁更新:对前一条数据的更新,可能导致后一条数据的prev_entry_length和encoding所需长度的变化,导致连锁更新反应;更新操作的最坏时间是O(N2)。(这种情况发生的概率很小,和中彩票一样)
应用
在redis中,list,zset和hash三种数据结构都直接或者间接使用到了ziplist。
hash:当hash的key值或者value值长度超过64的时候,就会从ziplist变成hashtable
list:list的默认编码是quicklist,quicklist是由双向链表和ziplist组合成的。即整个结构是一个双向链表,链表具体元素内容是ziplist。
zset:当有序集合满足这两个条件:1.元素个数小于128;2.保存的所有元素成员都小于64字节,则会使用ziplist作为存储的数据结构。不满足这两个条件时,就会使用skiplist来存储。