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

Redis压缩列表

区分一下

3.2之前 Redis中的List有两种编码格式 一个是LINKEDLIST 一个是ZIPLIST 这个ZIPLIST就是压缩列表

3.2之后来了一个QUICKLIST QUICKLIST是ZIPLIST和LINKEDLIST的结合体 也就是说Redis中没有ZIPLIST和LINKEDLIST了 然后在Redis5.0引入了LISTPACK用来替换QUiCKLIST中的ZIPLIST在REDIS7.0后完全取代了ZIPLIST

我们有说到压缩列表是List的底层数据结构,压缩列表主要用做为底层数据结构提供紧凑型的数据存储方式,能节约内存(节省链表指针的开销),小数据量的时候遍历访问性能好(连续+缓存命中率友好)。数据量少的时候会用它 

什么情况是数据量小的呢

1.列表对象保存的所有字符串对象长度都小于64字节;

2.列表对象元素个数少于512个,注意,这是LIST的限制,而不是ZIPLIST的限制;

满足以上两点 就会用ZIPLIST编码

ZIPLIST结构

zlbytes:表示该ZIPLIST一共占了多少字节数,这个数字是包含zlbytes本身占据的字节的。(夺大!)

zltail:ZIPLIST 尾巴节点相对于ZIPLIST的开头(起始指针)偏移的字节数。通过这个字段可以快速定位到尾部节点,例如现在有一个ZIPLIST,zl指向它的开头,如果要获取tail尾巴节点,即ZIPLIST里的最后一个节点,可以zl + zltail的值,这样定位到它。如果没有尾节点,就定位到 zlend

zllen:表示有多少个数据节点,在本例中就有3个节点。

entry1~entry3:表示压缩列表数据节点。

zlend:一个特殊的entry节点,表示ZIPLIST的结束。

ZIPLIST节点结构

就是上面的entry1 entry2....

他里面有三个字段

prevlen:表示上一个节点的数据长度。

encoding:编码类型。编码类型里还包含了一个entry的长度信息,可用于正向遍历

entry-data:实际的数据。

prevlen:

通过这个字段可以定位上一个节点的起始地址(或者说开头)也就是就是p-prevlen 可以跳到前一个节点的开头位置,实现从后往前操作,所以压缩列表才可以从后往前遍历。如果前一节点的长度,也就是前一个ENTRY的大小,小于254字节,那么prevlen属性需要用1字节长的空间来保存这个长度值,255是特殊字符,被zlend使用了如果前一节点的长度大于等于254字节,那么prevlen属性需要用5字节长的空间来保存这个长度值注意5个字节中中第一个字节为11111110,也就是254,标志这是个5字节的prelen信息,剩下4字节来表示大小。(这也差太多了 看人家MYSQL里面的可变长度列 少了就1字节 长了就2字节)

encoding:

00pppppp  1字节 String类型,且字符串长度小于2へ6,即小于等于63

 01pppppplqqqqqqqq  2字节 String类型,长度小于2^14次方,即小于等于16383

10000000|qqqqqqqq|rrrrrrrr|ssssssss|tttttttt 5字节 String类型,长度小于2へ32次方

110000001 2个字节的 int16类型

110100001 4个字节的 int32类型

11111110     1个字节的 int64类型

费老劲了 别背 就记住前几位是标识类型 后几位标识长度 对于int类型只标识类型 长度不用标

ZIPLIST性能

查询数据总量

由于ZIPLIST的header定义了记录节点数量的字段zllen,所以通常是可以在O(1)时间复杂度直接返回的,但是呢 zllen是两个字节的 也就是说最多也就能存65534的长度 大于了就存不下了 就得遍历了

遍历去吧 大于65534的节点数 累死 所以他只是应用节点数少的时候

查询指定节点

在ZIPLIST中查询指定数据的节点,需要遍历这个压缩列表,平均时间复杂度是O(N)。

更新数据

