Redis中ziplist与quicklist解析与对比小结

 更新时间:2026年01月07日 09:00:52   作者:程序员风屿  
本文介绍了Redis中List数据类型的两种编码方式ziplist和quicklist,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

一、背景 — 为什么要有多种“列表(List)”编码

  • 在内存数据库 Redis 中,列表(List)是常用数据类型之一,用于实现队列、堆栈、消息队列、任务队列等场景。
  • 不同场景对内存使用与访问效率有不同要求:少量元素 → 希望节省内存;大量元素或频繁插入/删除 → 需要高性能操作。
  • 因此Redis 设计者提供了不同的“编码方式”(encoding)来存储 List 对象,以兼顾 空间效率操作效率

在历史发展中,Redis 对 List 的编码方式经历了如下阶段:

  • 早期:使用 双向链表(linkedlist)压缩列表(ziplist),两种可选。
  • 从 Redis 3.2 版本起,引入 quicklist,作为新的默认结构,取代了 ziplist + linkedlist 的混合策略。

下面分别介绍 ziplist 和 quicklist 的结构与特性,然后比较优缺点。

二、ziplist —— 压缩列表(compact list)

2.1 ziplist 是什么

  • ziplist 是 Redis 提供的一种“紧凑型列表结构(compact list)”。它将多个 list 元素连续地存放在一块 连续内存(contiguous memory block) 中。
  • 每个 entry(元素)包含必要的 metadata(如前一个 entry 长度、当前 entry 长度、数据内容等),因此 ziplist 可以存放不同长度的数据项(字符串、整数等),而不需要为每个元素单独分配内存。
  • 因为内存连续、元素紧凑,ziplist 在内存占用上非常高效 — 对于存储少量、短字符串/整数列表时,能节省大量内存。

ziplist结构如图所示,参考Redis面试题:

下边的图也可加深理解

ziplist的各字段含义如下。

  • zlbytes:压缩列表的字节长度,占4B,因此压缩列表最长 2³²‑1B。
  • zltail:压缩列表尾元素相对于压缩列表起始地址的偏移量,占4B。
  • zllen:压缩列表的元素数目,占2B;当压缩列表的元素数目超过65535(2¹⁶‑1)时,zllen 无法存储,此时必须遍历整个压缩列表才能获取元素数目。
  • entry1、entr2y:压缩列表存储的若干个元素,可以是字节数组或者整数,长度不限;
  • zlend:压缩列表的结尾,占1B,固定为0xFF。

对于每一个entry元素来讲

entry 结构包含三个字段:

  1. prelen
    • 记录前一个元素的长度,用于从后向前遍历。
    • 前一个元素长度 < 254B → 占 1B。
    • 前一个元素长度 ≥ 254B → 占 5B(首字节为 0xFE,后 4B 为实际长度)。
  2. encoding
    • 表示 data 的数据类型(整数或字节数组)。
    • 长度可变(1B、2B 或 5B),通过开头的比特区分。
    • 同时可包含字节数组的长度信息(如 6bit、14bit 或 32bit 表示长度)。

以下是encoding字段的元素编码

编码 (encoding) 标识 / 类型encoding长度说明 / 含义 (简要)
00pppppp1B表示一个 string,长度 ≤ 63 字节。
01pppppp + qqqqqqqq2B表示一个 string,长度 ≤ 2¹⁴‑1字节。
10000000 + 4 bytes length5B表示一个较长 string(长度 ≤ 2³²‑1字节)。
110000001B表示一个 int16_t(16-bit 整数)元素。
110100001B表示一个 int32_t(32-bit 整数)元素。
111000001B表示一个 24-bit 整数编码(special 24-bit 整数)。
111111101B表示一个 int8_t(8-bit 整数)元素。
1111xxxx1Bxxxx表示范围为 0–12 的整数 。
  1. data
    • 实际存储的数据,可以是整数或字节数组,长度由 encoding 决定。

2.2 ziplist 的适用条件(默认策略)

在 Redis 配置文件(或编译时默认)中,对于 LIST、HASH、ZSET 等类型,会设置参数来决定是否使用 ziplist,例如:

  • list-max-ziplist-entries:限制 ziplist 中元素(entry)个数
  • list-max-ziplist-value:限制每个 entry 的最大字节数(value 大小)

