Redis从入门到精通【高阶篇】之底层数据结构简单动态字符串(SDS)详解

news2024/11/24 7:15:19

文章目录

  • 1.原理解析
    • 1.1.SDS的内部实现原理
      • 1.1.1 Redis 6.0版本和Redis5.0对比
      • 1.1.2 redis6和redis5对比
      • 1.1.3 优势
        • 1.1.3.1. 动态扩容
        • 1.1.3.2. 常数复杂度获取字符串长度
        • 1.1.3.3. 杜绝缓冲区溢出
        • 1.1.3.4. 减少修改字符串的内存重新分配次数
        • 1.1.3.5. 二进制安全
        • 1.1.3.6. 兼容部分C字符串函数
  • 2. SDS在Redis中的应用
    • 2.1. 字符串类型
    • 2.2.杜绝缓冲区溢出
  • 3. SDS的优化技巧
    • 3.1. 尽量避免频繁修改SDS的值
    • 3.2. 使用API操作SDS
    • 3.3. 避免使用大量的短字符串
    • 3.4. 避免使用过大的SDS
    • 3.5. 使用SDS的优点
  • 4.总结
  • 5. 系列文章

redis高阶篇.jpg

👏 简介:大家好,我是冰点,从业11年,目前在物流独角兽企业从事技术管理和架构设计方面工作,之前的把博客作为技术流水账在写。现在准备把多年的积累整理一下,成体系的分享给大家,也算是对多年开发生涯的总结。如果你在工作和学习中遇到问题也可反馈给我(iceicepip), 路漫漫其修远兮,吾将上下而求索。
 
🏳️‍🌈2023计划:
             🚩1. 将多年来整理的Redis学习和实践笔记整理并发布成专栏。
             🚩2. 将最近2年在groovy实践应用上的沉淀的初稿,发布成书籍。
             🚩3. 将多年来整理的MySQL学习研究笔记整理并发布成专栏。
             🚩4. 根据技术交流群答疑的问题,整理成博客文章发布分享。

我陆续将我整理的Redis精选比较,分享给大家,今天分享的是Redis底层数据结构简单动态字符串(SDS)。我们从数据结构解析,包括Redis5和Redis6的SDS结构差异分析。这样设计的优势,如果有不对的地方,请大家指正。

Redis是一个快速、开源、内存数据库,它是一个基于键值对的存储系统,由Salvatore Sanfilippo开发。Redis支持多种数据结构,其中字符串(String)是最常用的一种数据结构之一。在Redis中,字符串是由简单动态字符串(SDS)实现的。本文将详细介绍SDS的内部实现原理、优势以及在Redis中的应用。图片来源网络
image.png
redis底层数据结构

1.原理解析

1.1.SDS的内部实现原理

image.png
redis6.x版本底层数据结构

1.1.1 Redis 6.0版本和Redis5.0对比

Redis 6.0版本中,对于SDS的底层数据结构进行了升级。除了原有的SDS类之外,还有四个新的类:sdshdr8、sdshdr16、sdshdr32、sdshdr64。这些类的命名与其中的成员变量类型相关,分别表示使用8位、16位、32位、64位的无符号整数存储字符串长度和容量。
image.png

1.1.2 redis6和redis5对比

Redis 6.0版本相比Redis 5.0版本在SDS底层数据结构上进行了一些改进和优化。Redis 6.0中的SDS仍然包含三个成员变量lenfreebuf,但是buf不再是一个字符数组,而是一个unsigned char类型的数组。此外,在Redis 6.0中新增了四个SDS类:sdsHdr5sdsHdr8sdsHdr16sdsHdr32。这四个类分别代表SDS字符串的头部数据结构,用于存储SDS字符串的长度和空闲空间,以及标记SDS字符串的类型。

Redis 6.0版本中的这些改进和优化可以提高SDS的效率和灵活性。通过使用unsigned char类型的数组来存储SDS字符串,可以更好地处理二进制数据和字符编码。而新增的四个SDS类可以更灵活地处理不同长度的SDS字符串,减少内存浪费。此外,为了提高效率,Redis 6.0版本中还对SDS的内存管理进行了优化,避免了频繁的内存分配和释放操作。