ZIPLIST的更新就是增加、删除数据,ZIPLIST提供头尾增减的能力,但是操作平均时间复杂度是O(N),因为在头部增加一个节点会导致后面节点都往后移动,所以更新的平均时间复杂度,可以看作O(N)。其中要注意的是更新操作可能带来连锁更新。注意上面所说的增加节点导致后移,不是连锁更新。连锁更新是指这个后移,发生了不止一次,而是多次。比如增加一个头部新节点,后面依赖它的节点,需要prevlen字段记录它的大小,原本只用1字节记录,因为更新可能膨胀为5字节,然后这个entry的大小就也膨胀了。所以,当这个新数据插入导致的后移完成之后,还需要逐步迭代更新。这种现象就是连锁更新,时间复杂度是O(Nへ2),6.2已经优化为O(N),不用太过担心连锁更新的情况,实际的业务中,很少会刚好遇到需要迭代更新超过2个节点的情况,所以ZIPLIST更新平均时间复杂度,还是可以看作O(N)。不过,ZIPLIST最大的问题还是连锁更新导致性能不稳定。

LISTPACK优化

优化了连锁更新

LISTPACK是为了解决ZIPLIST最大的痛点——连锁更新,我们先来看,ZIPLIST的问题本源。我们知道,ZIPLIST需要支持LIST,LIST是一种双端访问结构,所以需要能从后往前遍历,上面有讲,ZIPLIST的数据节点的结构是这样的:

<prevlen> <encoding> <entry-data>

其中,prevlen就表示上一个节点的数据长度,通过这个字段可以定位上一个节点的数据,可以说,连锁更新问题,就是因为prevlen导致的。

所以我们需要一种不记录prevlen,并且还能找到上一个节点的起始位置的办法,Redis使用了很巧妙的一种方式。我们直接看LISTPACK的节点定义:

1 <encoding-type><element-data><element-tot-len>

encoding-type是编码类型

element-data是数据内容

element-tot-len存储整个节点除它自身之外的长度。

element-tot-len 所占用的每个字节的第一个bit用于标识是否结束。0是结束,1是继续,剩下7个bit来存储数据大小。当我们需要找到当前元素的上一个元素时,我们可以从后向前依次查找每个字节,找到上一个Entry的element-tot-len 字段的结束标识,就可以算出上一个节点的首位置了。举个例子:如果上个节点的element-tot-len为00000001 10000100,每个字节第一个bit标志是否结束,所以这里的element-tot-len一共就两个字节,大小为00000010000100,即132字节。

一些QS

1.ZIPLIST有什么优点

首先肯定是相对于LINKEDLIST

1.节约内存,内存利用率高 2.方便一次性分配 3.遍历时局部性更强

2.ZIPLIST是怎么压缩数据的?

就是看它的结构

然后entry的结构是

他里面的这个entry是紧密相连的 

 3.ZIPLIST下List可以从后往前和从前往后遍历吗

可以 它是双端队列结构 从结构分析 它里面有个encoding结构 包含了长度信息 实现了正向遍历

prelen上一个节点的长度 实现了反向遍历

4.压缩列表插入的时间复杂度是多少?

头部插入是O(N)  他要把后面的数据往后挤  尾部插入O(1)

5.连锁更新的原因如何解决

就跟多米诺骨牌似的 如果上一个节点小于254字节 那下一个节点的prevlen是1长度 要是正好处于这个阈值 更新到了255 那下一个节点就得提升4个字节 那下一个节点也可能提升 balabla

解决就是别保存上一个节点长度 LISTPACK记录的当前节点的长度

相关文章:

Redis压缩列表

区分一下 3.2之前 Redis中的List有两种编码格式 一个是LINKEDLIST 一个是ZIPLIST 这个ZIPLIST就是压缩列表 3.2之后来了一个QUICKLIST QUICKLIST是ZIPLIST和LINKEDLIST的结合体 也就是说Redis中没有ZIPLIST和LINKEDLIST了 然后在Redis5.0引入了LISTPACK用来替换QUiCKLIST中的…...

【SA8295P 源码分析】62 - Android GVM Kernel 内核 make bootimage 过程分析

