读书笔记-《Redis设计与实现》(一)数据结构与对象(下)

embedded/2025/2/1 15:10:31/

各位朋友新年快乐~

今天我们来继续学习 Redis 。


01

整数集合

当集合仅包含整数值,并且元素数量不多时,Redis 就会采用整数集合来作为集合键的底层实现。

typedef struct intset {// 编码方式uint32_t encoding;// 元素数量uint32_t length;// 数组int8_t contents[];
} intset;

可以看到,contents 就是存储元素的地方,各个元素按从小到大排序并且不包含重复值。注意虽然 contents 声明为 int8_t,但实际类型取决于 encoding。

看到上面的数据结构,不难想到一个问题——如果现有的数组编码为 int16_t,然后往里面添加一个 int32_t 的元素,会发生什么?

答案就是升级。整数集合升级包含三个步骤:扩展数组空间、升级旧元素类型并重新放置、放置新元素。

升级的好处是:提升整体灵活性(可以任意地往里面放置不同类型的元素)、尽可能节约内存


02

压缩列表

当列表键仅包含小整数值和短字符串,并且元素数量不多时,Redis 就会采用压缩列表来作为列表键的底层实现。

压缩列表的结构如下:

  • zlbytes:记录整个列表所占内存字节数。

  • zltail:记录表尾节点距离起始位置的偏移量。

  • zllen:记录节点数量,但最大值为 UINT16_MAX(65535),超过这个值就只能通过遍历才能得到具体数量。

  • entry:各个节点,结构包括 previous_entry_length、encoding、content。第一个属性顾名思义,记录前一个节点的长度,因此程序可通过当前节点的起始地址来计算出前一个节点的起始地址,进而实现从表尾向表头的遍历;后两个属性分别为节点值的编码和节点的值。

  • zlend:末端标识符 0xFF。


03

对象

