Redis-结构-压缩列表

redis源码分析教程之压缩链表ziplist详解 ziplist结构在redis运用非常广泛,是列表、字典等数据类型的底层结构之一。ziplist的优点在于能够一定程度地节约内存。下面这篇文章主要给大家介绍了关于redis源码分析教程之压缩链表ziplist的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。 立即下载

什么是压缩列表

 

压缩列表 ziplist 在 redis 中的应用也非常广泛,它是我们常用的 zset ,list 和 hash 结构的底层实现之一。当我们的容器对象的元素个数小于一定条件时,redis 会使用 ziplist 的方式储存,来减少内存的使用。

    > hset test_hash me sidfate
    (integer) 1
    > object encoding test_hash
    "ziplist"

为什么要在元素较少的时候使用 ziplist ?

因为 redis 中的集合容器中,很多情况都用到了链表的实现,元素和元素之间通过储存的关联指针有序的串联起来,但是这样的指针往往是 随机I/O,也就是指针地址是不连续的(分布不均匀)。而我们的 ziplist 它本身是一块连续的内存块,所以它的读写是 顺序I/O,从底层的磁盘读写来说,顺序I/O 的效率肯定是高于 随机I/O 。你可能会问了,那为什么不都用 顺序I/O 的 ziplist 代替 随机I/O 呢,因为 ziplist 是连续内存,当你元素数量多了,意味着当你创建和扩展的时候需要操作更多的内存,所以 ziplist 针对元素少的时候才能提升效率。

ziplist 如何减少内存使用的呢?

接下来让我们从源码中一探究竟。

源码结构

题外话:每当你想要去探究一个项目的源码的时候,首先应该去看的就是它的注释,好的注释即是文档。同时也告诉我们平时开始也要注意注释的编写。

首先从源码的注释中我们可以了解一些基础信息:

ziplist 是经过特殊编码的双向列表结构,用来提高内存使用效率。它可以储存字符串或者整数值,其中整数值被编码成实际的整数,而不是字符串形式。它可以在 O(1) 时间内对列表的两端进行 push 和 pop 操作。但是,因为每个操作都需要重新分配 ziplist 使用的内存,所以实际的复杂度与 ziplist 使用的内存大小有关。

ziplist 结构的布局如下:

<zlbytes> <zltail> <zllen> <entry> <entry> ... <entry> <zlend>
复制代码

属性字节数含义
zlbytes4压缩列表占用的内存字节数:在对压缩列表进行内存重分配, 或者计算 zlend 的位置时使用。
zltail4压缩列表表尾节点的偏移量:用来倒序遍历压缩列表。
zllen2记录了压缩列表包含的节点数量: 当这个属性的值小于 UINT16_MAX (65535)时, 这个属性的值就是压缩列表包含节点的数量; 当这个值等于 UINT16_MAX 时, 节点的真实数量需要遍历整个压缩列表才能计算得出。
entry[]待定节点数组,包含元素的具体信息
zlend1特殊值 0xFF (十进制 255 ),用于标记压缩列表的末端。

ziplist中的每个节点 entry 的结构如下:

<prevlen> <encoding> <entry-data>
复制代码

redis 为了节约内存在 ziplist 的 entry 这个结构上有很多骚操作,让我来一一说明。

prevlen

prevlen 表示前一个元素的长度,以便能够从后向前遍历列表。它有一套特别的编码方式:如果这个长度小于254字节,那么它占用1个字节;当长度大于或等于254时,占用5个字节,第一个字节被设置为254 (0xFE),其余的4个字节采用前一个条目的长度作为值。prevlen 用 5 bytes表示时,不代表长度一定大于等于254,这是为了减少 realloc 和 memmove 提高效率。

为什么临界值是 254 ?我们来算一笔,一个字节最大能储存值为255,那临界值应该是255啊,别忘了我们还有个 zlend,它的值是0xFF(255),为了避免混淆,所以用254区分。

encoding

encoding 表示元素的编码,它取决于元素的内容。当元素是一个字符串时,编码的第一个字节的前2位将保存用于存储字符串长度的编码类型,然后是字符串的实际长度。当条目是整数时,前2位都设置为1。下面的2位用于指定在这个报头之后将存储哪种类型的整数。对不同类型和编码的概述如下。第一个字节总是足以确定条目的类型。

  • |00pppppp| - 1 字节

    长度小于或等于63字节的字符串,63可以用6个字节表示,所以 pppppp 表示字符串的实际长度。

  • |01pppppp|qqqqqqqq| - 2 字节

    长度小于或等于16383字节(14 位)的字符串。

  • |10000000|qqqqqqqq|rrrrrrrr|ssssssss|tttttttt| - 5 字节

    长度大于16383(14位)的字符串,后4个字节代表长度。

  • |11000000| - 3 字节

    11000000 + int16(2字节)。

  • |11010000| - 5 字节

    11010000 + int32(4字节)。

  • |11100000| - 9 bytes

    11010000 + int64(8字节)。

  • |11110000| - 4 bytes

    11110000 + 24位有符号整数(3字节)。

  • |11111110| - 2 bytes

    11110000 + int8(1字节)。

  • |1111xxxx|

    极小整数,xxxx 的范围只能是 (0001~1101),也就是1~13,但是因为0000、1110、1111都被占用了。读取到的 value 需要将 xxxx 减 1,也就是整数 0~12 就是最终的 value。

  • |11111111|

    表示 ziplist 的结束,也就是 zlend 的值 0xFF。

