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

本文涉及的产品
Serverless 应用引擎 SAE,800核*时 1600GiB*时
性能测试 PTS,5000VUM额度
注册配置 MSE Nacos/ZooKeeper,118元/月
简介: SDS是Redis中的一种字符串类型,它是一种二进制安全的字符串,由简单动态字符串(SDS)实现。SDS支持多种数据结构,其中字符串(String)是最常用的一种数据结构之一。SDS的优点在于它可以避免C字符串常见的问题,比如缓冲区溢出和内存泄露等。SDS的常数复杂度获取字符串长度和杜绝缓冲区溢出可以避免使用strlen和strcat函数时的一些问题。同时,SDS的空间预分配和惰性空间释放两种策略可以减少修改字符串的内存重新分配次数。SDS也是二进制安全的,因为它不是以空字符串来判断字符串是否结束,而是以len属性表示的长度来判断字符串是否结束。SDS还兼容部分C字符串函数

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

一、SDS的内部实现原理

SDS是Redis中的一种字符串类型,它是一种二进制安全的字符串,相比于C语言中的字符串,SDS具有以下优点:

1. 动态扩容

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

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

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

3. 杜绝缓冲区溢出

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

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

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

5. 二进制安全

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

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

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

SDS可以重用C语言库中的一部分函数。
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语言库中的一部分函数。

二、SDS在Redis中的应用

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

  1. 字符串类型

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

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

杜绝缓冲区溢出
字符串拼接是我们经常做的操作,在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语言库中的一部分函数。

4.总结

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

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

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
2月前
|
消息中间件 NoSQL Redis
redis数据结构-List
redis数据结构-List
33 1
|
2月前
|
存储 缓存 NoSQL
redis数据结构-字符串
redis数据结构-字符串
32 1
|
3天前
|
存储 缓存 NoSQL
3)深度解密 Redis 的字符串
3)深度解密 Redis 的字符串
10 1
|
6天前
|
存储 JSON NoSQL
redis基本数据结构(String,Hash,Set,List,SortedSet)【学习笔记】
这篇文章是关于Redis基本数据结构的学习笔记,包括了String、Hash、Set、List和SortedSet的介绍和常用命令。文章解释了每种数据结构的特点和使用场景,并通过命令示例演示了如何在Redis中操作这些数据结构。此外,还提供了一些练习示例,帮助读者更好地理解和应用这些数据结构。
redis基本数据结构(String,Hash,Set,List,SortedSet)【学习笔记】
|
2月前
|
存储 监控 NoSQL
redis数据结构-HyperLogLog
redis数据结构-HyperLogLog
32 1
|
2月前
|
存储 NoSQL Redis
redis数据结构-ziplist
redis数据结构-ziplist
16 2
|
2月前
|
C# 开发者 UED
WPF开发者必备秘籍:深度解析文件对话框使用技巧,打开与保存文件原来如此简单!
【8月更文挑战第31天】在WPF应用开发中,文件操作是常见需求。本文详细介绍了如何利用`Microsoft.Win32`命名空间下的`OpenFileDialog`和`SaveFileDialog`类来正确实现文件打开与保存功能。通过示例代码展示了如何设置文件过滤器、初始目录等属性,并使用对话框进行文件读写操作。正确使用文件对话框能显著提升用户体验,使应用更友好易用。
51 0
|
2月前
|
存储 NoSQL 数据处理
redis数据结构-Bitmaps
redis数据结构-Bitmaps
29 0
|
2月前
|
存储 缓存 NoSQL
redis数据结构-hash
redis数据结构-hash
11 0
|
2月前
|
存储 NoSQL Redis
【Redis 探秘】SDS 简单动态字符串:揭秘 Redis 高效字符串处理的秘密武器!
【8月更文挑战第24天】Redis采用的简单动态字符串(SDS)是一种专为优化内存存储和字符串操作而设计的数据结构。相较于C语言的标准字符串,SDS改进了字符串长度计算、内存重分配及字符串比较等问题。其特性包括预分配冗余空间减少未来的内存重分配、显式存储长度以加快获取速度等。这些改进使Redis能更高效地管理字符串数据。例如,在Redis中,SDS被广泛应用于键值对的存储,显著提升了字符串操作的性能。了解SDS不仅对于深入理解Redis的工作原理至关重要,也是开发者技能树中的重要一环。
30 0
下一篇
无影云桌面