• Redis高可用系列——List类型底层详解



    前言

    Redis是一种高性能的键值型数据库,它支持多种数据结构,其中一种是list类型。list类型可以存储一个有序的字符串列表,类似于Java中的LinkedList或Python中的list。list类型的优点是可以在列表的两端进行快速的插入和删除操作,支持阻塞和非阻塞的读取方式。


    List

    概述

    list 是一个有序的字符串列表,它按照插入顺序排序,并且支持在两端插入或删除元素。一个 list 类型的键最多可以存储 2^32 - 1 个元素。

    redis3.2以后,list 类型的底层实现只有一种结构,就是quicklist。版本不同时,底层实现是不同的,下面会讲解。

    应用场景

    list 类型的应用场景主要是实现队列和栈,比如:

    • 消息队列,利用 lpush 和 rpop 命令实现生产者消费者模式。
    • 最新消息,利用 lpush 和 ltrim 命令实现固定长度的时间线。
    • 历史记录,利用 lpush 和 lrange 命令实现浏览记录或者搜索记录。

    底层原理

    在讲解list结构之前,需要先说明一下list结构编码的更替,如下

    • Redis3.2之前,list使用的是linkedlistziplist
    • Redis3.2~Redis7.0之间,list使用的是quickList,是linkedlistziplist的结合
    • Redis7.0之后,list使用的也是quickList,只不过将ziplist转为listpack,它是listpack、linkedlist结合版

    linkedlist与ziplist

    Redis3.2之前,linkedlistziplist两种编码可以选择切换,它们之间的转换关系如图

    请添加图片描述
    ziplist转为linkedlist的条件可在redis.conf配置

    list-max-ziplist-entries 512
    list-max-ziplist-value 64
    
    • 1
    • 2

    quickList(ziplist、linkedlist结合版)

    quicklist存储了一个双向列表,每个列表的节点是一个ziplist,所以实际上quicklist并不是一个新的数据结构,它就是linkedlistziplist的结合,然后被命名为快速列表。

    请添加图片描述

    ziplist内部entry个数可在redis.conf配置

    list-max-ziplist-size -2
    # -5: 每个ziplist最多为 64 kb  <-- 影响正常负载,不推荐
    # -4: 每个ziplist最多为 32 Kb  <-- 不推荐
    # -3: 每个ziplist最多为 16 Kb  <-- 最好不要使用
    # -2: 每个ziplist最多为 8 Kb   <-- 好
    # -1: 每个ziplist最多为 ![请添加图片描述](https://img-blog.csdnimg.cn/2f226105c23d4249ac727b7dc2b172f5.png)
    4 Kb   <-- 好
    # 正数为ziplist内部entry个数
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    ziplist通过特定的LZF压缩算法来将节点进行压缩存储,从而更进一步的节省空间,而很多场景都是两端元素访问率最高,我们可以通过配置list-compress-depth来排除首尾两端不压缩的entry个数。

    list-compress-depth 0
    # - 0:不压缩(默认值)
    # - 1:首尾第 1 个元素不压缩
    # - 2:首位前 2 个元素不压缩
    # - 3:首尾前 3 个元素不压缩
    # - 以此类推
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    quickList(listpack、linkedlist结合版)

    和Hash结构一样,因为ziplist有连锁更新问题,redis7.0ziplist替换为listpack,下面是新quickList的结构图

    请添加图片描述

    Redis中listpack源码

    typedef struct quicklist {
        quicklistNode *head;
        quicklistNode *tail;
        unsigned long count;        /* 所有列表包中所有条目的总数,占用16 bits,最大65536 */
        unsigned long len;          /* quicklistNode 的数量 */
        signed int fill : QL_FILL_BITS;       /* 单个节点的填充因子 */
        unsigned int compress : QL_COMP_BITS; /* 不压缩的端节点深度;0=off */
        unsigned int bookmark_count: QL_BM_BITS;
        quicklistBookmark bookmarks[];
    } quicklist;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    typedef struct quicklistNode {
        struct quicklistNode *prev;
        struct quicklistNode *next;
        unsigned char *entry;
        size_t sz;             /* 当前entry占用字节 */
        unsigned int count : 16;     /* listpack元素个数,最大65535 */
        unsigned int encoding : 2;   /* RAW==1 or LZF==2 */
        unsigned int container : 2;  /* PLAIN==1 or PACKED==2 */
        unsigned int recompress : 1; /* 当前listpack是否需要再次压缩 */
        unsigned int attempted_compress : 1; /* 测试用 */
        unsigned int extra : 10; /* 备用 */
    } quicklistNode;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    listpack内部entry个数可在redis.conf配置

    List-Max-listpack-size -2
    # -5: 每个listpack最多为 64 kb  <-- 影响正常负载,不推荐
    # -4: 每个listpack最多为 32 Kb  <-- 不推荐
    # -3: 每个listpack最多为 16 Kb  <-- 最好不要使用
    # -2: 每个listpack最多为 8 Kb   <-- 好
    # -1: 每个listpack最多为 4 Kb   <-- 好
    # 正数为listpack内部entry个数
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    总结

    Redis list类型是一种可以存储一个有序的字符串列表的数据结构,它有以下特点:

    • 可以在列表的两端进行快速的插入和删除操作,支持阻塞和非阻塞的读取方式
    • 可以根据索引或范围来获取列表中的元素,支持反向遍历和排序等操作
    • 可以用作栈、队列、消息队列等场景

    系列文章目录

    Redis内存优化——String类型介绍及底层原理详解
    Redis内存优化——Hash类型介绍及底层原理详解
    Redis内存优化——List类型介绍及底层原理详解
    Redis内存优化——Set类型介绍及底层原理详解
    Redis内存优化——ZSet类型介绍及底层原理详解
    Redis内存优化——Stream类型介绍及底层原理详解
    Redis内存优化——Hyperloglog、GEO、Bitmap、Bitfield类型详解
    Redis的三种持久化策略及选取建议

  • 相关阅读:
    人工智能数学基础--概率与统计11:离散随机变量的超几何分布和负二项分布
    linux开发板中的数据存储和读取操作
    使用Kubectl管理kubernetes集群
    Mock使用场景
    谷粒商城实战笔记-142-性能压测-压力测试-Apache JMeter安装使用
    Java的运行机制CLASSPATHJAVA_HOME
    一日一技:用Python做游戏有多简单
    Java_实现图书管理系统
    Mybatis—缓存
    [含文档+PPT+源码等]精品基于SpringCloud实现的商品服务系统-微服务-分布式[包运行成功]
  • 原文地址:https://blog.csdn.net/Star_Inori/article/details/126513876