Redis内存优化——List类型介绍及底层原理详解

文章目录

  • 前言
  • List
    • 概述
    • 应用场景
    • 底层原理
      • linkedlist与ziplist
      • quickList(ziplist、linkedlist结合版)
      • quickList(listpack、linkedlist结合版)
  • 总结
  • 系列文章目录


前言

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两种编码可以选择切换,它们之间的转换关系如图

Redis内存优化——List类型介绍及底层原理详解_第1张图片
ziplist转为linkedlist的条件可在redis.conf配置

list-max-ziplist-entries 512
list-max-ziplist-value 64

quickList(ziplist、linkedlist结合版)

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

Redis内存优化——List类型介绍及底层原理详解_第2张图片

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个数

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

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

quickList(listpack、linkedlist结合版)

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

Redis内存优化——List类型介绍及底层原理详解_第3张图片

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;
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;

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个数

总结

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

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

系列文章目录

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

你可能感兴趣的:(互联网技术架构,redis,数据库,分布式,缓存,云原生)