如果你觉得看的混乱了,别慌,上面的不需要全部记住,下面我会用一个鲜活的栗子(官方例子)来总结下。以下是一个包含了字符串 “2” 和 “5” 的压缩列表:

[0f 00 00 00] [0c 00 00 00] [02 00] [00 f3] [02 f6] [ff]
      |             |          |       |       |     |
   zlbytes        zltail    zllen     "2"     "5"   end
复制代码

最前面的4个字节的代表着数字 0x0f = 15(zlbytes = 15),表示这个 ziplist 总共占用了15个字节。紧跟着的4个字节代表数字 0x0c = 12(zltail = 12),说明最后一个元素的偏移量是12,也就是 “5” 这个元素到 ziplist 开头的长度。接着是 zllen = 2,代表总共有2个元素。之后就是实际储存 “2” 和 “5” 的 entry。解读下 “2” 为什么是 00 f3,00表示前一个元素长度为0,因为它是第一个元素,f3 是 0x11110011,也就是我们的 1111xxxx encoding类型,3 - 1 = 2正好是我们的 “2”,“5” 也同理。 最后是 ff 结尾表示结束。

有没有童鞋注意到官方例子总我们储存的是字符串的 “2” 和 “5”,但是 redis 把它当成了整数来储存 ?这一点其实是 redis 故意做的,很多地方都会做类似处理,目的么,还是为了减少内存消耗。

最后我们再看一个储存字符串的例子,我们把上面的 “5” 换成 “Hello World”,那么原先的 “5” 这个 entry 会变成:

[02] [0b] [48 65 6c 6c 6f 20 57 6f 72 6c 64]
复制代码

当AI换脸遇上内容审核:Facefusion NSFW检测的技术伦理与用户自主权之争 本文探讨了Facefusion开源AI换脸工具中NSFW检测机制的技术伦理困境与用户自主权之争。分析了其多层次防御机制的技术实现与社区规避方法,揭示了开源软件在安全与自由之间的平衡难题,并提出了分层权限设计等社区实践方案。 阅读详情

相关推荐

全球最大光伏电池缺陷异常检测数据集PVELAD【发布】

下载地址 1:GitHub - binyisu/PVEL-AD 下载地址 2:http://aihebut.com/col.jsp?id=118 下载地址 3:NAVEDownload 竞赛测试系统:Photovoltaic cell anomaly detection | Kaggle 一、简介 PVEL-AD 数据集又叫做EL2021数据集是用于对光伏电池异常缺陷检测方法进行基准测试的数据集,重点是光伏电池工业检测。PVEL-AD包含 36,543 张具有各种内部缺陷和异构背...

苏打水的杯子的博客 2万+

【redis基础知识】数据结构之压缩链表:ziplist

redis数据结构压缩链表ziplist,知识点介绍,源码分析

dylan的博客 1589

手把手教你用STM32F103C8T6驱动CLRC663国产NFC模块(兼容A/B/F/15693卡)

本文详细介绍了如何使用STM32F103C8T6驱动国产CLRC663 NFC模块,支持ISO14443A/B、Felica和ISO15693协议。从硬件设计、协议适配到状态监控,提供完整的工程实现方案,适用于智能门锁、支付终端等应用场景。

weixin_30689307的博客 445

ZipList(压缩链表)

redis-ZipList

打怪升级 1614

ERA5数据批量下载

ERA5再分析数据的IDM接管下载

qq_38734327的博客 3034

注册“Oracle Provider for OLE DB”和创建链接服务器

注册“Oracle Provider for OLE DB”和创建链接服务器 在sql server 数据库上创建链接服务器,连接oracle数据库,访问接口需要设置为:“Oracle Provider for OLE DB”。 如果电脑上没有这个驱动,安装一个完整的Oracle11gR2程序是一个有效的方法,但这个64位版本的安装包有2个多G, 相当庞大,如果仅仅...

weixin_30760895的博客 2383

【Redis 源码】压缩链表结构