【SA8295P 源码分析】62 - Android GVM Kernel 内核 make bootimage 过程分析 一、make bootimage 命令执行过程分析1.1 source buid/envsetup.sh 分析1.2 lunch msmnile_gvmq-userdebug 分析1.3 make bootimage:step 1 之 加载配置文件过程分析1.4 make bootimage:step 2 之…...

机器学习——SMO算法推导与实践

一、 硬间隔-SMO算法推导 明天再说&#xff0c;啊。。。。感觉天空明朗了很多&#xff0c;即使现在已经很晚了 还是要打开柯南&#xff0c;看看电视&#xff0c;等待天气预报所说的台风天吧&#xff01; 一时之间&#xff0c;忽然失去了用markdown语法写下推导过程的勇气。。。…...

mac的终端通过code .指令快速启动vscode

通过在vscode中安装"code"命令工具 打开vsocode&#xff0c;使用快捷键⇧⌘P&#xff0c;然后输入shell&#xff0c;会弹出来“Shell命令&#xff1a;在PATH中安装‘code’命令”浮窗&#xff0c;选择安装就可以了&#xff0c;然后就可以在终端通过code .来快速启动…...

前端系统使用iframe下载文件

需求描述 前端调用后端的接口&#xff0c;获取到文件的路径&#xff0c;并下载。 碰到的问题 页面组件存在与云端的组件库&#xff0c;使用window.open()无法满足需求&#xff08;在当前页面下载&#xff09;&#xff0c;因为路径是跨域的&#xff0c;所以决定使用iframe的方…...

RabbitMQ - 简单案例

目录 0.引用 1.Hello world 2.轮训分发消息 2.1 抽取工具类 2.2 启动两个工作线程接受消息 2.4 结果展示 3.消息应答 3.1 自动应答 3.2 手动消息应答的方法 3.3 消息自动重新入队 3.4 消息手动应答代码 4.RabbitMQ 持久化 4.1 队列如何实现持久化 4.2 消息实现持久化 5.不…...

《吐血整理》高级系列教程-吃透Fiddler抓包教程(30)-Fiddler如何抓Android7.0以上的Https包-番外篇

1.简介 通过宏哥前边几篇文章的讲解和介绍想必大家都知道android7.0以上&#xff0c;有android的机制不在信任用户证书&#xff0c;导致https协议无法抓包。除非把证书装在系统信任的证书里&#xff0c;此时手机需要root权限。但是大家都知道root手机是非常繁琐的且不安全&…...

服务器被攻击了怎么办?

服务器被攻击是无法避免的&#xff0c;但是我们能通过做好防护措施&#xff0c;提高服务器的安全性&#xff0c;降低被攻击的几率。那么当服务器已经被 攻击了&#xff0c;怎样才能降低损失呢&#xff1f;该怎样补救&#xff1f; 断开网络 全部的攻击都来自于网络&#xff0c;因…...

P1156 垃圾陷阱(背包变形)

垃圾陷阱 题目描述 卡门――农夫约翰极其珍视的一条 Holsteins 奶牛――已经落了到 “垃圾井” 中。“垃圾井” 是农夫们扔垃圾的地方&#xff0c;它的深度为 D D D&#xff08; 2 ≤ D ≤ 100 2 \le D \le 100 2≤D≤100&#xff09;英尺。 卡门想把垃圾堆起来&#xff0c…...

[Docker实现测试部署CI/CD----构建成功后钉钉告警(7)]

目录 15、钉钉告警创建项目群&#xff0c;然后添加机器人添加机器人Jenkins 系统配置项目配置修改Jenkinsfile文件&#xff0c;添加钉钉提示信息测试 不修改Jenkinsfile文件&#xff0c;添加钉钉提示信息测试 15、钉钉告警 创建项目群&#xff0c;然后添加机器人 首先需要在钉…...

UE5 半透明覆层材质

文章目录 前言介绍示例1示例2示例3 前言 本文采用虚幻5.2.1版本演示&#xff0c;介绍半透明覆层材质&#xff08;覆层材质&#xff09;。 介绍 半透明覆层材质是 UE5.1 版本 更新的功能&#xff0c;使用半透明覆层材质&#xff0c;可以轻松的给物体表面附着一层材质。 在UE5…...