当元素数量或元素大小超过这些限制时,Redis 会放弃 ziplist 编码,转为其他更适合的编码方式(在老版本可能是 linkedlist,现在是 quicklist)。

2.3 ziplist 的优点与缺点

优点

  • 内存利用率高 — 非常节省内存空间,适合存储少量、小数据。
  • 内存连续,有利于 CPU 缓存和遍历效率。

缺点 / 缺陷

  • 对修改操作(插入 / 删除 / 更新)不友好 — 因为要保持连续内存,一旦中间插入或删除,就可能触发内存重新分配和数据搬移(realloc + memcpy),代价高昂。这里会涉及连锁更新问题。
  • 当元素较多或较大时,ziplist 会非常臃肿或重复 realloc,性能和稳定性都不理想。
  • 因此,ziplist 更适合“短小、稳定、不频繁变更”的列表数据,不适合大数据量或高频写入场景。

三、quicklist —— 快速列表(QuickList)

3.1 quicklist 是什么

  • quicklist 是从 Redis 3.2 开始引入的 List 编码方式,用于替代早期的 ziplist /adlist 编码。
  • 它本质上是 双向链表 + 压缩子列表 的混合结构:一个 quicklist 是一个双向链表,而链表的每个节点(quicklistNode)内部持有一个 ziplist来存储一段连续的元素。
  • 这样的设计兼顾了链表和 ziplist 各自的优点。

3.2 quicklist 的结构与配置参数

quicklist 的主要结构由 quicklistquicklistNode 两个 C 结构体定义,在 Redis 源码中(例如 quicklist.h / quicklist.c)可以查看。

结构图

在quicklist中,关键字段包括:

  • head / tail:指向链表头尾节点。
  • count:List 中所有元素entry的总数。
  • len:quicklistNode 节点数量。
  • fill:用于控制每个 ziplist 容量上限entry 数量 或 字节大小,通过 list-max-ziplist-size 配置项设定。
  • compress:用于控制压缩深度,即链表两端多少个节点不压缩,中间节点可被压缩以节省内存,通过 list-compress-depth 配置项控制。
  • 每个 quicklistNode 包含指向内部 ziplist(或 listpack)的指针 zl,大小 sz,元素计数 count 等信息。

⚠️ 注意:在 Redis 最新版本中(例如 7.x),listpack 已经逐步取代 ziplist 作为内部压缩子列表结构,但 quicklist 的设计思想不变 —— 分段 + 链表 + 压缩子列表。

3.3 quicklist 的优点

  • 兼顾空间与效率:通过将列表拆成多个小段(ziplist),既避免了大型链表带来的内存碎片和高 overhead,也避免了大型 ziplist 带来的频繁 realloc 问题。
  • 快速头尾操作(push/pop):因为 quicklist 是链表结构,在头尾插入删除是 O(1) 操作,非常高效,适合队列/栈等操作频繁场景。
  • 压缩可选:中间节点可以压缩(LZF 等算法/listpack 压缩),节省内存;而头尾保留原始以保证访问性能。
  • 灵活适应不同场景:既适合存储小量短元素,也适合存储大量元素或长列表。

3.4 quicklist 的限制与注意事项

  • 如果配置不当(ziplist 内部过大、压缩设置不合理),可能出现性能开销过重,或内存碎片/压缩开销问题。
  • quicklist 内部实现比简单链表或数组复杂,对于某些极端访问模式(大量随机访问中间、频繁跨节点访问)可能不如纯数组或其他结构高效。

quicklist 的两种极端情况如下:

1. 当 ziplist 节点过多时,quicklist 退化为双向链表。最极端的情况是每个 ziplist 节点只包含一个 entry,即一个元素对应一个节点。
2. 当 ziplist 节点过少时,quicklist 退化为 ziplist。最极端的情况是整个 quicklist 中只含有一个 ziplist 节点。

  • 对于非常频繁的随机访问或修改,可能需要谨慎评估是否适合使用列表结构。

四、ziplist vs quicklist —— 对比总结