​ 通过上面的描述,清晰的看出ziplist的由来,组成,以及如何创建一个ziplist对象,以及部分源码的理解​ 如果读者想了解更多的ziplist更多源码,可阅读ziplist.c源码,里面涵盖了插入,删除等等api的实现。

学习学习学习学习 1314

STM32CubeMX实战:TIM定时器中断配置避坑指南(附100ms精准定时代码)

本文深入解析STM32CubeMX配置TIM定时器中断的常见误区与避坑技巧,重点阐述时钟源、预分频器与自动重装载值的精准计算方法。通过实战案例,提供一份可直接复用的100ms精准定时中断代码模板,并分享调试验证方法,帮助开发者构建稳定可靠的嵌入式系统心跳。

grafana8visual的博客 500

Redis核心技术-数据结构1-底层(动态字符串、双向链表、压缩列表、跳表)结构

  我们平常所熟悉的String、List、Set、Sorted Set、Hash等只是Redis键值对中值的数据类型,也就是数据的保存类型,而他们底层的实现是如何的呢? 6种底层数据结构

ALONG的博客 1122

linux驱动由浅入深系列:基于高通平台分析触摸屏(TP)、虚拟按键驱动

触摸屏的触摸板(touch panel简称TP)驱动的基本架构和普通按键驱动基本一致,可以参考文章:linux驱动由浅入深系列:输入子系统之二(编写一个gpio_key驱动)。只是其功能稍稍复杂些,配置也多些,下面一起来看一下。 TP包括 触摸屏、虚拟按键、虚拟按键背光灯 TP驱动芯片厂商主要有:Goodix(汇顶),FocalTech(敦泰科技),cypress(赛普拉斯),synapt

Radia的专栏 4767

【AI理论学习】手把手推导扩散模型:Diffusion Models(DDPM)

生成扩散模型DDPM如下图所示分为前向、逆向两个过程,它首先通过不断往原始清晰数据中添加噪声使其变成标准高斯噪声(前向过程),而后期望从标准高斯噪声中还原原始数据(逆向过程)。若能实现,那便可从已知的标准高斯分布中采样一个噪声数据,而后利用DDPM模型生成符合原始数据分布的新数据。 Diffusion模型包含两个过程:数学符号:y∝xy\propto xy∝x:y正比于x,即y随着x增大而线性增大。 条件概率:贝叶斯公式:p(A∣B)=p(B∣A)×p(A)p(B)p(A|B)=\frac{p(B|A)\

小哲的博客 1509

Redis数据结构--压缩链表

压缩列表是一种为节约内存而开发的顺序型数据结构。压缩链表用于存储小整数值,或者长度比较短的字符串。 压缩链表的结构 压缩列表节点的结构 previous_entry_length属性以字节为单位,记录了压缩列表中前一个节点的长度。previous_entry_length属性的长度可以是1字节或者5字节。如果前一节点的长度小于254字节,那么previous_entry_length属性的长度为1字节:前一节点的长度就保存在这一个字节里面。如果前一节点的长度大于等...

beyond_czx的博客 1721

【五分钟论文笔记】Vision Banana:图像生成器成为通用视觉学习器

图像生成训练可以像 LLM 预训练一样,让模型学习强大且通用的视觉表示感知即生成——将视觉任务输出参数化为 RGB 图像,是一种优雅且强大的统一框架视觉理解能力可以在不牺牲生成能力的情况下获得——两者可以共存于同一个模型。

专注:太空算力、AI infra、异构调度、大模型成本工程 231

Redis数据结构之压缩列表

压缩列表(ziplist) 是列表键和哈希键的底层实现之一。当一个列表键只包含少量列表项,并且每个列表项要么就是小整数值,要么就是长度比较短的字符串,那么Redis就会使用压缩列表来做列表键的底层实现。

trigger的博客 709

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Redis数据结构总结-链表&&压缩列表

当我们的容器对象的元素个数小于一定条件时,redis 会使用 ziplist 的方式储存,来减少内存的使用。然后在 Redis 5.0 设计了新的数据结构 listpack,沿用了压缩列表紧凑型的内存布局,最终在最新的 Redis版本,将 Hash 对象和 Zset 对象的底层数据结构实现之一的压缩列表,替换成由 listpack 实现。因此,Redis 3.0 的 List 对象在数据量比较少的情况下,会采用「压缩列表」作为底层数据结构的实现,它的优势是节省内存空间,并且是内存紧凑型的数据结构。

左灯右行的爱情 1164

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

【Redis】压缩列表结构

ziplist(压缩列表)是redis中一种特殊编码的双向链表数据结构,主要用于存储小型列表和哈希表。ziplist并不是一个显式的c结构体,而是通过紧凑的字节数组来实现的。2、如果前一个entry的长度 >= 254字节,则prevlen占用5字节(第一个字节是0xFE,后4字节存储实际长度)。1、如果前一个entry的长度 < 254字节,则prevlen占用1字节(直接存储长度值)。2、如果数据类型为字符串,就根据字符串长度大小使用1、2、5字节编码。1、如果数据类型为整数,就使用1字节编码。

qq_45795794的博客 704

Redis6种底层数据结构之压缩列表

1)压缩列表是一种为节约内存而开发的顺序型数据结构2)压缩列表被用作列表键和哈希键的底层实现之一3)压缩列表可以包含多个节点,每个节点可以保存一个字节数组或者整数值4)添加新节点到压缩列表,或者从压缩列表中删除节点,可能会引发连锁更新操作,但是这种操作出现的概率不高,所以对性能影响不大。

