13- Redis 中的 压缩列表 数据结构

压缩列表的最大特点,就是它被设计成一种内存紧凑型的数据结构,占用 一块连续的内存空间,不仅可以利用 CPU 缓存,而且会针对不同长度的数据,进行相应编码,这种方法可以有效的节省内存开销。

但是,压缩列表的缺陷也是有的:

  • 不能保存过多的元素,否则查询效率就会降低;

  • 新增或修改某个元素时,压缩列表占用的内存空间需要重新分配,甚至可能引发连锁更新的问题。

因此,Redis 对象(List 对象、Hash 对象、Zset 对象)包含的元素数量较少、或者元素值不大的情况才会使用压缩列表作为底层数据结构。

1. 压缩列表结构设计

压缩列表是 Redis 为了节约内存而开发的,它是由连续内存块组成的顺序型数据结构,有点类似于数组。

压缩列表在表头由三个字段:

  • zlbytes,记录整个压缩列表占用堆内存字节数;

  • zltail,记录压缩列表【尾部】节点距离起始地址有多少字节,也就是列表尾的偏移量;

  • zllen,记录压缩列表包含的节点数量;

表尾有一个字段:

  • zlend,标记压缩列表的结束点,固定值 0xFF(十进制 255)

在压缩列表中,如果我们要查找定位第一个元素和最后一个元素元素,可以通过表头第三个字段(zllen)的长度直接定位,复杂度是 O(1),而查找其他元素时,就没有这么高效了,只能逐个查找,此时的复杂度就是 O(N) 了,因此压缩列表不适合保存过多的元素

另外,压缩列表节点(entry)的构成如下:

  • prevlen,记录了【前一个节点】的长度,目的是为了实现从后向前遍历;

  • encoding,记录了当前节点实际数据的【类型和长度】,类型主要有两种:字符串和整数

  • data,记录了当前节点的实际数据,类型和长度都由 encoding 决定;

当我们往压缩列表中插入数据时,压缩列表就会根据数据类型是字符串还是整数,以及数据的大小,会使用不同空间大小的 prevlen 和 encoding 这两个元素里保存的信息,这种根据数据大小和类型进行不同的空间大小分配的设计思想,正是 Redis 为了节省内存而采用的

分别说下,prevlen 和 encoding 是如何根据数据的大小和类型来进行不同的空间大小分配。

压缩列表里的每个节点中的 prevlen 属性都记录了【前一个节点的长度】,而且 prevlen 属性的空间大小跟前一个节点长度值有关,比如:

  • 如果前一个节点的长度小于 254 字节,那么 prevlen 属性需要用 1 字节的空间来保存这个长度值

  • 如果前一个节点的长度大于等于 254 字节,那么 prevlen 属性需要用 5 个字节的空间来保存这个长度值

encoding 属性的空间大小跟数据是字符串还是整数,以及字符串的长度有关,如下图(下图的 content 表示的是实际数据,即本文的 data 字段):

  • 如果当前节点的数据是整数,则 encoding 会使用 1 字节的空间进行编码,也就是 encoding 长度为 1 字节。通过 encoding 确认了整数类型,就可以确认整数数据的实际大小了,比如如果 encoding 编码确认了数据是 int16 整数,那么 data 的长度就是 int16 的大小了。

  • 如果当前节点的数据是字符串,根据字符串的长度大小,encoding 会使用 1 字节/2 字节/5 字节的空间进行编码,encoding 编码的前两个 bit 表示数据的类型,后续的其他 bit 标识字符串数据的实际长度,即 data 的长度。

2. 连锁更新

压缩列表除了查找复杂度高的问题,还有一个问题。

压缩列表新增某个元素或修改某个元素时,如果空间不够,压缩列表占用的内存空间就需要重新分配。而当新插入的元素较大时,可能会导致后续元素的 prevlen 占用空间都发生变化,从而引起【连锁更新】问题,导致每个元素的空间都要重新分配,造成访问压缩列表性能的下降。

前面提到,压缩列表节点的 prevlen 属性会根据前一个节点的长度进行不同的空间大小分配:

  • 如果前一个节点的长度小于 254 字节,那么prevlen 属性需要用 1 字节的空间来保存这个长度值;

  • 如果前一个节点的长度大于等于 254 字节,那么prevlen 属性需要用 5 字节的空间来保存这个长度值;

现在假设一个压缩列表中有多个连续的、长度在 250 ~ 253 之间的节点,如下图:

因为这些节点长度值小于 254 字节,所以 prevlen 属性需要用 1 字节的空间来保存这个长度值。

