• redis数据结构(五) quik list


    1.为什么会定义quiklist

      前面已经讲过了redis中list的一个实现ziplist,由于ziplist将所有数据保存在一片连续的内存空间中所以使用ziplist不会照成内存碎片,但是也正是这样导致了ziplist不适合存储过多的数据,因为这会对重新申请内存空间和复制元素造成很大压力.为了存储大量数据,必须使用一个新的数据结构来保存.普通的linkedlist虽然也可以保存大量的数据,但是linkedlist中的每个节点中都保存了前一个节点和后一个节点的指针,而且每个节点都会单独是申请内存空间,这导致了内存使用率较低和内存碎片严重,为了兼顾内存使用率,和解决碎片问题,redis使用了一个这种的办法解决这两个问题,redis中引入了一个新的数据结构quiklist.

      quiklist本质上是inkedlist和ziplist的结合体.quiklist的整体上是一个linkedlist,但是linkedlist中的每个节点都是一个ziplist.就是把linkedlist分段存储,每一段都是一个ziplist.

    2.内部结构

      2.1 quicklist

    struct quicklist {
        quicklistNode* head; //头节点指针
        quicklistNode* tail; //尾节点指针
        long count; // 元素总数
        int nodes; // ziplist 节点的个数
        int compressDepth; // LZF 算法压缩深度
    }

      为了方便从前面和后面插入,遍历链表,quiklist中保存了头节点和尾节点的指针.

      count:quiklist中元素的总个数,这样不通过遍历也可以知道整个quiklist中元素的总数

      nodes:quiklist中节点的个数,即整个quiklist中总共有多少个ziplist节点.

      compressDepth:压缩深度,默认为0,当为0的时候表示不压缩,当为一个大于0的整数时,表示链表两端的几个node不压缩

      

      2.2 quiklistNode

    struct quicklistNode {
        quicklistNode* prev;
        quicklistNode* next;
        ziplist* zl; // 指向压缩列表
        int32 size; // ziplist 的字节总数
        int16 count; // ziplist 中的元素数量
        int2 encoding; // 存储形式 2bit,原生字节数组还是 LZF 压缩存储
    }

      size:当前节点占用的总字节数,包括了保存的值和头信息的大小

      count:当前节点中元素的总数量

      

    3.配置参数

      list-max-ziplist-size 3

        每个ziplist中节点的个数,它可以取正值,也可以取负值。

        当取正值的时候,表示按照数据项个数来限定每个quicklist节点上的ziplist长度。比如,当这个参数配置成5的时候,表示每个quicklist节点的ziplist最多包含5个数据项。

        当取负值的时候,表示按照占用字节数来限定每个quicklist节点上的ziplist长度。这时,它只能取-1到-5这五个值,每个值含义如下:

          -5: 每个quicklist节点上的ziplist大小不能超过64 Kb。

          -4: 每个quicklist节点上的ziplist大小不能超过32 Kb。

          -3: 每个quicklist节点上的ziplist大小不能超过16 Kb。

          -2: 每个quicklist节点上的ziplist大小不能超过8 Kb。(-2是Redis给出的默认值)

          -1: 每个quicklist节点上的ziplist大小不能超过4 Kb。

      list-compress-depth 2 

        这个参数表示一个quicklist两端不被压缩的节点个数。注:这里的节点个数是指quicklist双向链表的节点个数,而不是指ziplist里面的数据项个数。实际上,一个quicklist节点上的ziplist,如果被压缩,就是整体被压缩的。

        参数list-compress-depth的取值含义如下:

          0: 是个特殊值,表示都不压缩。这是Redis的默认值。

          1: 表示quicklist两端各有1个节点不压缩,中间的节点压缩。

          2: 表示quicklist两端各有2个节点不压缩,中间的节点压缩。

          3: 表示quicklist两端各有3个节点不压缩,中间的节点压缩。

          依此类推...

     4.使用

    Redis 早期版本存储 list 列表数据结构使用的是压缩列表 ziplist 和普通的双向链表linkedlist,也就是元素少时用 ziplist,元素多时用 linkedlist。

    考虑到链表的附加空间相对太高,prev 和 next 指针就要占去 16 个字节 (64bit 系统的指针是 8 个字节),另外每个节点的内存都是单独分配,会加剧内存的碎片化,影响内存管理效率。后续版本对列表数据结构进行了改造,使用 quicklist 代替了 ziplist 和 linkedlist。现在list只是用quiklist保存

  • 相关阅读:
    JavaScript界面传值与前后台互调
    @requestBody注解的使用
    mybatis动态sql中foreach标签的使用
    mybatis动态SQL中的sql片段
    mybatis动态sql中where标签的使用
    mybatis动态sql中的trim标签的使用
    mybatis动态SQL中的set标签的使用
    SQL-join(inner join)、left join、right join、full join
    Oracle-distinct()用法、count(distinct( 字段A || 字段B))是什么意思?distinct多个字段
    Oracle-where exists()、not exists() 、in()、not in()用法以及效率差异
  • 原文地址:https://www.cnblogs.com/monkeydai/p/16084925.html
Copyright © 2020-2023  润新知