特性 / 维度ziplistquicklist
内存布局连续内存 block(compact)链表 + 多个 ziplist/listpack segments
内存开销低,连续、紧凑较高(链表+子列表)但比纯链表低
适合场景元素少、数据小、读不频繁修改元素多、队列 / 栈 / 批量 push/pop / 变长频繁
插入/删除性能中间插入删除开销大(可能 memcpy)头尾 O(1),节点级调整,较稳定
内存碎片几乎无较少(链表 + 子列表)
压缩 / 节省空间默认紧凑可配置压缩,兼顾效率
Redis 中默认支持早期版本Redis 3.2+ 默认

Redis 之所以在内存数据库 / 缓存系统中表现出色,很大程度上是因为它为不同场景提供了优化良好的底层数据结构。ziplist 与 quicklist 是 Redis List 类型在历史与现在对空间与时间折中的经典设计。

  • ziplist:为“少量、小数据、节省内存”而生。
  • quicklist:为“高性能、灵活、适应大/变动列表”而设计。

到此这篇关于Redis中ziplist与quicklist解析与对比小结的文章就介绍到这了,更多相关Redis ziplist与quicklist内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • RedisTemplate中boundHashOps的使用小结

    RedisTemplate中boundHashOps的使用小结

    redisTemplate.boundHashOps(key) 是 RedisTemplate 类的一个方法,本文主要介绍了RedisTemplate中boundHashOps的使用小结,具有一定的参考价值,感兴趣的可以了解一下
    2024-04-04
  • Win10下通过Ubuntu安装Redis的过程

    Win10下通过Ubuntu安装Redis的过程

    这篇文章主要介绍了Win10下通过Ubuntu安装Redis,在安装Ubuntu需要先打开Windows功能,接着创建一个用户及密码,本文给大家介绍的非常详细,需要的朋友可以参考下
    2022-04-04
  • Redis三种特殊数据类型的具体使用

    Redis三种特殊数据类型的具体使用

    本文主要介绍了Redis三种特殊数据类型的具体使用,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • Redis搭建一主多从的实现步骤

    Redis搭建一主多从的实现步骤

    本文主要介绍了在Linux环境下配置Redis的一主两从架构,包括创建配置文件,设置不同端口,启动服务,以及通过inforeplication命令检查复制状态,感兴趣都可以了解一下
    2025-10-10
  • 简介Lua脚本与Redis数据库的结合使用

    简介Lua脚本与Redis数据库的结合使用

    这篇文章主要介绍了简介Lua脚本与Redis数据库的结合使用,Redis是基于主存的高性能数据库,需要的朋友可以参考下
    2015-06-06
  • 利用redis实现分布式锁,快速解决高并发时的线程安全问题

    利用redis实现分布式锁,快速解决高并发时的线程安全问题

    这篇文章主要介绍了利用redis实现分布式锁,快速解决高并发时的线程安全问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • 防止redis内存溢出优化方法

    防止redis内存溢出优化方法

    本文主要介绍了防止redis内存溢出优化方法,包括使用maxmemory-policy选项、设置数据过期时间和配置Redis集群等,具有一定的参考价值,感兴趣的可以了解一下
    2025-03-03
  • 使用宝塔在服务器上配置Redis的详细图文教程

    使用宝塔在服务器上配置Redis的详细图文教程

    这篇文章主要给大家介绍了关于使用宝塔在服务器上配置Redis的相关资料,包括下载和安装Redis,开放端口,修改配置文件以允许远程访问和设置密码,该过程对于理解Redis在项目部署中的配置提供了实用指导,需要的朋友可以参考下
    2024-11-11
  • 基于Redis有序集合实现滑动窗口限流的步骤

    基于Redis有序集合实现滑动窗口限流的步骤

    滑动窗口算法是一种基于时间窗口的限流算法,通过动态地滑动窗口,可以动态调整限流的速率,Redis有序集合可以用来实现滑动窗口限流,本文介绍基于Redis有序集合实现滑动窗口限流,感兴趣的朋友一起看看吧
    2024-12-12
  • 利用Redis实现防止接口重复提交功能

    利用Redis实现防止接口重复提交功能

    大家好,本篇文章主要讲的是利用Redis实现防止接口重复提交功能,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览
    2021-12-12

最新评论