码迷,mamicode.com
首页 > 其他好文 > 详细

Redis数据结构之压缩列表-ziplist

时间:2019-09-01 16:19:20      阅读:78      评论:0      收藏:0      [点我收藏+]

标签:出现   冗余   com   操作   结构   int   插入   数据   更新   

为了节约内存,在zsethash容器对象元素个数较少时,Redis会采用压缩列表(ziplist)进行存储。

压缩列表是一块连续的内存空间,元素之间紧挨着存储,不存在冗余

一个压缩列表可以包含任意多个节点(entry),每个节点可以保存一个字节数组或者一个整数值

结构

// 压缩列表
struct ziplist<T> {
    int32 zlbytes;        // 压缩列表占用的内存字节数
    int32 zltail_offset;  // 记录表尾节点距离起始地址有多少个字节,用于快速定位最后一个元素
    int16 zllength;       // 压缩列表包含的节点数
    T[] entries;          // 压缩列表包含的所有节点
    int8 zlend;           // 特殊值0xFF,标记压缩列表结尾
} ziplist;

  技术图片

 

// 列表节点
struct entry {
    int<val> prevlen;        // 前一个entry节点的长度
    int<val> encoding;       // 节点的content属性保存的数据的类型
    optional byte[] content; // 节点的值
} entry;

  技术图片

prevlen字段长度是1个字节或5个字节:

  • 前一个节点长度小于254:使用1个字节

  • 前一个节点长度大于等于254:使用5个字节

增加元素

由于ziplist是紧凑存储的,没有冗余空间,所以每一次插入新的元素都需要调用realloc扩展内存。取决于内存分配算法和当前ziplist内存大小,realloc可能重新分配内存空间然后进行拷贝,也可能直接在原地址上进行扩展,不进行拷贝。

如果ziplist占据内存太大,realloc重新分配内存和拷贝会产生很大的消耗,所以ziplist不适合存储大型字符串,存储元素也不宜过多。

级联更新

由于每一个entry都有一个prevlen属性,该属性可能是1个字节或5个字节,取决于前一个元素的长度,所以在前一个元素长度变更,即长度由大于等于254变为小于254或由小于254变为大于等于254时,会导致后一个节点的prevlen属性更新。

如果后一个节点长度是253,则该节点的后续节点也需要更新,依此类推,可能导致后续所有的节点都需要进行更新,这种在特殊情况下产生的连续多次空间扩展操作称之为级联更新

级联更新在最坏情况下需要对ziplist执行N次内存重分配操作,而每次分配的最坏复杂度为O(N),所以级联更新的最坏复杂度为O(N^2)

尽管级联更新的复杂度较高,但是该操作造成性能问题的几率很低:

  • 需要ziplist中恰好有多个连续的、长度介于250~253个字节的节点才可能引发连续更新,该情况很少见

  • 即使出现级联更新,只要被更新的节点数量不多,就不会对性能产生影响

Redis数据结构之压缩列表-ziplist

标签:出现   冗余   com   操作   结构   int   插入   数据   更新   

原文地址:https://www.cnblogs.com/jeemzz/p/11442570.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!