这样的设计可以根据实际情况选择更合适的底层数据结构,从而减少内存占用。例如,当存储的字符串长度较小时,可以选择使用sdshdr8或sdshdr16,而当存储的字符串长度较大时,则可以使用sdshdr32或sdshdr64

1.1.3 优势

上面我们已经解析了一下Redis5和Redis6的数据结构,我们可以总结归纳出SDS具有以下优点,以下这些优点,我也不再赘述。根据上面的解析我们很容易理解。

1.1.3.1. 动态扩容

SDS可以动态增加内存空间,避免了静态数组的大小限制。

1.1.3.2. 常数复杂度获取字符串长度

SDS中的len属性表示字符串长度,可以在常数时间内获取字符串长度。

1.1.3.3. 杜绝缓冲区溢出

SDS会检查内存是否足够,避免了缓冲区溢出的问题。

1.1.3.4. 减少修改字符串的内存重新分配次数

SDS采用惰性空间释放和空间预分配的策略,可以减少修改字符串的内存重新分配次数。

1.1.3.5. 二进制安全

SDS不以空字符串来判断字符串是否结束,而是以len属性表示的长度来判断字符串是否结束,所以支持存储任何二进制数据。
关于二进制安全我引用一个网友的图片更形象
C语言是判断空字符(‘\0’)去判断一个字符的长度的,但是有很多数据结构经常会穿插空字符在中间,比如图片,音频,视频,压缩文件的二进制数据,就比如下面这个单词,只能识别前面的 不能识别后面的字符。
image.png

Redis就不存在这个问题了,他不是保存了字符串的长度嘛,他不判断空字符,只判断长度,所以redis也经常被拿来保存各种二进制数据

1.1.3.6. 兼容部分C字符串函数

SDS可以重用C语言库<string.h>中的一部分函数。
SDS的实现位于Redis的源代码中的src/sds.h和src/sds.c中。SDS的总体结构包括头部sdshdr和存储用户数据的buf,其中用户数据后总跟着一个\0。SDS有四种不同的头部,分别是sdshdr8、sdshdr16、sdshdr32和sdshdr64,其中len属性表示字符串长度,buf[]数组用来保存字符串的每个元素,alloc属性表示整个SDS除过头部与末尾的\0,剩余的字节数,flags始终为一字节,以低三位标识着头部的类型,高5位未使用。

下面是SDS的头部结构体示例:

struct sdshdr {
    uint32_t len;    //字符串长度
    uint32_t alloc;  //字符串空间大小
    unsigned char flags; //表示sds的类型(8位)
    char buf[];  //用于存储字符串数据
};

image.png

SDS的头部结构体中,len和alloc是SDS的关键属性,它们分别表示字符串的长度和分配的空间大小。对于一个SDS字符串,其实际长度可以通过len属性来获取,而其当前分配的空间大小则可以通过alloc属性来获取。
image.png

SDS支持的最大长度是2^32字节,因此len和alloc都是32位无符号整数。SDS的len属性不仅用于表示字符串的长度,还用于记录buf数组中已使用的字节数,因此SDS的实际长度可能比len属性的值要小。

SDS的优点在于它可以避免C字符串常见的问题,比如缓冲区溢出和内存泄露等。SDS的常数复杂度获取字符串长度和杜绝缓冲区溢出可以避免使用strlen和strcat函数时的一些问题。同时,SDS的空间预分配和惰性空间释放两种策略可以减少修改字符串的内存重新分配次数。SDS也是二进制安全的,因为它不是以空字符串来判断字符串是否结束,而是以len属性表示的长度来判断字符串是否结束。SDS还兼容部分C字符串函数,可以重用C语言库<string.h>中的一部分函数。

2. SDS在Redis中的应用

SDS是Redis中最常用的底层数据结构之一,它被广泛应用于各种场景中,比如缓存、计数器、分布式锁等。在Redis中,SDS不仅作为字符串类型的基础实现,还被应用于其他数据结构中。

2.1. 字符串类型

