Redis 中 string 和 list 的原理说明

news2025/3/10 14:48:37

Redis 中 string 和 list 的底层实现

Redis有5种基础数据结构,对应的value分别为:string (字符串)、list (列表)、set (集合)、hash (哈希) 和 zset (有序集合)

Redis 对象头结构体:

struct RedisObject {
	int4 type; // 4bits 对象的基本类型
	int4 encoding; // 4bits 对象的编码方式
	int24 lru; // 24bits 对象的最近访问时间(Least Recently Used)
	int32 refcount; // 4bytes 对象的引用计数
	void *ptr; // 8bytes,64-bit system 指向对象的实际存储位置
} robj;

string

结构

Redis的字符串是动态字符串,是可以修改的字符串,内部结构实现上类似于Go的slice切片,采用预分配冗余空间的方式来减少内存的频繁分配

img

  • 内部为当前字符串实际分配的空间capacity一般要高于实际字符串长度len
  • 当字符串长度小于1M时,扩容加倍;大于1M时,扩容增加1M
  • 字符串最大长度为512M
sds

虽然Redis是用c实现的,但是他们的string结构并不相同,Redis中的字符串是可以修改的字符串,在内存中它是以字节数组的形式存在的

Redis 的字符串叫「SDS」,也就是 Simple Dynamic String,是一个带长度信息的字节数组

struct SDS<T> {
	T capacity; // 数组容量   使用泛型表示
	T len; // 数组长度      使用泛型表示
	byte flags; // 特殊标识位.
	byte[] content; // 数组内容   字节数组
}

T:当字符串比较短时,len和capacity可以使用byte和short来表示,Redis为了对内存做极致的优化,不同长度的字符串使用不同的结构体来表示

编码方式

sds编码

img

当字符串长度小于或等于 44 字节 时,Redis 使用 embstr 编码(embedded string 嵌入式)

当字符串长度大于 44 字节 时,Redis 使用 raw 编码

整数编码

当存储的值是一个小整数时,Redis 会使用整数编码来存储,这样可以节省内存

list

Redis 的List类型是一个简单的字符串列表,支持从头部或尾部插入和删除元素。它的底层实现方式取决于列表的大小和元素的特性

双向链表(LinkedList)

在Redis3.2之前,当List的元素数量较多或元素较大时,Redis使用双向链表作为底层数据结构

// 节点
typedef struct listNode {
    struct listNode *prev;	//上一元素
    struct listNode *next;	//下一元素
    void *value;	//元素值
} listNode;

// 双向链表
typedef struct list {
	// 头结点
    listNode *head;
    // 尾元素
    listNode *tail;
    // 元素值复制函数
    void *(*dup)(void *ptr);
    // 元素值释放函数
    void (*free)(void *ptr);
    // 元素值对比函数
    int (*match)(void *ptr, void *key);
    // 元素长度
    unsigned long len;
} list;

img

压缩链表(ziplist)

当List中的元素数量较少(默认小于512个)且每个元素的大小较小(默认小于 64 字节)时,Redis会使用 ziplist

img

  • zlbytes:4 字节,记录整个 Ziplist 占用的内存字节数
  • zltail:4 字节,记录 Ziplist 表尾节点的偏移量
  • zllen:2 字节,记录 Ziplist 中的节点数量
  • entry:列表节点,每个节点的长度由其内容决定
  • zlend:1 字节,标记 Ziplist 的结束(值为 0xFF)

快排列表(quicklist)

结构

在3.2之后,Redis使用Quicklist

Quicklist是由多个压缩列表(ziplist)组成的双向链表,每个压缩列表称为一个节点

// quicklist.h

typedef struct quicklistEntry {
    unsigned char *value; // 存储的值
    unsigned int sz; // 值得长度
    long long longval; // 如果是整数,这里存储整数表示
    unsigned int encoding:4; // 值得编码方式
    unsigned int attempted_float_conversion:1; // 是否尝试过将值转换为浮点数
} quicklistEntry;

typedef struct quicklistNode {
    struct quicklistNode *prev; // 前一个节点
    struct quicklistNode *next; // 下一个节点
    unsigned char *zl; // 指向ziplist
    unsigned int sz; // ziplist的大小
    unsigned int count:16; // ziplist中的元素数量
    unsigned int encoding:4; // 编码类型
    unsigned int container:4; // 容器类型
    unsigned int recompress:1; //是否需要重新压缩
} quicklistNode;

typedef struct quicklist {
    quicklistNode *head; // 头节点
    quicklistNode *tail; // 尾节点
    const quicklistCompress *compress; // 压缩深度
    unsigned int count; // 节点数量
    unsigned long len; // 总元素数量
    signed int fill : QL_FILL_BITS; // 每个节点的填充因子
    unsigned int compress : QL_COMP_BITS; // 压缩深度
    unsigned int bookmark_count: QL_BM_BITS; // 书签数量
    quicklistBookmark bookmarks[]; // 书签数组
} quicklist;

