当前位置: 首页 > news >正文

ziplist、quicklist、listpack之间的区别

在Redis的底层实现中,数据结构的设计始终围绕“内存高效”与“性能优异”两大核心目标。ziplist、quicklist、listpack这三种紧凑结构便是这一设计理念的典型体现——它们并非传统意义上的标准数据结构,而是Redis为适配自身内存数据库的特性量身定制的优化方案。从ziplist的诞生到quicklist的迭代,再到listpack的崛起,每一次演进都源于对前序结构缺陷的弥补。本文将深入剖析这三种结构的设计细节、核心优劣及适用场景,带你理清Redis紧凑结构的演进脉络。

一、设计基石:为何Redis执着于“紧凑结构”?

Redis作为内存数据库,内存利用率直接决定了服务的承载能力;同时,作为高性能中间件,操作延迟的高低直接影响业务体验。传统数据结构在Redis场景中存在明显短板:

  • 链表:每个节点需存储前驱/后继指针,存在大量内存冗余;节点离散存储导致CPU缓存命中率低。
  • 哈希表:初始化时需预分配空间,小数据场景下内存浪费严重;负载因子过高时需扩容,存在性能抖动。

为此,Redis设计了“紧凑结构”系列:通过连续内存存储、动态编码等方式减少内存开销,同时针对不同数据规模和操作场景优化性能。ziplist、quicklist、listpack便是在不同阶段为解决特定问题而诞生的产物。

二、初代王者:ziplist(压缩列表)的功与过

ziplist是Redis最早推出的紧凑结构,核心定位是“用连续内存存储小数据,极致节省内存”。它并非链表,而是一块精心设计的连续内存块,通过动态编码实现多元素的紧凑排列。

2.1 核心结构特点

ziplist的整体结构由“头部信息+多个entry(元素)+尾部标记”组成,其中每个entry包含三个关键部分:

  1. previous_entry_length:记录前一个entry的长度,用于反向遍历(从后向前查找元素)。
  2. encoding:记录当前元素的编码类型(整数/字符串)和长度,实现动态压缩。
  3. data:存储元素的实际数据。

这种设计的核心优势是“无指针开销”——所有元素紧凑排列在连续内存中,相比传统链表节省了大量指针占用的内存。

2.2 高光时刻:适用场景与优势

在Redis 5.0之前,ziplist是List、Hash、ZSet三种数据类型的“小数据默认存储方案”,触发条件由配置参数控制(以Hash为例):

  • 哈希表中字段数量 ≤ hash-max-ziplist-entries(默认512);
  • 每个字段的键值对大小 ≤ hash-max-ziplist-value(默认64字节)。

典型场景如存储用户基础信息:HSET user:1001 name "ZhangSan" age "25",此时Hash会以ziplist存储,内存利用率极高。

ziplist的核心优势总结:

  • 内存开销极低:连续内存存储,无指针冗余,动态编码进一步压缩空间;
  • 缓存友好:连续内存布局提升CPU缓存命中率,读取小数据时速度极快;
  • 兼容性强:支持整数、字符串等多种数据类型,适配多场景需求。

2.3 致命缺陷:连锁更新与性能瓶颈

ziplist的“previous_entry_length”字段是一把双刃剑——它实现了反向遍历,但也引入了连锁更新这一致命问题:

当在某个entry前插入一个新元素时,若新元素的长度导致后续entry的“previous_entry_length”字段无法容纳(例如原字段是1字节,新元素长度超过256字节,需将后续字段的“previous_entry_length”从1字节扩容为5字节),则后续entry的长度会发生变化,进而导致其下一个entry的“previous_entry_length”也需要调整,以此类推,形成连锁反应。极端情况下,一次插入操作可能触发整个ziplist的更新,时间复杂度飙升至O(n²)。

此外,ziplist的连续内存特性还导致:

  • 插入/删除低效:中间位置的插入/删除需移动后续所有元素,时间复杂度O(n);
  • 扩展性差:数据量增大时,内存重分配和数据移动的开销会急剧增加。

这些缺陷使得ziplist无法适配大列表、高频修改等场景,也为后续quicklist和listpack的出现埋下了伏笔。

三、列表救星:quicklist(快速链表)的平衡之道

