解析Redis数据结构之简单动态字符串sds
IT行业相对于一般传统行业,发展更新速度更快,一旦停止了学习,很快就会被行业所淘汰。所以我们需要踏踏实实的不断学习,精进自己的技术,尤其是初学者。今天golang学习网给大家整理了《解析Redis数据结构之简单动态字符串sds》,聊聊Redis数据结构、动态字符串、sds,我们一起来看看吧!
Redis是用ANSI C语言编写的,它是一个高性能的key-value数据库,它可以作用在数据库、缓存和消息中间件。其中 Redis 键值对中的键都是 string 类型,而键值对中的值也是有 string 类型,在 Redis 中 string 类型运用还是很广泛的。本文主要介绍 string 的数据结构—— 简单动态字符串(Simple Dynamic String) 简称sds。
sds 实现
sds 的数据结构:
struct sdshdr { //buf 已占用的长度 int len; // buf 剩余的可用的长度 int free; // 保存字符串数据的地方 char buf[]; }
结构 sdshdr 保存了 len、free 和 buf 三个属性,分别记录字符的已使用的长度,未使用的长度,以及实际保存字符串的数组。
以下是一个新建的,保存 hello world 字符串的 sdshdr 结构:
struct sdshdr { len = 5; free = 0; buf = "hello\0"; }
- free 属性值为0,表示这个sds没有分配未使用的空间。
- len 属性值为5,表示这个sds保存了一个五字节长的字符串。
- buf 属性是一个 char 类型的数组,数组的前五个字节分别保存了 'h'、'e'、'l'、'l'、'o' 五个字符,而最后一个字节保存了空字符'\0'。
sds 遵守 C 字符串以空字符串结尾的惯例,保存的空字符串一个字节空间不计算在 sds 的 len 属性里面。添加空字符串到字符串末尾等操作,都是由 sds 函数自动完成的,所以这个空字符对于使用者来说完全是透明的。
通过 len 属性,可以实现时间复杂度 O(1) 的长度计算。另外通过对 buf 分配一些额外的空间,并使用 free 记录未使用空间的长度,sdshdr 可以减少内存的重新分配。这是 sds 相对 c 字符串的一个优势。
为何 Redis 不用 C 语言表示字符串
Redis 是使用 C 语言开发的,而在使用最多的字符串上,Redis 没有使用 C 语言传统的字符串表示,而且使用自己构建的简单动态字符串(sds)。
在 C 语言中,字符串可以用一个 \0 结尾的 char 数组表示。比如 hello world 在 C 语言中就可以表示为"hello world\0"。数组一般初始化以后长度就已经固定了,不能支持字符串追加append和长度计算操作:
- 每次计算字符串长度都要遍历一遍数组,所以时间复杂度是O(N)
- 对字符串每次进行追加操作,需要对字符串进行一次内存分配
sds 优化追加字符操作
Redis 作为数据库,对于查询速度要求严格,数据修改也比较频繁,如果每次修改字符串都需要执行一次内存分配的话,都会占用大量的时间。所以 Redis 选择了 sds 而不是 C 字符串,sds 可以减少追加字符的内存分配。通过举例来说明,执行以下操作时,sds 内部的变化:
redis> set msg "hello world" OK redis> append msg " again" (integer)18 redis> get msg "hello world again"
首先 set 命令创建并保存hello world 到一个 sdshdr 中,这个 sdshdr 的值如下:
struct sdshdr { len = 11; free = 0; buf = "hello world\0"; }
当执行 append 命令时,相对应的 sdshdr 被更新,字符串 " again" 会被追加到原来的 "hello world" 之后:
struct sdshdr { len = 17; free = 17; buf = "hello world again\0 "; }
当调用 set 命令创建 sdshdr 时,Redis 没有给 sdshdr 分配多余的空间,free 属性为0。而在执行 append 操作之后,Redis 为 buf 分配了多于所需空间一倍的大小。
在执行 append 命令之后,保存 "hello world again" 共需要17 + 1 个字节,但是程序为 sdshdr 分配了 17 + 17 + 1 = 35 个字节,而后续如果在对 sdshdr 进行追加操作,只要追加的长度不超过 free 属性值,那么就不需要对 buf 进行内存重分配。
比如执行以后命令并不会引起 buf 的内存重分配,因为新追加的字符串长度小于17:
redis> append msg " again" (integer) 23
对应的 sdshdr 结构如下:
struct sdshdr { len = 23; free = 11; buf = "hello world again again\0 "; }
redis 内存分配可以查看源码 sds.s/sdsMakeRoomFor,sdsMakeRoomFor 函数描述了内存分配的策略,下面的该函数的伪代码:
// sdshdr:追加前的字符 // addlen:追加字符串 sds sdsMakeRoomFor(sdshdr, addlen) { // 多余空间大于追加空间,无序再分配内存,直接返回 if (free >= addlen) return s; // 计算新字符的长度 newlen = (len+addlen); // 如果新字符的长度小于 SDS_MAX_PREALLOC,就分配两倍新字符空间 // 如果新字符的长度大于 SDS_MAX_PREALLOC,就分配新字符空间 + SDS_MAX_PREALLOC 空间 if (newlen而对于字符的缩短操作,Redis 保存缩短后的字符串,此时并不会进行内存重分配,而是使用 free 属性记录缩短的字符长度。
总结
Redis 的 string 类型为何使用sds而不是 C 字符串,因为sds有两点优势:
- 计算字符长度,C 字符串复杂度O(n),而 sds 复杂度为 O(1)
- 字符追加操作,C 字符串每次都需要对内存进行重分配,而 sds 每次会进行动态扩容,当添加字符小于空闲字符时,不会对内容进行分配,减少系统等待时间
参考
到这里,我们也就讲完了《解析Redis数据结构之简单动态字符串sds》的内容了。个人认为,基础知识的学习和巩固,是为了更好的将其运用到项目中,欢迎关注golang学习网公众号,带你了解更多关于redis的知识点!

- 上一篇
- Redis实现分布式锁的实例讲解

- 下一篇
- Redis缓存IO模型的演进教程示例精讲
-
- 务实的泥猴桃
- 很好,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢作者大大分享文章!
- 2023-05-26 02:45:21
-
- 乐观的小蝴蝶
- 这篇博文太及时了,太详细了,太给力了,已加入收藏夹了,关注大佬了!希望大佬能多写数据库相关的文章。
- 2023-05-04 05:28:10
-
- 高兴的太阳
- 很好,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢楼主分享博文!
- 2023-02-01 14:13:43
-
- 洁净的灯泡
- 这篇技术贴真及时,好细啊,写的不错,已加入收藏夹了,关注博主了!希望博主能多写数据库相关的文章。
- 2023-01-14 07:27:19
-
- 数据库 · Redis | 5小时前 | redis redis-check-rdb 数据文件损坏 redis-check-aof 恢复步骤
- Redis数据文件损坏后的恢复攻略
- 465浏览 收藏
-
- 数据库 · Redis | 17小时前 | redis Django 缓存 settings.py django-redis
- Django项目Redis缓存集成详解步骤
- 458浏览 收藏
-
- 数据库 · Redis | 2天前 |
- Redis启动时如何指定配置文件
- 225浏览 收藏
-
- 数据库 · Redis | 2天前 |
- Redis启动后无法访问?排查与解决攻略
- 498浏览 收藏
-
- 数据库 · Redis | 2天前 |
- Redis启动后访问异常?快速排查与解决
- 206浏览 收藏
-
- 数据库 · Redis | 3天前 |
- 检查Redis版本及升级指南
- 335浏览 收藏
-
- 数据库 · Redis | 4天前 |
- 检查Redis版本及升级指南
- 134浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 508次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 484次学习
-
- 笔灵AI生成答辩PPT
- 探索笔灵AI生成答辩PPT的强大功能,快速制作高质量答辩PPT。精准内容提取、多样模板匹配、数据可视化、配套自述稿生成,让您的学术和职场展示更加专业与高效。
- 20次使用
-
- 知网AIGC检测服务系统
- 知网AIGC检测服务系统,专注于检测学术文本中的疑似AI生成内容。依托知网海量高质量文献资源,结合先进的“知识增强AIGC检测技术”,系统能够从语言模式和语义逻辑两方面精准识别AI生成内容,适用于学术研究、教育和企业领域,确保文本的真实性和原创性。
- 29次使用
-
- AIGC检测-Aibiye
- AIbiye官网推出的AIGC检测服务,专注于检测ChatGPT、Gemini、Claude等AIGC工具生成的文本,帮助用户确保论文的原创性和学术规范。支持txt和doc(x)格式,检测范围为论文正文,提供高准确性和便捷的用户体验。
- 35次使用
-
- 易笔AI论文
- 易笔AI论文平台提供自动写作、格式校对、查重检测等功能,支持多种学术领域的论文生成。价格优惠,界面友好,操作简便,适用于学术研究者、学生及论文辅导机构。
- 43次使用
-
- 笔启AI论文写作平台
- 笔启AI论文写作平台提供多类型论文生成服务,支持多语言写作,满足学术研究者、学生和职场人士的需求。平台采用AI 4.0版本,确保论文质量和原创性,并提供查重保障和隐私保护。
- 36次使用
-
- 阿里面试这样问:Redis为什么把简单的字符串设计成SDS?
- 2023-02-22 126浏览
-
- 深入解析Redis源码之SDS
- 2023-02-24 119浏览
-
- redis中的数据结构和编码详解
- 2023-01-07 290浏览
-
- Redis高效率原因及数据结构分析
- 2022-12-31 143浏览
-
- 浅谈redis五大数据结构和使用场景
- 2022-12-30 417浏览