这时,如果将一个长度大于等于 254 字节的新节点加入到压缩列表的表头节点,即新节点将成为 e1 的前置节点,如下图:

因为 e1 节点的 prevlen 属性只有 1 个字节大小,无法保存新节点的长度,此时就需要对压缩列表的空间重新分配操作,并将 e1 节点的 prevlen 属性从原来的 1 字节大小扩展为 5 字节大小。

多米诺牌的效应就此开始

开始。

e1 原本的长度在 250 ~ 253 之间,因为刚才的扩展空间,此时 e1 的长度就大于等于 254 了,因此原本 e2 保存 e1 的 prevlen 属性也必须从 1 字节扩展至 5 字节大小。

正如扩展 e1 引发了对 e2 的扩展一样,扩展 e2 也会引发对 e3 的扩展,而扩展 e3 又会引发对 e4 的扩展...一直持续到结尾。

这种在特殊情况下产生的连续多次空间扩展操作就叫做【连锁更新】,就像多米诺牌的效应一样,第一张牌倒下了,推动了第二张牌倒下;第二张牌倒下,又推动了第三张牌倒下...

3. 压缩列表的缺陷

空间扩展操作也就是重新分配内存,因此连锁更新一旦发生,就会导致压缩列表占用的内存空间要多次重新分配,这就会直接影响到压缩列表的访问性能

所以说,虽然压缩列表紧凑型的内存布局能节省内存开销,但是如果保存的元素数量增加了,或是元素变大了,会导致内存重新分配,最糟糕的是会有【连锁更新】的问题

因此,压缩列表只会用于保存的节点数量不多的场景,只要节点数量足够小,即使发生连锁更新,也是能接受的。

虽说如此,Redis 针对压缩列表在设计上的不足,在后来的版本中,新增设计了两种数据结构:quicklist(Redis 3.2 引入)和 listpack(Redis 5.0 引入)。这两种数据结构的设计目标,就是尽可能地保持压缩列表节省内存的优势,同时解决压缩列表的【连锁更新】的问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/683233.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C#-foreach循环语句

foreach循环语句 语法: foreach(数据类型 变量名 in 数组或集合对象) { 语句块; } foreach 会在每次循环的过程中,依次从数组或集合对象中取出一个新的元素放foreach( )里定义的变量中,直到所有元素都成功取出后退出循环。 foreach循环…

Mysql root用户远程连接失败解决方案

最近,踩坑云服务器通过root用户远程连接Mysql数据库失败,Mysql 版本为 5.7.44,原因如下,因为root用户权限过大,可能会有风险操作,可以新增其他用户来解决此问题,如果一定要用root用户&#xff0…

C# Onnx E2Pose人体关键点检测

C# Onnx E2Pose人体关键点检测 目录 效果 模型信息 项目 代码 下载 效果 模型信息 Inputs ------------------------- name:inputimg tensor:Float[1, 3, 512, 512] --------------------------------------------------------------- Outputs ---…

【python010】获取任意多边形区域内的经纬度点并可视化

1.熟悉、梳理、总结项目研发实战中的Python开发日常使用中的问题、知识点等,如获取任意多边形区域内的经纬度点并可视化,找了N篇文章没发现有效的解决方案。 2.欢迎点赞、关注、批评、指正,互三走起来,小手动起来! 3.欢…

Leetcode刷题(四十)

Pow(x, n)(Medium) 实现 pow(x, n) ,即计算 x 的整数 n 次幂函数(即,xn )。示例 1:输入:x 2.00000, n 10 输出:1024.00000 示例 2:输入:x 2.1…

微服务Day7学习-数据聚合、同步、补全

文章目录 数据聚合聚合分类 自动补全DSL实现Bucket聚合DSL实现Metrics聚合RestAPI实现聚合多条件聚合对接前端接口拼音分词器自定义分词器自动补全查询实现酒店搜索框自动补全 数据同步数据同步思路分析利用mq实现mysql与elasticsearch数据同步 集群介绍搭建ES集群 数据聚合 聚…

电拖基础JIAOXUE

1.最简单的TT马达,实际就是一个减速电机: 减速箱的内部包含了一组齿轮。在实际的使用中,绝大部分的电动机都要和减速箱配合使用,因为一般的电机转速都在每分钟几千转甚至1万转以上,而在实际的使用中并不需要这么快的转…

RN:Error: /xxx/android/gradlew exited with non-zero code: 1