在Redis中,字符串类型是最常用的数据结构之一,它可以用于存储各种类型的数据,比如整数、浮点数、二进制数据等。字符串类型中的字符串值是由SDS实现的,它可以动态扩容,避免了静态数组的大小限制。SDS还可以减少修改字符串的内存重新分配次数,从而提高了性能。

SDS在Redis中的应用非常广泛,它作为字符串类型的基础实现,还被应用于其他数据结构中。SDS的优点在于它可以避免C字符串常见的问题,比如缓冲区溢出和内存泄露等。SDS的常数复杂度获取字符串长度和杜绝缓冲区溢出可以避免使用strlen和strcat函数时的一些问题。同时,SDS的空间预分配和惰性空间释放两种策略可以减少修改字符串的内存重新分配次数。SDS也是二进制安全的,因为它不是以空字符串来判断字符串是否结束,而是以len属性表示的长度来判断字符串是否结束。SDS还兼容部分C字符串函数,可以重用C语言库<string.h>中的一部分函数。

2.2.杜绝缓冲区溢出

字符串拼接是我们经常做的操作,在C和Redis中一样,也是很常见的操作,但是问题就来了,C是不记录字符串长度的,一旦我们调用了拼接的函数,如果没有提前计算好内存,是会产生缓存区溢出的。

比如本来字符串长这样:
image.png

现在需要在后面拼接 ,但是没计算好内存,结果就可能这样了:

image.png

3. SDS的优化技巧

在使用SDS时,还有一些优化技巧可以提高性能:

3.1. 尽量避免频繁修改SDS的值

SDS的修改操作会引起内存重新分配,因此频繁修改SDS的值会导致性能下降。如果需要频繁修改SDS的值,可以考虑使用缓存等技术来避免频繁的修改操作。

3.2. 使用API操作SDS

SDS提供了一些API操作,比如sdscat、sdscmp、sdsnew等,使用这些API操作可以避免直接操作SDS的buf数组,从而提高代码的可读性和可维护性。

3.3. 避免使用大量的短字符串

空间预分配策略会分配一定的额外空间,用于存储未来可能的扩展。如果使用大量的短字符串,会浪费SDS的空间预分配策略,因为大量的短字符串可能占用预分配的空间,而未来可能需要更多的空间来存储更长的字符串。因此,如果需要存储大量的短字符串,可以考虑使用其他数据结构,比如哈希表或者列表。

3.4. 避免使用过大的SDS

最大长度是2^32字节,因此如果需要存储非常大的字符串,可以考虑使用其他的存储方式,比如文件系统或者分布式存储系统。

3.5. 使用SDS的优点

SDS的优点在于它可以避免C字符串常见的问题,比如缓冲区溢出和内存泄露等。SDS的常数复杂度获取字符串长度和杜绝缓冲区溢出可以避免使用strlen和strcat函数时的一些问题。同时,SDS的空间预分配和惰性空间释放两种策略可以减少修改字符串的内存重新分配次数。SDS也是二进制安全的,因为它不是以空字符串来判断字符串是否结束,而是以len属性表示的长度来判断字符串是否结束。SDS还兼容部分C字符串函数,可以重用C语言库<string.h>中的一部分函数。

4.总结

SDS是Redis中的一种字符串类型,它是一种二进制安全的字符串,由简单动态字符串(SDS)实现。SDS支持多种数据结构,其中字符串(String)是最常用的一种数据结构之一。SDS的优点在于它可以避免C字符串常见的问题,比如缓冲区溢出和内存泄露等。SDS的常数复杂度获取字符串长度和杜绝缓冲区溢出可以避免使用strlen和strcat函数时的一些问题。同时,SDS的空间预分配和惰性空间释放两种策略可以减少修改字符串的内存重新分配次数。SDS也是二进制安全的,因为它不是以空字符串来判断字符串是否结束,而是以len属性表示的长度来判断字符串是否结束。SDS还兼容部分C字符串函数,可以重用C语言库<string.h>中的一部分函数。