在Raspberry Pi 4上安装Ubuntu 20.04 + ROS noetic(不带显示器)

在Raspberry Pi 4上安装Ubuntu 20.04 ROS noetic&#xff08;不带显示器&#xff09; 1. 所需设备 所需设备&#xff1a; 树莓派 4 B 型 wifi microSD 卡&#xff1a;最小 32GB MicroSD 转 SD 适配器 &#xff08;可选&#xff09;显示器&#xff0c;鼠标等 2. 树莓派…...

CommStudio for .NET Crack

CommStudio for .NET Crack CommStudio for.NET使您的应用程序可以轻松地使用串行端口和调制解调器进行通信。CommStudio for.NET是一套全面的组件和可视化调试工具&#xff0c;可将远程系统和设备与visual Studio 2005和visual Studio 2008集成。开发与遗留系统和外部设备集成…...

蓝桥杯上岸考点清单 (冲刺版)!!!

大家好 我是寸铁&#x1f4aa; 真题千千万万遍&#xff0c;蓝桥省一自然现&#xff01; ✌️ 日更3000里&#xff0c;蓝桥眷顾你 &#x1f31f; 暴力出奇迹&#xff0c;打表过样例 &#x1f44a; 冲刺蓝桥杯省一模板大全来啦 &#x1f525; 蓝桥杯4月8号就要开始了 &#…...

AI一键生成短视频

AI一键生成推文短视频 阅读时长&#xff1a;10分钟 本文内容&#xff1a; 结合开源AI&#xff0c;一键生成短视频发布到常见的某音&#xff0c;某手平台&#xff0c;狠狠赚一笔 前置知识&#xff1a; 1.基本的 python 编程知识 2.chatGPT 使用过 3.stable diffution 使用过 成果…...

基于MATLAB长时间序列遥感数据分析(以MODIS数据处理为例)

MATLAB MATLAB是美国MathWorks公司出品的商业数学软件&#xff0c;用于数据分析、无线通信、深度学习、图像处理与计算机视觉、信号处理、量化金融与风险管理、机器人&#xff0c;控制系统等领域。 [1] MATLAB是matrix&laboratory两个词的组合&#xff0c;意为矩阵工厂&a…...

postgresql之内存池-AllocsetContext

一、简介 postgresql大部分的内存分配管理都是通过MemoryContext进行操作的&#xff0c; 多个相关的MemoryContext构成了一个树型结构&#xff0c; 多个树构成了一个森林。 实现了三种MemoryContext: SlabContextGenerationContextAllocSetContext 使用全局变量CurrentMemo…...

QT 使用单例模式

目录 1. 单例模式介绍 2.单例模式实现 1. 单例模式介绍 有些时候我们在做 qt 项目的时候,要用到很多类. 例如我们用到的类有 A,B,C,D. 其中,A 是 B,C,D 中都需要用到的类,A 类非常的抢手. 但是,A 类非常的占内存,定义一个 A 对象需要 500M 内存,假如在 B,C,D 中都定义一个 A 类…...

接口测试——postman接口测试(三)

目录 1. postman介绍与安装 2. postman发送get请求 3. postman发送post请求 1. postman介绍与安装 安装网址&#xff1a;Postman安装教程&#xff1a;留言找我要即可 2. postman发送get请求 import pymysql from flask import Flask,request# 这里是mysql的基本连接信息 c…...

react中hooks的理解与使用

一、作用 我们知道react组件有两种写法一种是类组件&#xff0c;另一种是函数组件。而函数组件是无状态组件&#xff0c;如果我们要想改变组件中的状态就无法实现了。为此&#xff0c;在react16.8版本后官方推出hooks&#xff0c;用于函数组件更改状态。 二、常用API 1、use…...

STM32的电动自行车信息采集上报系统(学习)

摘要 针对电动自行车实时监管不便的问题&#xff0c;设计了一种基于STM32的电动自行车信息采集系统&#xff0c;通过获取电池、位置和行驶状态信息并上报到服务器中&#xff0c;实现实时监管。 通过多路串口请求电池、行驶状态和位置信息&#xff0c;以并发方式进行数据接收、…...

