Redis从入门到精通之底层数据结构SDS(简单动态字符串)详解 您所在的位置:网站首页 底层代码开发的意义 Redis从入门到精通之底层数据结构SDS(简单动态字符串)详解

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

2024-06-13 17:48| 来源: 网络整理| 查看: 265

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

一、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不仅作为字符串类型的基础实现,还被应用于其他数据结构中。

字符串类型

在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的优点,提高代码的性能和可读性。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有