在Redis中,SDS不仅作为字符串类型的基础实现,还被应用于其他数据结构中。使用SDS时,可以避免频繁修改SDS的值,使用API操作SDS,避免使用大量的短字符串,避免使用过大的SDS,充分利用SDS的优点,提高代码的性能和可读性。

5. 系列文章

《Redis从入门到精通【高阶篇】之底层数据结构压缩列表(ZipList)详解》
在这里插入图片描述
参考资料:

  1. 陈雷老师的《Redis5设计与源码分析 》
  2. Redis 6.0源码

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

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

相关文章

SpringMVC06:Json交互处理

目录 一、什么是JSON? 二、代码测试 1、新建一个module&#xff0c;SpringMVC-05-json&#xff0c;添加web支持和lib包 2、在index.jsp中编写测试内容 3、配置tomcat&#xff0c;启动项目&#xff0c;在浏览器中打开&#xff0c;查看控制台输出 4、controller返回JSON数据…

AC变DC220V变5V小家电电源芯片-AH8652、AH8669

Q: 什么是AH8652和AH8669电源芯片? A: AH8652和AH8669都是AC变DC的电源芯片&#xff0c;适用于将输入的交流电压&#xff08;220V&#xff09;转换为5V直流电压输出&#xff0c;用于小家电的电源模块等应用。 AC变DC220V变5V小家电电源芯片-AH8669 Q: AH8652和AH8669的最大输…

2023智源大会议程公开丨自动驾驶论坛

6月9日&#xff0c;2023北京智源大会&#xff0c;将邀请这一领域的探索者、实践者、以及关心智能科学的每个人&#xff0c;共同拉开未来舞台的帷幕&#xff0c;你准备好了吗&#xff1f;与会知名嘉宾包括&#xff0c;图灵奖得主Yann LeCun、图灵奖得主Geoffrey Hinton、OpenAI创…

Observability:如何有效地将应用日志发送到 Elasticsearch

在今天的文章中&#xff0c;我们将探讨使用 3 种不同的架构发送应用的日子到 Elasticsearch。我们将详述它们的优缺点。更多关于日志架构的介绍&#xff0c;请参考 “Elastic&#xff1a;开发者上手指南” 中的 “Elastic Stack 架构” 部分。 介绍 采用 Elastic Stack&#x…

前端录制回放rrweb

rrweb 是 ‘record and replay the web’ 的简写&#xff0c;旨在利用现代浏览器所提供的强大 API 录制并回放任意 web 界面中的用户操作。 rrweb中文文档 https://github.com/rrweb-io/rrweb/blob/master/guide.zh_CN.md 本文项目地址 https://github.com/qdfudimo/vue-rrweb…

网安学习|Kail安全渗透测试系统之【前期信息收集】工具实践学习

欢迎关注「全栈工程师修炼指南」公众号 点击 &#x1f447; 下方卡片 即可关注我哟! 设为「星标⭐」每天带你 基础入门 到 进阶实践 再到 放弃学习&#xff01; “ 花开堪折直须折&#xff0c;莫待无花空折枝。 ” 作者主页&#xff1a;[ https://www.weiyigeek.top ] 博客&…

达梦数据库与MySQL的区别及语法差异

达梦数据库与MySQL的区别及其SQL语句对比 简介&#xff1a;正文&#xff1a;1. 达梦数据库和MySQL的概述2. 特点对比3. SQL语句对比1. 数据类型&#xff1a;2. 语法&#xff1a;1. DDL&#xff08;数据定义语言&#xff09;的差异&#xff1a;2. DML&#xff08;数据操作语言&a…

面向对象——多态、抽象类、接口

学习资料来自&#xff1a;黑马程序员&#xff0c;内容仅为学习记录&#xff0c;侵删 多态 多态&#xff1a;事务存在的多种形态 多态的前提&#xff1a;1、有继承关系&#xff1b;2、重写父类方法&#xff1b;3、父类引用指向子类对象 面向对象 面向对象多态中成员访问特点…

动态测试数据处理

分类 动态测试数据&#xff1a; 1、确定性数据&#xff1a;能够用明确的数学表达式进行描述的数据称为确定性数据。 Ⅰ、周期数据 Ⅱ、非周期数据 2、随机性数据&#xff1a;无法用明确的数学表达式表述&#xff1b;若在一个…