问题 执行 yarn android 报错: 解决 这个大概率是缓存问题,我说一下我的解决思路 1、yarn doctor 2、根据黄色字体提示,说我包版本不对(但是这个是警告应该没事,但是我还是装了) npx expo install --…

Lodop 实现局域网打印

文章目录 前言一、Lodop支持打印的方式lodop 打印方式一般有3种:本地打印局域网集中打印广域网AO打印 二、集成步骤查看lodop 插件的服务端口:查看ip后端提供接口返回ip,前端动态获取最后步骤 前言 有时候会根据不同的ip来获取资源文件&…

计算机网络 期末复习(谢希仁版本)第6章

DNS采用UDP。 DHCP 给运行服务器软件、且位置固定的计算机指派一个永久地址,给运行客户端软件的计算机分配一个临时地址

文件无法在当前环境下执行在 x86_64 系统上运行 ARM 可执行文件

目录 遇到的问题是由于"..."文件无法在当前环境下执行。这个错误通常是因为二进制文件的格式不兼容,可能是因为它是为不同的架构编译的。例如,如果二进制文件是为 x86 架构编译的,但你在 ARM 设备上尝试运行它,就会出现…

语言模型测试系列【9】

语言模型 文心一言讯飞星火通义千问2.5豆包360智脑百小应腾讯元宝KimiC知道 好长时间没有做语言模型的测试了,一方面是没有好的素材,各模型都在升级优化,而且频率很高;另一方面近期在阅读和学习其他的知识,所以更的也…

Typora编辑的markdown文档莫名其妙消失或未保存--解决方案【亲测可行】

由于误触键盘导致文件关闭,打开文件之后发现里面文字全没了~气死了!!!! 可以通过如下方法解决! 一、打开typora 二、【文件】-【偏好设置】 三、点击恢复未保存的草稿,找到最近的文件复制粘贴…

针对AlGaN/GaN高电子迁移率晶体管的显式表面电势计算和紧凑电流模型

来源:An Explicit Surface Potential Calculation and Compact Current Model for AlGaN/GaN HEMTs(EDL 15年) 摘要 在本文中,我们提出了一种新的紧凑模型,用于基于费米能级和表面电位的显式解来描述AlGaN/GaN高电子迁移率晶体管。该模型计算…

【LLM】度小满金融大模型技术创新与应用探索

note 从通用大模型到金融大模型金融大模型的训练技术创新金融大模型的评测方法创新金融大模型的应用实践创新总结:金融大模型迭代路径 一、轩辕大模型 二、垂直大模型训练 1. 数据准备 数据质量是模型效果的保障。首先数据要丰富,这是必备的条件。我们…

hcache缓存查看工具

1、hcache概述 hcache是基于pcstat的,pcstat可以查看某个文件是否被缓存和根据进程pid来查看都缓存了哪些文件。hcache在其基础上增加了查看整个操作系统Cache和根据使用Cache大小排序的特性。官网:https://github.com/silenceshell/hcache 2、hcache安装 2.1下载…

Python Flask 入门开发

Python基础学习: Pyhton 语法基础Python 变量Python控制流Python 函数与类Python Exception处理Python 文件操作Python 日期与时间Python Socket的使用Python 模块Python 魔法方法与属性 Flask基础学习: Python中如何选择Web开发框架?Pyth…

【Tool】Matlab 数据分析可视化

一、问题描述 近期围绕imu总是出现问题,自己整理了一下将数据可视化的工具 二、imu 类 1. 待处理数据格式 # yaw roll pitch time -2.08131 -0.0741765 0.0200713 121.281000000 -2.08724 -0.0745256 0.0197222 121.301000000 -2.093 -0.075747…

【机器学习基础】Python编程01:五个实用练习题的解析与总结

Python是一种广泛使用的高级编程语言,它在机器学习领域中的重要性主要体现在以下几个方面: 简洁易学:Python语法简洁清晰,易于学习,使得初学者能够快速上手机器学习项目。 丰富的库支持:Python拥有大量的机器学习库,如scikit-learn、TensorFlow、Keras和PyTorch等,这些…

吴恩达2022机器学习专项课程C2W3:2.24 机器学习实践建议(决定下一步做什么模型评估模型选择交叉验证)

目录 引言一、绘图评估模型的局限性二、使用测试集评估模型1.线性回归2.逻辑回归3.测试误差与泛化误差 三、测试集评估模型存在的问题1.评估模型流程2.流程存在的问题 四、解决问题1.训练集分割成三段2.计算交叉验证集的误差 五、重新评估模型1.线性回归模型2.神经网络模型3.评…