为解决ziplist在大列表场景下的性能问题,Redis 3.2版本推出了quicklist,并将其作为List类型的默认底层实现。quicklist的核心设计思路是“分块存储”——将一个大列表拆分为多个小ziplist,再通过双向链表将这些小ziplist连接起来,兼具ziplist的内存优势和链表的操作优势。

3.1 核心结构特点

quicklist的结构由“quicklist(整体控制)+ quicklistNode(节点)+ ziplist(数据块)”三级组成,核心结构体定义如下:


// 快速链表整体结构
typedef struct quicklist {quicklistNode *head;          // 头节点指针quicklistNode *tail;          // 尾节点指针unsigned long count;          // 列表总元素数unsigned long len;            // 节点数量(quicklistNode的个数)int fill : 16;                // 单个ziplist的最大容量(由配置控制)unsigned int compress : 16;   // 中间节点压缩深度(LZF算法)
} quicklist;// 快速链表节点
typedef struct quicklistNode {struct quicklistNode *prev;    // 前驱节点指针struct quicklistNode *next;    // 后继节点指针unsigned char *zl;             // 指向当前节点的ziplistunsigned int sz;               // 当前ziplist的字节大小unsigned int count : 16;       // 当前ziplist的元素个数unsigned int encoding : 2;     // 编码(原生ziplist/压缩ziplist)
} quicklistNode;

关键设计细节:

  • 分块控制:通过fill参数控制单个ziplist的最大容量(默认512元素),避免单个ziplist过大;
  • 压缩优化:通过compress参数控制中间节点的压缩深度(默认不压缩),对首尾节点不压缩以保证操作性能,中间节点用LZF算法压缩节省内存;
  • 双向链表:通过prev/next指针实现节点间的快速遍历,首尾操作时间复杂度为O(1)。

3.2 核心优势与适用场景

quicklist完美解决了ziplist在大列表场景下的痛点,核心优势包括:

  • 平衡内存与性能:单个节点内用ziplist紧凑存储,节点间用链表连接,既减少内存冗余,又降低插入/删除的移动成本;
  • 隔离连锁更新:分块存储使得连锁更新仅局限在单个ziplist内,不会扩散到整个列表,极大降低了极端情况的性能风险;
  • 灵活配置:通过list-max-ziplist-sizelist-compress-depth两个参数,可根据业务场景调整分块大小和压缩策略。

适用场景:Redis List类型的全场景需求,尤其是大列表、高频头尾操作的场景,如消息队列(LPUSH入队、RPOP出队)、用户动态时间线(头部插入新动态、尾部删除旧动态)等。

3.3 局限性

quicklist的缺陷主要集中在内存层面:

  • 指针开销:每个quicklistNode需存储prev/next指针,相比纯ziplist存在额外内存开销;
  • 分块碎片:多个ziplist节点分散存储,可能产生一定的内存碎片(但远低于传统链表)。

四、终极迭代:listpack(列表打包)的优化升级

虽然quicklist解决了ziplist在大列表的性能问题,但ziplist本身的连锁更新缺陷仍存在于Hash、ZSet等类型中。为此,Redis 5.0版本推出了listpack作为ziplist的替代品(实验性),并在Redis 7.0版本中将其作为Hash、ZSet的默认紧凑存储方案。listpack的核心目标是“解决连锁更新,同时保持ziplist的内存优势”。

4.1 核心结构特点

listpack的设计思路是“单条目自包含”——摒弃ziplist的“previous_entry_length”字段,改为每个entry仅存储自身的长度信息。其整体结构为“头部信息+多个entry+尾部标记”,每个entry的格式为“entry长度+编码类型+数据”。

这一设计从根源上解决了连锁更新问题:由于每个entry仅记录自身长度,修改或插入某个entry时,不会影响后续entry的长度字段,自然不会触发连锁更新。

此外,listpack还做了其他优化:

  • 编码简化:精简了编码类型,减少了字段解析的开销;
  • 尾部标记优化:用固定的2字节标记结尾,相比ziplist的1字节标记更稳定。

4.2 核心优势与适用场景

listpack作为ziplist的升级版,继承了其内存优势,同时弥补了核心缺陷,优势总结:

  • 无连锁更新风险:单条目自包含设计,修改元素不会影响其他entry,写入性能更稳定;
  • 内存开销低:连续内存存储,无指针开销,内存利用率与ziplist相当;
  • 读写性能优异:读操作与ziplist一致(需遍历),写操作因无连锁更新而略优于ziplist。

