美文网首页
Redis底层数据结构——SDS

Redis底层数据结构——SDS

作者: 坤坤坤坤杨 | 来源:发表于2022-11-28 12:24 被阅读0次

Redis是C语言开发的,C语言自己就有字符类型,但是Redis却没直接采用C语言的字符串类型,而是自己构建了动态字符串(SDS)的抽象类型。Redis的key以及字符串数据结构的值, 最大的大小为 512M

set aobing cool

就好比这样的一个命令,其实我是在Redis创建了两个SDS,一个是名为aobing的Key SDS,另一个是名为cool的Value SDS,就算是字符类型的List,也是由很多的SDS构成的Key和Value罢了,SDS在Redis中除了用作字符串,还用作缓冲区(buffer)。

redis 3.2之前版本源码如下:

struct sdshdr{
 int len;
 int free;
 char buf[];
}

redis 3.2之后版本源码如下:

typedef char *sds;

/* Note: sdshdr5 is never used, we just access the flags byte directly.
 * However is here to document the layout of type 5 SDS strings. */
struct __attribute__ ((__packed__)) sdshdr5 {
    unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr8 {
    uint8_t len; /* used */
    uint8_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr16 {
    uint16_t len; /* used */
    uint16_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr32 {
    uint32_t len; /* used */
    uint32_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr64 {
    uint64_t len; /* used */
    uint64_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};

由源码可知SDS有五种不同的头部. 其中sdshdr5实际并未使用到. 所以实际上有四种不同的头部, 分别如下:



四种不同的头部分别表示不同长度的字符串。

  • len 保存了SDS保存字符串的长度。
  • buf[] 数组用来保存字符串的每个元素。
  • alloc分别以uint8, uint16, uint32, uint64表示整个SDS, 除过头部与末尾的\0, 剩余的字节数。
  • flags 始终为一字节, 以低三位标示着头部的类型, 高5位未使用。

1. SDS和c字符串的区别

计数方式不同

C语言对字符串长度的统计,就完全来自遍历,从头遍历到末尾,直到发现空字符就停止,以此统计出字符串的长度,这样获取长度的时间复杂度来说是0(n),大概就像下面这样


而从上面的源码中可以看到,redis自己本身就保存了长度的信息,所以获取长度的时间复杂度为0(1)。

杜绝缓冲区溢出

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

比如本来字符串长这样:



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


减少修改字符串时内存重分配次数

C语言字符串底层也是一个数组,每次创建的时候就创建一个N+1长度的字符,多的那个1,就是为了保存空字符的。

Redis是个高速缓存数据库,如果需要对字符串进行频繁的拼接和截断操作,如果写代码忘记了重新分配内存,就可能造成缓冲区溢出,以及内存泄露。

内存分配算法很耗时,对于一个高速缓存数据库来说,这样的开销也是我们应该要避免的。

Redis为了避免C字符串这样的缺陷,就分别采用了两种解决方案,去达到性能最大化,空间利用最大化:

  • 空间预分配:当对SDS进行扩展操作的时候,Redis会为SDS分配好内存,并且根据特定的公式,分配多余的free空间,还有多余的1byte空间(这1byte也是为了存空字符),这样就可以避免连续执行字符串添加所带来的内存分配消耗

    如果sds的长度是小于1m的话,分配2*strlen+1byte的长度
    如果sds的长度大于等于1m的话,那么分配strlen+1m的内存

    比如现在有这样的一个字符:



    当调用了拼接函数,字符串边长了,Redis还会根据算法计算出一个free值给他备用:



    再继续拼接,备用的free用上了,省去了这次的内存重分配:

    在redis 3.2 之后对字符串进行缩短操作时,程序不立即使用内存重新分配来回收缩短后多余的字节,而是使用 alloc 属性将这些字节的数量记录下来,等待后续使用。

  • 惰性空间释放:刚才提到了会预分配多余的空间,很多小伙伴会担心带来内存的泄露或者浪费,别担心,当我们执行完一个字符串缩减的操作,redis并不会马上收回空间,因为可以预防继续添加的操作,这样可以减少分配空间带来的消耗,当再次操作还是没用到多余空间的时候,Redis也还是会收回对于的空间,防止内存的浪费的。
    还是同样的字符串


    当调用了删减的函数,并不会马上释放掉free空间:

    如果我们需要继续添加这个空间就能用上了,减少了内存的重分配,如果空间不需要了,调用函数删掉就好了
二进制安全

C语言是判断空字符('\0')去判断一个字符的长度的,但是有很多数据结构经常会穿插空字符在中间,比如图片,音频,视频,压缩文件的二进制数据,就比如下面这个单词,只能识别前面的 不能识别后面的字符。



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


转载自:https://mp.weixin.qq.com/s?__biz=MzAwNDA2OTM1Ng==&mid=2453144083&idx=1&sn=9a20b8370fb7017d5c4a94da94ba0f63&scene=21#wechat_redirect

相关文章

  • Redis设计与实现-笔记(一)

    数据结构与对象 Redis的底层数据结构,了解Redis的底层数据结构有助于我们更好的运用Redis。 SDS R...

  • Redis底层数据结构

    Redis底层数据结构类型 简单动态字符串(simple dynamic string)SDS Redis 没有直...

  • Redis字符串与C字符串区别

    一、数据结构 redis的字符串底层数据结构是sds(simple dynamic string),即简单动态字符...

  • redis

    redis Redis 数据结构和底层实现string:简单动态字符串SDS,Redis 的字符串是动态字符串,是...

  • Redis对象(一) - 类型和编码

    对象 前边学习了Redis底层实现的各种数据结构, 包括SDS, list, skiplist, dict, in...

  • redis笔记

    redis基础知识 数据结构 底层数据结构 SDS 双向链表 压缩列表 跳跃表 Hash表 整数数组 对外数据结构...

  • redis数据结构--SDS

    redis底层存储字符串的数据结构叫做简单动态字符串(simple dynamic string)。 SDS定义 ...

  • t_string.c

    Redis的t_string.c是对于string数据结构的实现。底层是基于 sds 及 dict 实现的。 首先...

  • 2020-08-16:Redis底层数据结构?

    前言 每日一题专栏 Redis底层数据结构? 简链字跳整 压快压 SDS simple synamic strin...

  • redis底层数据结构以及对象系统

    底层数据结构 SDS(simple dynamic string,简单动态字符串) SDS空间预分配:对SDS字符...

网友评论

      本文标题:Redis底层数据结构——SDS

      本文链接:https://www.haomeiwen.com/subject/vgmlfdtx.html