强大的工具:APISpace IP归属地查询API

引言 IP地址在互联网世界中扮演着重要的角色&#xff0c;对于许多应用程序和服务来说&#xff0c;了解IP地址的归属地信息可以提供有价值的洞察和功能。 在本文中&#xff0c;我们将介绍一种名为IP归属地-IPv4区县级 API 的强大工具&#xff0c;它提供了查询 IP 地址归属地信…

如何解释物联网IOT平台?

物联网开发的本质是将各种物品通过网络连接在一起&#xff0c;并对这些物品进行数字化管理&#xff0c;从而实现智能自动化。在物联网的早期阶段&#xff0c;一些物联网应用程序&#xff08;例如&#xff0c;智能电表&#xff09;使用软件将信息传输到后台服务器。但随着时间的…

华为路由器:多区域OSPF协议实验

一、实验拓扑 二、ospf基本概念复习 区域划分&#xff1a;area0为骨干区域&#xff0c;其他area1、area2都为普通区域/常规区域。普通区域必须和骨干区域直接相连。ABR&#xff1a;区域边界路由器。R2、R3位于两个区域的中间&#xff0c;我们称之为区域边界路由器 &#xff1b…

ObjectARX如何监控实体双击事件(利用钩子函数或者反应器)

目录 1 实现方法1——钩子函数1.1 钩子函数的作用1.2 利用钩子函数监控双击事件 2 实现方法2——反应器2.1 反应器的作用2.2 利用编辑器反应器监控双击事件 在ObjectARX开发中&#xff0c;常常要监控鼠标的双击事件&#xff0c;比如&#xff0c;往一个实体中写了扩展数据&#…

基于html+css的图展示115

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

2023年湖北下半年中级职称申报中级职称评审申报条件是什么?

2023年湖北下半年中级职称申报中级职称评审申报条件是什么&#xff1f; 2023年湖北中级职称申报条件&#xff1a;本科毕业5年&#xff0c;专科毕业7年&#xff0c;相关专业 助工满4年这个条件目前不是硬性要求&#xff0c;意思就是有肯定更好&#xff0c;没有也没有太大的影响 …

穿越火线几次体验良好的游戏优化方案

文章目录 介绍救世主模式终结者模式30人生化模式挑战模式英雄级武器源武器英雄级武器皮肤英雄级武器游戏玩偶英雄级武器万化包、光效英雄级武器强化英雄级武器音效卡免费获取挑战强化武器戒指击杀效果个人竞技击杀效果人机训练模式交易所火线币快速加入跳跳乐爆头战HS间谍模式地…

做了一个日内信号可视化系统

量化策略开发&#xff0c;高质量社群&#xff0c;交易思路分享等相关内容 大家好&#xff0c;半年过去了。松鼠Quant计划6月内发布本年度最重要的一个策略:盘口策略。这个策略群友们的呼声很高&#xff0c;也是花了比较多时间去弄。整个策略有多个python脚本: CTP数据生成order…

如何提高浪涌保护器的使用寿命和安全性

浪涌保护是保护设施免受电气事件影响的基本要求。具体来说&#xff0c;浪涌保护器&#xff08;SPD&#xff09;旨在限制瞬态电压并转移浪涌电流以保护系统和设备。 SPD浪涌保护器必须考虑的一种现象是临时过电压&#xff08;TOV&#xff09;。传统设备处理 TOV 的方式可能会导…

【unity数据持久化】游戏排行榜信息简单的存储,你还知道吗?数据管理类_PlayerPrfs

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;uni…

谈一谈冷门的C语言爬虫

C语言可以用来编写爬虫程序&#xff0c;但是相对于其他编程语言&#xff0c;C语言的爬虫开发可能会更加复杂和繁琐。因为C语言本身并没有提供现成的爬虫框架和库&#xff0c;需要自己编写网络请求、HTML解析等功能。 不过&#xff0c;如果你对C语言比较熟悉&#xff0c;也可以…