蓝桥杯上岸每日N题 第七期(小猫爬山)!!!

蓝桥杯上岸每日N题 第七期(小猫爬山)&#xff01;&#xff01;&#xff01; 同步收录 &#x1f447; 蓝桥杯上岸必背&#xff01;&#xff01;&#xff01;(第四期DFS) 大家好 我是寸铁&#x1f4aa; 冲刺蓝桥杯省一模板大全来啦 &#x1f525; 蓝桥杯4月8号就要开始了 &a…...

【Linux系统编程】冯诺依曼体系结构

目录 前言 什么是冯诺依曼体系结构&#xff1f; 冯诺依曼体系结构如何进行数据处理的&#xff1f; 存储器在冯诺依曼体系中有什么作用&#xff1f; 冯诺依曼体系结构为什么要这样设计&#xff1f; 冯诺依曼结构总结 前言 相信对于冯诺依曼这个人的名字大家一定不会感到陌…...

数据结构--动态顺序表

文章目录 线性表动态顺序表数组与顺序表 接口实现初始化&#xff1a;尾插&#xff1a;尾删头插头删指定位置插入指定位置删除查找摧毁 完整代码 线性表 线性表是数据结构中最基本、最简单也是最常用的一种数据结构。线性表是指由n个具有相同数据类型的元素组成的有限序列。 线…...

笔试数据结构选填题

目录 卡特兰数Catalan&#xff1a;出栈序列/二叉树数 树 二叉树 N01N2 哈夫曼树&#xff08;最优二叉树&#xff09;Huffman 度m的哈夫曼树只有度为0和m的结点&#xff1a;Nm(n-1)/(m-1) 平衡二叉树AVL Nh表示深度为h最少结点数&#xff0c;则N00&#xff0c;N11&#…...

# 鸢尾花的案例学习

# 鸢尾花的案例学习 # 1. 导入小型的数据 from sklearn.datasets import load_iris import numpy as np import pandas as pd import seaborn as sbn import matplotlib.pyplot as plt # 2. 获取数据 irisload_iris() # 3.查看数据print("数据集\n ",len(iris.d…...

线程、进程的区别

线程、进程的区别 在开发中&#xff0c;我们经常听到线程和进程两个概念&#xff0c;它们都是操作系统的基本概念&#xff0c;操作系统以进程为基本单位分配存储器&#xff0c;以线程为基本单位分配CPU。虽然它们有很多相似之处&#xff0c;但是它们也有很大的区别。本文将详细…...

在 Ubuntu 上安装 Docker 桌面

Ubuntu 22.04 (LTS) 安装 Docker 桌面 要成功安装 Docker Desktop&#xff0c;您必须&#xff1a; 满足系统要求拥有 64 位版本的 Ubuntu Jammy Jellyfish 22.04 (LTS) 或 Ubuntu Impish Indri 21.10。对于非 Gnome 桌面环境&#xff0c;必须安装 gnome-terminal&#xff1a;…...

【WebRTC---序篇】(七)RTC多人连麦方案

服务端可以选择mediasoup&#xff0c;作为SFU服务器&#xff0c;只负责转发数据 下图举例三个Client (browser或者客户端)同时加入一个房间&#xff0c;每个app同时发布一路视频和一路音频&#xff0c;并且接受来自其他app的音视频流&#xff0c;mediasoup内部的结构如下&…...

【Java可执行命令】(十六)诊断命令请求发送工具 jcmd:提供一种简单而强大的方式来管理和监控 Java 进程 ~

Java可执行命令之jcmd 1️⃣ 概念2️⃣ 优势和缺点3️⃣ 使用3.1 语法格式3.2 jcmd -l&#xff1a;列出正在运行的 Java 进程3.3 jcmd < pid> help&#xff1a;列出特定进程的诊断命令列表3.4 jcmd < pid> < command>&#xff1a;执行诊断命令 4️⃣ 应用场景…...