适用场景:替代ziplist用于Hash、ZSet的小数据存储,例如:

  • Hash:存储用户属性、商品详情等小字段集合;
  • ZSet:存储小型排行榜(如用户积分前100名)。

五、三者横向对比:演进脉络与选型指南

为清晰展示三种结构的差异,我们从核心特性、性能、适用场景等维度进行横向对比:

特性

ziplist

quicklist

listpack

内存连续性

完全连续

分块连续(节点内连续)

完全连续

连锁更新风险

高(依赖prevlen)

低(分块隔离)

无(自包含长度)

插入/删除性能

O(n),可能触发连锁更新

O(n),分块降低开销

O(n),无连锁更新

内存开销

极低

中等(指针+分块)

极低(与ziplist相当)

适用Redis版本

≤5.0(主力),≥5.0(逐步淘汰)

≥3.2(List默认)

≥5.0(实验),≥7.0(Hash/ZSet默认)

核心适用类型

旧版Hash、List、ZSet

List(全场景)

新版Hash、ZSet

从对比中可清晰看出Redis紧凑结构的演进逻辑:

  1. ziplist:为解决小数据内存问题而生,奠定紧凑存储的基础,但因连锁更新缺陷逐渐被替代;
  2. quicklist:针对List的大列表场景优化,通过分块平衡内存与性能,成为List的终极方案;
  3. listpack:解决ziplist的连锁更新缺陷,成为Hash、ZSet的新一代紧凑存储方案。

六、总结与实践建议

ziplist、quicklist、listpack的演进,本质是Redis对“内存效率”与“操作性能”平衡的持续探索。三者并非互斥关系,而是针对不同数据类型、不同场景的精准适配。在实际开发中,我们可根据这一特性优化Redis使用:

  1. List类型:无需关注底层实现,Redis会通过quicklist自动适配小列表与大列表场景;若为高频头尾操作的消息队列,可适当调大list-compress-depth压缩中间节点,节省内存。
  2. Hash/ZSet类型:尽量控制字段数量和元素大小,使其能以listpack存储(Redis 7.0+默认),避免过早转为哈希表或跳表导致内存浪费。
  3. 版本选择:若业务中存在大量Hash/ZSet的小数据存储,建议升级至Redis 7.0+,利用listpack规避ziplist的连锁更新风险。
http://www.dtcms.com/a/512103.html

相关文章:

  • 1.序列式容器-vectorlist
  • 长沙外贸建站用spl做网站
  • 无锡网站建设818gxwordpress 迁移 域名
  • 使用beautifulSoup提取信息
  • 一种独特机理驱动的化学反应分类器详解
  • 南京佛搜做网站公司wordpress支付宝支付
  • C++ 多态:面向对象编程中的灵活性与扩展性
  • 微信公众号内嵌网站开发做团购的的网站有哪些
  • 当前非英语国家中出现的“去英语化”趋势
  • CR后的反思、编辑表格实现
  • MyBatis-Plus黑马
  • 网站建设需要几个部门网站首页布局设计
  • C语言基础入门--指针
  • 計組-中斷與子程序調用的區別
  • 做牛津布面料在哪个网站找客户八大员继续教育入口
  • SD-WAN是什么?与MPLS,MSTP,IPSEC,SSL 有什么区别?
  • 【操作系统】408操作系统核心考点精讲:宏内核、微内核与外核架构全解析​
  • EXCEL文本数字如何批量转换为数字
  • Linux 文件权限深度解析:从原理到实战管理
  • SpringMVC 数据校验和BindingResult以及自定义校验注解
  • [明道云专栏·里程碑] 从第一篇到第一百篇:这是一场属于“低代码实战者”的长跑
  • Ubuntu 安装 Harbor
  • 网站屏蔽ip地址河南网站备案系统短信
  • 中科院网站做的好的院所双鸭山网站建设公司
  • Linux配置Samba文件共享并访问Windows文件
  • Cursor配置markdown转Word的MCP工具教程
  • 常见springboot相关注解
  • ◆comfyUI教程◆第2章13节 XL模型专用工作流与refiner精炼
  • PostIn V1.3.1版本发布,新增在线更新程序命令,新增请求体json支持引用变量
  • asp网站作业下载二级建造师报名时间2022年官网