Redis数据结构之listpack
前言
当数据量较小时,Redis 会优先考虑用 ziplist 来存储 hash、list、zset,这么做可以有效的节省内存空间,因为 ziplist 是一块连续的内存空间,它采用一种紧凑的方式来存储元素。但是它也有缺点,比如查找的时间复杂度高、内存分配的开销、连锁更新的风险等。
于是 Redis 在 3.0 版本推出了 quicklist,它可以看作是 ziplist 的升级版,本质是把多个 ziplist 串联成链表,把每个 ziplist 限制在一定的大小,以此来降低 内存分配、连锁更新 的影响,但是它并没有完全解决连锁更新的问题,并且链表的每个节点也是要额外占用内存的。
Redis 5.0 终于推出了一个新的紧凑列表 listpack,它沿用了 ziplist 的内存布局,元素紧挨在一起,没有指针的额外开销,同时解决了连锁更新的问题。
listpack
listpack 的设计和 ziplist 如出一辙,如果你了解 ziplist,相信很容易理解 listpack。
listpack 也叫 紧凑列表,它采用紧凑的内存布局,本质上仍是一个字节数组。为了节省空间,它采用了多种编码方式来表示不同长度的整型和字符串。最后,它不再像 ziplist 一样元素还要记录上一个元素的大小,而是记录当前元素的大下,彻底解决了连锁更新的问题。