qq_40853117的博客 887

【Redis数据结构】ziplist 压缩列表

详细介绍了 redis 的底层数据结构 ziplist 的实现方式以及级联更新问题

weixin_62533201的博客 1250

redis——数据结构(整数集合,压缩列表)

4、整数集合 整数集合(intset)是 Redis 用于保存整数值的集合抽象数据结构, 可以保存int16_t、int32_t、int64_t的整数值, 并且保证集合中不会出现重复元素。 实现较为简单: typedef struct intset { // 编码方式 uint32_t encoding; // 集合包含的元素数量 uint32_...

少说,多做。 3747

Redis底层数据结构——压缩列表

压缩列表是什么 Redis 中的压缩列表是由一系列特殊编码的连续内存块组成的顺序型数据结构。列表中每个节点可以存储一个字节数组或者一个整数值。 它的存在主要是为了节约内存。 压缩列表应用场景 压缩列表在 Redis 中主要作为了 List 列表和 Hash 哈希两种数据结构的底层实现之一。 在 List 列表中,要是列表中的存储元素数量少且每个元素是小的整数值或者长度较短的字符串,那么列表将使用压缩列表结构作为底层实现。 在 Hash 哈希中,要是哈希中的存储键值对数量少且每个键值对的键和值是小的整数值或者

红橙呀 507

Redis数据结构——压缩列表

6、压缩列表 压缩列表(ziplist)使列表键和哈希键的底层实现之一,当一个列表键只包含少量列表项,并且每个列表项要么就是小整数值,要么就是长度比较短的字符串那么Redis就会使用压缩列表来做列表键的底层实现。 另外,当一个哈希键只包含少量键值对,并且每个键值对的键和值要么是小整数值,要么是长度比较短的字符串,那么Redis就会使用压缩列表来做哈希键的底层实现。 6.1、压缩列表的构成 压缩列表是Redis 为了节约内存而开发的,是由一系列特殊编码的连续内存块组成的顺序型数据结构,一个压缩列表可以包含任意

huangsheng的博客 1163

redis底层数据结构——压缩列表

redis压缩列表

SO_zxn的博客 916

充分探讨Redis压缩列表结构设计的原因

充分探讨Redis压缩列表结构设计的原因

睿智的仓鼠 983

redis数据结构之压缩列表

压缩列表用于存储长度受限的字符串和整数。废话不多说,直接上redis压缩列表的内存结构示意图: 从图中可以看出,redis压缩列表由表示压缩列表占总内存的字节数的zlbytes,表示到达ziplist 表尾节点的偏移量的zltail,表示ziplist 中节点的数量的zllen,各个节点以及用于标记ziplist的末端的zlend。 注意:zllen并不是一直表示节点的数量,只有zll

tym8865的专栏 2787

Redis 数据结构之【压缩列表】

含义: 压缩列表是一块连续的内存空间,元素之间紧挨着存储,没有任何冗余空隙。 内部结构: struct ziplist<T> { int32 zlbytes; // 整个压缩列表占用字节数 int32 zltail_offset; // 最后一个元素距离压缩列表起始位置的偏移量,用于快速定位到最后一个节点 int16 zllength; // 元素个数 T[] entries; // 元素内容列表,挨个挨个紧凑存储 int8 ...

weixin_39815304的博客 285

Redis数据结构 压缩列表

目录 简介 压缩列表的构成 压缩列表节点的构成 previous_entry_length encoding content 连锁更新 压缩列表API 重点回顾 简介 压缩列表(ziplist)是列表键和哈希键的底层实现之一。 当一个列表键只包含少量 列表项,并且每个列表项要么就是小整数值,要么就是长度比较短的字符串,那么Redis就 会使用压缩列表来做列表键的底层实现。 ...

今天吃了吗的博客 530
上一篇: Redis面试题
下一篇: Java集合详解7:HashSet,TreeSet与LinkedHashSet
wrr-cat
博客等级 码龄9年 128粉丝 302原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值