主要的数据结构包括:

  • quicklistEntry:表示 quicklist 中的一个条目(entry)
  • quicklistNode:表示 quicklist 中的一个节点,包含一个 ziplist
  • quicklist:整个 quicklist 结构,包含头尾节点、统计信息等
工作原理
  1. 节点存储
    • 每个 quicklistNode 包含一个 ziplist,用于紧凑存储多个元素。
    • ziplist 是一种紧凑的内存结构,适合存储小数据项。
  2. 动态调整
    • 当向 Quicklist 中插入数据时,Redis 会根据配置的 list-max-ziplist-size 参数决定是否需要创建新的节点。
    • 如果当前 ziplist 达到大小限制,Redis 会创建一个新的 quicklistNode,并在新节点中创建一个新的 ziplist。
  3. 压缩策略
    • Quicklist 支持对中间节点进行压缩,以节省内存。
    • 压缩深度由 list-compress-depth 参数控制,可以指定两端不压缩的节点数量。
  4. 内存管理
    • Quicklist 通过合理控制 ziplist 的大小,避免大规模连续内存申请。
    • 压缩和解压缩使用 LZF 算法,适合实时应用。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DeepLabv3+改进6:在主干网络中添加SegNext_Attention|助力涨点

🔥【DeepLabv3+改进专栏!探索语义分割新高度】 🌟 你是否在为图像分割的精度与效率发愁? 📢 本专栏重磅推出: ✅ 独家改进策略:融合注意力机制、轻量化设计与多尺度优化 ✅ 即插即用模块:ASPP+升级、解码器 PS:订阅专栏提供完整代码 目录 论文简介 步骤一 步骤二…

亚信安全发布2024威胁年报和2025威胁预测

在当今数字化时代&#xff0c;网络空间已成为全球经济、社会和国家安全的核心基础设施。随着信息技术的飞速发展&#xff0c;网络连接了全球数十亿用户&#xff0c;推动了数字经济的蓬勃发展&#xff0c;同时也带来了前所未有的安全挑战。2024年&#xff0c;网络安全形势愈发复…

[数据分享第七弹]全球洪水相关数据集

洪水是一种常见的自然灾害&#xff0c;在全球范围内造成了极为严重的威胁。近年来&#xff0c;针对洪水事件的检测分析&#xff0c;以及对于洪水灾害和灾后恢复能力的研究日渐增多&#xff0c;也产生了众多洪水数据集。今天&#xff0c;我们一起来收集整理一下相关数据集。&…

MySQL 面试篇

MySQL相关面试题 定位慢查询 **面试官&#xff1a;**MySQL中&#xff0c;如何定位慢查询? 我们当时做压测的时候有的接口非常的慢&#xff0c;接口的响应时间超过了2秒以上&#xff0c;因为我们当时的系统部署了运维的监控系统Skywalking &#xff0c;在展示的报表中可以看到…

【Andrej Karpathy 神经网络从Zero到Hero】--2.语言模型的两种实现方式 (Bigram 和 神经网络)

目录 统计 Bigram 语言模型质量评价方法 神经网络语言模型 【系列笔记】 【Andrej Karpathy 神经网络从Zero到Hero】–1. 自动微分autograd实践要点 本文主要参考 大神Andrej Karpathy 大模型讲座 | 构建makemore 系列之一&#xff1a;讲解语言建模的明确入门&#xff0c;演示…

Android MVC、MVP、MVVM三种架构的介绍和使用。

写在前面&#xff1a;现在随便出去面试Android APP相关的工作&#xff0c;面试官基本上都会提问APP架构相关的问题&#xff0c;用Java、kotlin写APP的话&#xff0c;其实就三种架构MVC、MVP、MVVM&#xff0c;MVC和MVP高度相似&#xff0c;区别不大&#xff0c;MVVM则不同&…

python使用django搭建图书管理系统

大家好,你们喜欢的梦幻编织者回来了 随着计算机网络和信息技术的不断发展&#xff0c;人类信息交流的方式从根本上发生了改变&#xff0c;计算机技术、信息化技术在各个领域都得到了广泛的应用。图书馆的规模和数量都在迅速增长&#xff0c;馆内藏书也越来越多&#xff0c;管理…

JavaScript系列06-深入理解 JavaScript 事件系统:从原生事件到 React 合成事件

JavaScript 事件系统是构建交互式 Web 应用的核心。本文从原生 DOM 事件到 React 的合成事件&#xff0c;内容涵盖&#xff1a; JavaScript 事件基础&#xff1a;事件类型、事件注册、事件对象事件传播机制&#xff1a;捕获、目标和冒泡阶段高级事件技术&#xff1a;事件委托、…

大话机器学习三大门派:监督、无监督与强化学习