- totalbytes:listpack 占用的字节数,4 字节
- size:listpack 元素数量,2 字节
- element:元素
- end:结尾符 0xFF 1 字节
totalbytes + size 也被称作 listpack 头部,大小是 6 字节,再加上 1 字节的结尾符,所以一个空的 listpack 大小是 7 字节。
编码方式
为了节省内存,listpack 针对不同长度的整型和字符串定义了多种编码方式:
#define LP_ENCODING_7BIT_UINT 0
#define LP_ENCODING_13BIT_INT 0xC0
#define LP_ENCODING_16BIT_INT 0xF1
#define LP_ENCODING_24BIT_INT 0xF2
#define LP_ENCODING_32BIT_INT 0xF3
#define LP_ENCODING_64BIT_INT 0xF4
#define LP_ENCODING_6BIT_STR 0x80
#define LP_ENCODING_12BIT_STR 0xE0
#define LP_ENCODING_32BIT_STR 0xF0
- _UINT 结尾:无符号整型
- _INT 结尾:有符号整型
- _STR 结尾:字符串
这里对编码方式举例解释一下,其它几种以此类推:
- LP_ENCODING_7BIT_UINT:代表 7Bit 无符号整型,1 个字节表示,高 1 位是 0,低 7 位表示整型值
- LP_ENCODING_13BIT_INT:代表 13Bit 有符号整型,2 字节表示,高 3 位是 110,低 13 位 表示整型值
- LP_ENCODING_6BIT_STR:长度不超过 63 的字符串。1 字节表示 encoding,高 2 位是 10,低 6 位代表字符串的长度,data 部分是具体的字符串值
避免连锁更新
listpack 彻底解决了 ziplist 连锁更新的问题,怎么做的呢?
ziplist 为什么会存在连锁更新的问题?就是因为每个元素要记录上一个元素的长度,而且采用变长字节记录,小于 254 就用1字节,否则用5字节。如此一来,某个元素修改时,影响的就不仅仅是自己了,还会影响后面的元素,引发连锁反应。
listpack 解决方式就是元素不再记录上一个元素的大小了,而是改为记录自身的大小,这样元素与元素之间就独立了,不会相互影响到。
遍历问题
ziplist 元素记录上一个元素的大小,是为了支持从后向前遍历。listpack 改为记录元素自身大小了,那么还支持双向遍历吗?
答案是支持的,我们来看一下双向遍历的过程。
- 正向遍历
正向遍历时,listpack 首先跳过 6 字节的头部,指针就会指向第一个元素,再根据元素的 encoding 字段得到元素的长度和类型,然后就可以正常访问元素了。再根据 encoding 计算当前元素长度占用的字节数,跳过当前元素占用的字节数,就可以访问下一个元素了,直到访问到结尾符,代表结束。
- 反向遍历
首先访问 listpack 的前4字节得到总长度,然后就可以定位到末尾结尾符位置。然后指针左移就可以访问到最后一个元素的长度 len,指针再左移 len 就可以访问最后一个元素的 encoding,根据编码方式访问元素。指针再左移又可以访问到倒数第2个元素的长度,以此类推。
访问元素长度len字段时,有一个关键点,就是如何判断 len 部分结束了。因为 len 可能占用1字节,也可能占用多个字节。listpack 的做法是,每个字节只使用 7 Bit,最高位来表示是否还要继续读。
尾巴
listpack 是 Redis 对 ziplist 的改进版本,彻底解决 ziplist 连锁更新的问题。紧凑的内存布局,避免了传统链表指针带来的访问效率和内存占用问题,非常适合小数据量的存储。
需要注意的是,listpack 查询效率依然是 O(N),查找时间会随着元素数量线性增长,不过好在 Redis 基本拿它存储少量数据,所以 N 的值一般不会太大。
相关文章:
Redis数据结构之listpack
前言 当数据量较小时,Redis 会优先考虑用 ziplist 来存储 hash、list、zset,这么做可以有效的节省内存空间,因为 ziplist 是一块连续的内存空间,它采用一种紧凑的方式来存储元素。但是它也有缺点,比如查找的时间复杂度…...
VMware 配置记录
VMware 配置笔记 CentOS 7.9 镜像下载 官网太慢,建议在阿里云镜像站去CentOS配置页找标准版下载。 选标准版即可,各版本区别: DVD:标准版,包含常用软件,体积为 4.4 G;Everything:…...
【Java基础面试十四】、 封装的目的是什么,为什么要有封装?
文章底部有个人公众号:热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享? 踩过的坑没必要让别人在再踩,自己复盘也能加深记忆。利己利人、所谓双赢。 面试官: 封装的目的是什么&…...
阿里云2023年双十一优惠活动整理
随着双十一的临近,阿里云也为大家准备了一系列优惠活动。作为国内知名的云服务提供商,阿里云在双十一期间推出了多种优惠政策和福利,让用户在享受优质云服务的同时,也能节省一些费用。本文将对阿里云双十一优惠活动进行详细整理&a…...
HTML标签详解 HTML5+CSS3+移动web 前端开发入门笔记(四)
HTML中列表的作用 HTML中的列表(List)用于呈现按照一定逻辑关系组织的信息,以便用户更好地理解和识别。列表可以分为有序列表、无序列表和定义列表三种类型。 有序列表(Ordered List):用于表示按照一定顺序…...
lenovo联想笔记本ThinkPad系列T15p或P15v Gen3(21DA,21DB,21D8,21D9)原厂Win11系统镜像
下载链接:https://pan.baidu.com/s/1V4UXFhYZUNy2ZQ8u4x1AFg?pwdqz0s 系统自带指纹驱动、人脸识别驱动、显卡、声卡等所有驱动、出厂主题壁纸、Office办公软件、Lenovo联想电脑管家等预装程序 所需要工具:32G或以上的U盘 文件格式:ISO …...
【SpringBoot】拦截器(Interceptor)的使用
感兴趣的可以查看上一篇过滤器的使用 【Springboot】Filter 过滤器的使用 一、什么是拦截器 拦截器(Interceptor)是一种特殊的组件,它可以在请求处理的过程中对请求和响应进行拦截和处理。拦截器可以在请求到达目标处理器之前、处理器处理请…...
CS鱼饵制作
文章目录 宏病毒(宏钓鱼)快捷方式钓鱼shellQMaker bug伪装pdf文件上线 宏病毒(宏钓鱼) 启动teamsever服务器,具体过程请参考我之前的文章: 在主机中启动CS客户端,111是真实机的用户:…...
问题记录1 json解析问题
问题: json解析int类型不符合预期,使用json.NewDecoder解决。 示例如下: package mainimport ("bytes""encoding/json""fmt" )func main() {data1 : map[string]interface{}{}data1["id"] int64(4…...
std::move以及右值引用等
在这里只能给出 s t d : : m o v e std::move std::move一个比较通俗的看法,不能从原理上深挖,真是惭愧。不过这里面涉及到一些小 t r i c k trick trick,还是挺有意思的。 先说 s t d : : m o v e std::move std::move的两个用法:…...
分享一个比对图片是否一致的小工具(来源: github)
运行效果图: 官网: GitHub - codingfishman/image-diff: 一个方便的图片对比工具一个方便的图片对比工具. Contribute to codingfishman/image-diff development by creating an account on GitHub.https://github.com/codingfishman/image-diff 优缺点: 1.采用比对各色块是…...
编写AA程序需要做以下几个步骤:
编写AA程序需要做以下几个步骤: 首先,需要选择一个合适的开发环境,如Visual Studio或Eclipse,并安装AUTOSAR插件或工具链。 其次,需要创建一个AA项目,并配置相关的参数,如目标机器、编译器选项、链接选项等。 然后,需要编写AA代码,并遵循AUTOSAR规范和编码指南。 …...
jmeter接口测试使用rsa加密解密算法
本篇介绍jmeter 使用rsa算法进行加密参数 如果测试过程中,部分接口采用了rsa加密算法,我们的jmeter 也是可以直接拿来调用的,不需要开发配合去掉加密代码! 直接上代码 import org.apache.commons.codec.binary.Base64; import j…...
IDEA通过Docker插件部署SpringBoot项目
1、配置Docker远程连接端口 找到并编辑服务器上的docker.service文件。 vim /usr/lib/systemd/system/docker.service在下面ExecStart替换成下面的 ExecStart/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock2.重启docker systemctl daemon-reload s…...
微查系统,一站式查询,让您的查询更加便捷
微查系统是挖数据一款功能强大的查询系统,是一个集多种查询和核验工具于一身的综合性平台。它可以大大简化企业和个人的查询流程,节省时间和成本,提高查询的准确性和效率。本文将介绍微查系统的主要特点,功能和使用方法࿰…...
C++stack和queue模拟实现以及deque的介绍
stack和queue介绍以及模拟实现 1.stack1.1stack的介绍1.2stack的使用 2.queue2.1queue的介绍2.2queue的使用 3.容器适配器3.1什么是适配器 4.stack模拟实现5.queue的模拟实现6.deque(双端队列) 1.stack 1.1stack的介绍 stack的文档介绍 stack是一种容…...
WPF ListView 鼠标点击,移动改变背景色不启作用
构建数据源 <Window.Resources><x:ArrayExtension x:Key"stringList"xmlns"clr-namespace:System;assemblymscorlib"Type"String"><String>第一行</String><String>第二行</String><String>第三行<…...
Maven Dependency 机制
依赖关系管理是Maven的核心功能。管理单个项目的依赖关系很容易。管理由数百个模块组成的多模块项目和应用程序的依赖关系是可能的。Maven在定义、创建和维护具有良好定义的类路径和库版本的可复制构建方面有很大帮助。 一、传递依赖 Maven通过自动包含可传递的依赖关系&…...
CustomShapes/自定义形状, CustomCurves/自定义曲线, AnimateableData/数据变化动画 的使用
1. CustomShapes 自定义形状视图 1.1 资源图文件 therock.png 1.2 创建自定义形状视图 CustomShapesBootcamp.swift import SwiftUI/// 三角形 struct Triangle: Shape{func path(in rect: CGRect) -> Path {Path { path inpath.move(to: CGPoint(x: rect.midX, y: rect.mi…...
软件测试用例设计方法-因果图法
边界值法是等价类划分法的补充,所以,它们是一对搭档。 那么,判定表法有没有它的搭档呢? 答案是,有的。那就是本篇文章分享的用例设计方法—— 因果图法 。 定义 因果图法: 用来处理等价类划分和边界值考…...
51c自动驾驶~合集58
我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留,CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制(CCA-Attention),…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...
渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...
为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...
