• Redis数据结构(4):zipList(压缩列表)


    1.概述

      压缩列表是一块连续的内存空间,元素之间紧挨着存储,没有任何冗余空间。

      Redis 为了节约内存空间使用,zset 和 hash 容器对象在元素个数较少的时候,采用压缩列表 (ziplist) 进行存储。3.2.0版本之前, 当 List 容器对象在元素个数较少的时候,也采用压缩列表 (ziplist) 进行存储, 3.2.0之后 List 全部使用 quickList(快速列表).

    2. zipList 基本结构

    struct ziplist<T> {
        int32 zlbytes; // 4 byte, 记录整个压缩列表占用内存字节数,在内存分配或者计算 zlend 的位置时使用
        int32 zltail_offset; // 4 byte, 最后一个元素距离压缩列表起始位置的偏移量,用于快速定位到最后一个节点
        int16 zllength; // 2 byte, 元素个数当属性值 < 65535 时, 属性值表示节点个数, 当属性值 = 65535 时, 真实节点个数需要遍历压缩列表才能计算得出
        T[] entries; // 元素节点列表,节点之间挨个紧凑存储,无冗余空间
        int8 zlend; // 1 byte,标志压缩列表的结束,值恒为 0xFF
    }

     


    压缩列表为了支持双向遍历,所以才会有 ztail_offset 这个字段,用来快速定位到最后一个元素,然后倒着遍历。

    3. entry 基本结构

      每个压缩列表的节点可以保存一个字节数组或者一个整数值.

    struct entry {
        int<var> prevlen; // 前一个 entry 的字节长度, 前一个节点长度小于254字节,则该属性用一个字节表示, 否则(大于等于254字节)用五个字节表示,第一个字节被设置为0xFE(254), 后四个字节表示前一个节点长度
        int<var> encoding; // 记录了节点的 content 属性所保存的数据的类型及长度. 当属性长度为 1 2 5 字节,值最高位为 00 01 10 时表示为字节数组, 数组长度有编码去除最高2位之后的其他位记录, 当属性长度为 1 字节长, 最高位以 11 开头表示是整数编码,整数的类型和长度有编码去除最高2位的其他位表示
        optional byte[] content; // 保存节点的值, 可以是一个字节数组或者整数.
    }

    4. 连锁更新

         当压缩列表有多个连续的且长度介于250字节到253字节的节点,连锁更新才可能被触发.实际中这种情况并不多见.

      其次, zipList 本来就是元素较少的情况下使用的数据结构, 所有更新节点的数量也并不会太多, 对性能造成的影响并不大.

      prevlen 属性的字节长度引起的连锁更新

        有N个节点的长度都是介于250字节到254字节之间, 当增加了一个新的节点 ,该节点的 prevlen 属性值字节长度为五个字节,则下一个节点的 prevlen  属性则变为五个字节, 其总体长度也介于254字节到257字节之间,下下一个节点也发生同样的变化.之后后续节点都要进行更新操作.

    5. 内存分配

      因为 ziplist 都是紧凑存储,没有冗余空间 (对比一下 Redis 的字符串结构)。节点的增删都会影响其结构

      插入一个新的元素就需要调用 realloc 扩展内存。取决于内存分配器算法和当前的 ziplist 内存大小,realloc 可能会重新分配新的内存空间,并将之前的内容一次性拷贝到新的地址,也可能在原有的地址上进行扩展,这时就不需要进行旧内容的内存拷贝.

      当删除一个元素后, 后面的节点则要向前移动

  • 相关阅读:
    Fliptile
    Face The Right Way
    Jessica's Reading Problem
    Subsequence
    Xcode下载途径
    target信息异常
    清除编译缓存DerivedDate
    Xcode快捷键
    Xcode忽略编译警告
    iOS项目Info.plist中关键字汇总
  • 原文地址:https://www.cnblogs.com/virgosnail/p/9542246.html
Copyright © 2020-2023  润新知