以武侠江湖为隐喻&#xff0c;系统阐述了机器学习的三大范式&#xff1a;​监督学习&#xff08;少林派&#xff09;​凭借标注数据精准建模&#xff0c;擅长图像分类等预测任务&#xff1b;无监督学习&#xff08;逍遥派&#xff09;​通过数据自组织发现隐藏规律&#xff0c;…

win11编译llama_cpp_python cuda128 RTX30/40/50版本

Geforce 50xx系显卡最低支持cuda128&#xff0c;llama_cpp_python官方源只有cpu版本&#xff0c;没有cuda版本&#xff0c;所以自己基于0.3.5版本源码编译一个RTX 30xx/40xx/50xx版本。 1. 前置条件 1. 访问https://developer.download.nvidia.cn/compute/cuda/12.8.0/local_…

FY-3D MWRI亮温绘制

1、FY-3D MWRI介绍 风云三号气象卫星&#xff08;FY-3&#xff09;是我国自行研制的第二代极轨气象卫星&#xff0c;其有效载荷覆 盖了紫外、可见光、红外、微波等频段&#xff0c;其目标是实现全球全天候、多光谱、三维定量 探测&#xff0c;为中期数值天气预报提供卫星观测数…

Codeforces1929F Sasha and the Wedding Binary Search Tree

目录 tags中文题面输入格式输出格式样例输入样例输出说明 思路代码 tags 组合数 二叉搜索树 中文题面 定义一棵二叉搜索树满足&#xff0c;点有点权&#xff0c;左儿子的点权 ≤ \leq ≤ 根节点的点权&#xff0c;右儿子的点权 ≥ \geq ≥ 根节点的点权。 现在给定一棵 …

HBuilder X 使用 TortoiseSVN 设置快捷键方法

HBuilder X 使用 TortoiseSVN 设置快捷键方法 单文件&#xff1a;(上锁&#xff0c;解锁&#xff0c;提交&#xff0c;更新) 安装好 TortoiseSVN &#xff0c;或者 按图操作&#xff1a; 1&#xff0c;工具栏中 【自定义快捷键】 2&#xff0c;点击 默认的快捷键设置&…

Java jar包后台运行方式详解

目录 一、打包成 jar 文件二、后台运行 jar 文件三、示例四、总结在 Java 开发中,我们经常需要将应用程序打包成可执行的 jar 文件,并在后台运行。这种方式对于部署长时间运行的任务或需要持续监听事件的应用程序非常重要。本文将详细介绍如何实现 Java jar 包的后台运行,并…

Mysql5.7-yum安装和更改mysql数据存放路径-2020年记录

记录下官网里用yum rpm源安装mysql, 1 官网下载rpm https://dev.mysql.com/downloads/repo/yum/ https://dev.mysql.com/doc/refman/5.7/en/linux-installation-yum-repo.html&#xff08;附官网操作手册&#xff09; wget https://repo.mysql.com//mysql80-community-release…

[项目]基于FreeRTOS的STM32四轴飞行器: 七.遥控器按键

基于FreeRTOS的STM32四轴飞行器: 七.遥控器 一.遥控器按键摇杆功能说明二.摇杆和按键的配置三.按键扫描 一.遥控器按键摇杆功能说明 两个手柄四个ADC。 左侧手柄&#xff1a; 前后推为飞控油门&#xff0c;左右推为控制飞机偏航角。 右侧手柄&#xff1a; 控制飞机飞行方向&a…

Android15使用FFmpeg解码并播放MP4视频完整示例

效果: 1.编译FFmpeg库: 下载FFmpeg-kit的源码并编译生成安装平台库 2.复制生成的FFmpeg库so文件与包含目录到自己的Android下 如果没有prebuiltLibs目录,创建一个,然后复制 包含目录只复制arm64-v8a下

安装树莓派3B+环境(嵌入式开发)

一、环境配置 1、下载树莓派镜像工具 点击进入下载连接 进入网站&#xff0c;点击下载即可。 2、配置wifi及ssh 将SD卡插入读卡器&#xff0c;再接入电脑&#xff0c;随后打开Raspberry Pi Imager下载工具&#xff0c; 选择Raspberry Pi 3 选择64位的操作系统 选择SD卡 选择…

p5.js:sound(音乐)可视化,动画显示音频高低变化

本文通过4个案例介绍了使用 p5.js 进行音乐可视化的实践&#xff0c;包括将音频振幅转化为图形、生成波形图。 承上一篇&#xff1a;vite&#xff1a;初学 p5.js demo 画圆圈 cd p5-demo copy .\node_modules\p5\lib\p5.min.js . copy .\node_modules\p5\lib\addons\p5.soun…

Linux下安装elasticsearch(Elasticsearch 7.17.23)

Elasticsearch 是一个分布式的搜索和分析引擎&#xff0c;能够以近乎实时的速度存储、搜索和分析大量数据。它被广泛应用于日志分析、全文搜索、应用程序监控等场景。 本文将带你一步步在 Linux 系统上安装 Elasticsearch 7.17.23 版本&#xff0c;并完成基本的配置&#xff0…