Redis数据结构系列五:QuickList快速链表

Redis3.2引入的QuickList是一种双端链表,每个节点包含ZipList,用于解决ZipList内存连续性问题。QuickList通过控制节点大小和压缩机制,兼顾链表和Ziplist优点,提高内存效率和申请速度。
摘要由CSDN通过智能技术生成

QuickList快速链表

Redis在3.2版本引入了新的数据结构QuickList,它是一个双端链表,可看成LinkedList + ZipList,只不过LinkList链表中的每个节点都是一个ZipList

知识点:

  • 问题1:为什么存在了ZipList,还需要QuickList的存在?
    ZipList虽然节省内存,但申请内存必须是连续空间,如果内存占用较多,申请内存效率很低。所以我们必须限制ZipList的长度和entry大小

  • 问题2:但是我们要存储大量数据,超出了ZipList最佳的上限该怎么办?
    我们可以创建多个ZipList分片存储数据。

  • 问题3:数据拆分后比较分散,不方便管理和查找,这多个ZipList如何建立联系?
    Redis在3.2版本引入了新的数据结构QuickList,它是一个双端链表,只不过链表中的每个节点都是一个ZipList

QuickList的结构示意图如下:
在这里插入图片描述
可以看出,quickList的本质就是双端链表,只不过链表中的节点是ziplist,通过这种形式,将分片的ziplist联系起来。

QuickList配置项

  1. 为了避免QuickList中的每个ZipList中entry过多,Redis提供了一个配置项: list-max-ziplist-size来限制。
  • 如果值为,则代表ZipList的允许的entry个数的最大值

  • 如果值为,则代表zipList的最大内存大小,分5种情况:默认值为-2

    • -1:每个ZipList的内存占用不能超过4kb

    • -2:每个ZipList的内存占用不能超过8kb

    • -3:每个ZipList的内存占用不能超过16kb

    • -4:每个ZipList的内存占用不能超过32kb

    • -5:每个ZipList的内存占用不能超过64kb

  1. 除了控制ZipList的大小,QuickList还可以对节点的ZipList做压缩。通过配置项list-compress-depth来控制。因为链表般都是从首尾访问较多,所以首尾是不压缩的。这个参数是控制首尾不压缩的节点个数:
    • 0:特殊值,代表不压缩

    • 1:标示QuickList的首尾各有1个节点不压缩,中间节点压缩

    • 2:标示QuickList的首尾各有2个节点不压缩,中间节点压缩

    • 以此类推

QuickList数据结构

typedef struct quicklist {
    // quicklist头结点
    quicklistNode *head;
    // quicklist 尾节点
    quicklistNode *tail;
    // 所有的ziplist中的entry总数量
    unsigned long count;        /* total count of all entries in all ziplists */
    // ziplist节点数量
    unsigned long len;          /* number of quicklistNodes */
    // ziplist中entry的上限,默认为-2,和redis中配置的 list-max-ziplist-size 一致
    int fill : QL_FILL_BITS;              /* fill factor for individual nodes */
    // 首尾节点不压缩的个数,若设置为1,则首尾节点各有一节点不压缩;设置为0,则代表所有节点不压缩
    unsigned int compress : QL_COMP_BITS; /* depth of end nodes not to compress;0=off */
    // 内存重分配时的书签数量及数组,一般用不到
    unsigned int bookmark_count: QL_BM_BITS;
    quicklistBookmark bookmarks[];
} quicklist;
typedef struct quicklistNode {
    // 前一个节点(ziplist)指针
    struct quicklistNode *prev;
    // 后一个节点(ziplist)指针
    struct quicklistNode *next;
    // 当前节点ziplist指针
    unsigned char *zl;
    // 当前节点ziplist的字节大小,即zlbytes
    unsigned int sz;             /* ziplist size in bytes */
    // 当前节点ziplist中entry的数量
    unsigned int count : 16;     /* count of items in ziplist */
    // 编码方式:1-ziplist; 2-lzf压缩模式
    unsigned int encoding : 2;   /* RAW==1 or LZF==2 */
    // 数据容器类型:1-其他(预留扩展类型);2-ziplist
    unsigned int container : 2;  /* NONE==1 or ZIPLIST==2 */
    // 是否被压缩:1-说明被解压,将来要重新压缩。
    unsigned int recompress : 1; /* was this node previous compressed? */
    // 测试字段
    unsigned int attempted_compress : 1; /* node can't compress; too small */
    // 预留字段
    unsigned int extra : 10; /* more bits to steal for future usage */
} quicklistNode;

在这里插入图片描述
从上图可看出:
quicklist的每个节点为quickListNode,实际上内容是zipList。

由于compress=1,代表首尾各存在一节点不压缩,中间节点压缩,中间节点压缩为0x4…等乱码,读的时候需要解压缩;写的时候需要重新压缩。

总结

QuickList的特点:——兼具链表和Ziplist的优点

  • 是一个节点为ZipList双端链表

  • 节点采用ZipList,解决了传统链表的内存占用问题

  • 控制了ZipList大小,解决连续内存空间申请效率问题

  • 中间节点可以压缩,进一步节省内存

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值