typedef struct redisObject {// 类型unsigned type:4;// 编码unsigned encoding:4;// 指向底层数据结构的指针void *ptr;// 引用计数,用于内存回收int refcount;// 记录最后一次被访问的时间,用于计算空转时长unsigned lru:22;// ...} robj;

对象的关键属性如上。众所周知,Redis 包含五个对象类型,分别是字符串、列表、Hash、集合、有序集合。而我们在操作键值对时,键总是一个字符串对象,而值则可以是这五个中的任意一种。

编码则是我们前面学习的各种数据结构,例如 SDS、链表、字典、跳表、整数集合、压缩列表等等。通过这种切换编码的机制,极大提高了 Redis 的灵活性和效率

五种类型的编码如下:

  • 字符串对象:long 类型时编码为 int,字符串且长度大于39字节时为 raw(即 SDS),字符串且长度小于等于39字节时为 embstr。embstr 的特点是使用连续内存空间存储 redisObject 和 sdshdr 两个结构,减少了内存分配和回收次数,提升了读取速度。

  • 列表对象:所有字符串元素长度较小并且元素总数较少时(具体数值可配置)为 ziplist,否则为 linkedlist

  • Hash 对象:所有键值对的键和值字符串长度较小并且元素总数较少时(具体数值可配置)为 ziplist,否则为 hashtable。在使用前者时,键值对会按照顺序存放,例如依次放入键值对“hello-world”、“happy-new year”,则存储的节点顺序为 hello、world、happy、new year。

  • 集合对象:所有元素为整数值且元素总数较少时(具体数值可配置)为 intset,否则为 hashtable。在使用后者时,所有的键均没有值。

  • 有序集合对象:所有元素长度较小且元素总数较少时(具体数值可配置)为 ziplist,否则为 skiplist。特殊的点在于,使用后者时对象的结构为 zset,其同时包含一个字典和一个跳跃表,从而使得该对象在单个元素查询和范围操作时,都有着极低的时间复杂度。

了解了对象的类型和编码后,我们不难得出,Redis 的命令(如 DEL、LLEN)是多态的。前者是基于类型的多态,一个命令同时处理不同类型的键;而后者是基于编码的多态,一个命令同时处理不同的编码。

另外,Redis 还会对只包含整数值的字符串对象进行共享,即多个键指向同一个地址以节省内存。共享的数值范围(如从 0 到 9999)同样可通过配置修改。这一点对于 Java 开发来说也不陌生了,出发点和 Integer 的缓存是一样的。


原文链接:读书笔记-《Redis设计与实现》(一)数据结构与对象(下)

原创不易,点个关注不迷路哟,谢谢~

文章推荐:

  • 读书笔记-《当下的力量》
  • 读书笔记-《写给大家看的设计书》
  • 赛博朋克2077玩后感
  • 程序员工作中常见问题,你遇到过几个?
  • 如何设计离线跑批系统
  • 读书笔记-《人人都是产品经理》
  • 如何养成好习惯
  • 读书笔记-《最好的告别》
  • 读书笔记-《Spring技术内幕》(四)事务
  • 读书笔记-《Redis设计与实现》(一)数据结构与对象(上)


http://www.ppmy.cn/embedded/158655.html

相关文章

元旦和春节取名的历史变迁

在中国漫长的历史长河中的春节,真要追溯起来也只有一百多年历史——是从晚清时期才逐渐出现在国人的生活里的,而且那时不叫“春节”而叫“元旦”。只不过随着历史的发展过程,“过年”这个名词也一直在演变,直至1949年最终才定下来…

HTML5+SVG+CSS3实现雪中点亮的圣诞树动画效果源码

源码介绍 这是一款基于HTML5SVGCSS3实现雪中点亮的圣诞树动画效果源码。画面中的圣诞树矗立在雪地中,天上飘落着雪花。当鼠标滑过圣诞树时,可见到圣诞树上的灯光闪烁,同时左下角探出雪怪模样的半个脑袋,四处张望着。整体画面栩栩…

使用 Ollama 和 Kibana 在本地为 RAG 测试 DeepSeek R1

作者:来自 Elastic Dave Erickson 及 Jakob Reiter 每个人都在谈论 DeepSeek R1,这是中国对冲基金 High-Flyer 的新大型语言模型。现在他们推出了一款功能强大、具有开放权重的思想链推理 LLM,这则新闻充满了对行业意味着什么的猜测。对于那些…

网络安全实战指南:攻防技术与防御策略

📝个人主页🌹:一ge科研小菜鸡-CSDN博客 🌹🌹期待您的关注 🌹🌹 1. 引言 随着数字化转型的加速,网络安全已成为各行业不可忽视的重要领域。从数据泄露到勒索软件攻击,网络…

Kafka生产者ACK参数与同步复制

目录 生产者的ACK参数 ack等于0 ack等于1(默认) ack等于-1或all Kafka的同步复制 使用误区 生产者的ACK参数 Kafka的ack机制可以保证生产者发送的消息被broker接收成功。 Kafka producer有三种ack机制 ,分别是 0,1&#xf…

Docker小游戏 | 使用Docker部署2048网页小游戏

Docker小游戏 | 使用Docker部署2048网页小游戏 前言项目介绍项目简介项目预览二、系统要求环境要求环境检查Docker版本检查检查操作系统版本三、部署2048网页小游戏下载镜像创建容器检查容器状态检查服务端口安全设置四、访问2048网页小游戏五、总结前言 在当今快速发展的技术世…

MyBatis 入门

目录 一. MyBatis 概述 二. MyBatis 入门 1. 创建工程, 导入依赖 2. 数据准备 3. 配置数据库相关信息 4. 编写持久层代码 5. 编写测试代码 三. MyBatis基础操作. 1. 打印日志 2. 参数传递 3. 增 (Insert) 4. 删 (Delete) 5. 改 (Update) 6. 查 (Select) (1) 起…

p4:使用pytorch实现猴痘病识别

🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 我的环境 语言环境:python 3.7.12 编译器:pycharm 深度学习环境:tensorflow 2.7.0 数据:本地数据集 一、代码 …