Redis-底层原理学习之-字符串

7 篇文章 0 订阅

Redis-底层原理学习之-字符串

redis底层数据结构中—字符串简介

命令:
设置一个值 key value;

set key val

获取设置的key的值
get key

那么问题来了 key value 是怎么存储的?

Redis没有直接使用C语言传统的字符串表示(以空字符结尾的字符数组,以下简称C字符串),而是自己构建了一种名为简单动态字符串(simple dynamic string,SDS)的抽象类型(对象),并将SDS用作Redis的默认字符串表示。

在Redis里面,C字符串只会作为字符串字面量(string literal)用在一些无须对字符串值进行修改的地方,比如打印日志,当Redis需要的不仅仅是一个字符串字面量,而是一个可以被修改的字符串值时,Redis就会使用SDS来表示字符串值。

当你执行,redis> SET key "hello ",(msg 作为key,他有自己的保存位置,字符串字面量;"hello " 作为value,肯定更要进行保存了。) Redis将在数据库中创建一个新的键值对,其中:
·键值对的键是一个字符串对象,对象的底层实现是一个保存着字符串“key”的SDS。
·键值对的值也是一个字符串对象,对象的底层实现是一个保存着字符串“hello”的SDS。

又比如,如果执行命令:
redis> RPUSH tg “app” “ban” “cher”

那么Redis将在数据库中创建一个新的键值对,其中:
·键值对的键是一个字符串对象,对象的底层实现是一个保存了字符串“tg”的SDS。
·键值对的值是一个列表对象,列表对象包含了三个字符串对象,这三个字符串对象分别由三个SDS实现:第一个SDS保存着字符串“app”,第二个SDS保存着字符串“ban”,第三个SDS保存着字符串“cher”。

除了用来保存数据库中的字符串值之外,SDS还被用作缓冲区(buffer):AOF模块中的AOF缓冲区,以及客户端状态中的输入缓冲区,都是由SDS实现的,在之后介绍AOF持久化和客户端状态的时候,我们会看到SDS在这两个模块中的应用。

SDS的定义
sds这个对象包括几个部分

struct sdshdr {
    //SDS所保存字符串的长度
    int len;

    // 记录buf数组中未使用字节的数量
    int free;

    // 字节数组,用于保存字符串
  char buf[];
};

sds结构图
几个字段的说明:
free属性的值为0,表示这个SDS没有分配任何未使用空间。
·len属性的值为5,表示这个SDS保存了一个五字节长的字符串。
·buf属性是一个char类型的数组,数组的前五个字节分别保存了’R’、‘e’、‘d’、‘i’、‘s’五个字符,而最后一个字节则保存了空字符’\0’。
注:最后一个空字符是每个string值都会预留 的;

那么下一个问题来了

SDS 的好处,为什么不直接使用 C 语言的字符串

c的字符串与sds对比
得出几个结论:

  1. C 语言的字符串如果想要得到他的长度,需要进行遍历,意味着时间复杂度为 o(N)。如果使用sds,我们的长度直接从len属性里获取,o(1). 本质上,其实就是多了一个len属性,保存了我们的字符串的长度;

  2. C语言的字符串如果进行我们的 扩展(增加字符串的长度) 或者 缩减(减少字符串的长度)。 进行扩展:我们必须要提前分配内存空间,一旦忘了分配,造成缓冲区溢出;进行缩减:必须要有意识的进行空间的释放,否则造成空间浪费。无论是进行扩展还是缩减,都需要进行内存的重新分配,耗时啊。 SDS 来说,他不会造成缓冲区溢出的问题,是封装好的对象,他已经为我们考虑了这部分内存的扩展及缩减问题。

  3. 大家看到了 free 这个属性是个好东西。我们在第1点里,说了 len 的好处,时间复杂度问题。现在free 是一个非常有效的空间属性。
    3.1 当创建我们的 sds 对象的时候,如 msg,他的 free 空间也会分配与当前的字符串相同大小的空间; len=3; free=3;buf[]= [‘m’, ‘s’, ‘g’,‘\0’]; 这部分free 之所以分配了 3 个长度的空间,是预防我们进行字符串的扩展,扩展的时候可以直接使用,而无需进行控减分配,我们称之为 空间预分配;
    3.2 如果我存储的 不是 msg,是一个超过 1M 的字符串,比如说 20 M,那么我的 free 怎么分配?如果我们的buf 超过 1M,那么我们free 就分配1M,哪怕你是 20M, 我们的 free 也是分配1M。因为msg小于1M,所以就分配与 len相同的值。
    3.3 当我们需要对字符串进行缩减,如果msg 缩减为 m。len = 1; free = 5;buf[]= [‘m’,‘\0’]。将这种设计,称之为 惰性空间释放(惰性空间删除)

  4. 二进制安全问题。C 语言来说,他的字符串是二进制不安全的,因为C语言的 空字符 结尾的设计,如果一个字符串中间有空字符串,那么 c语言的字符串的二进制转化会遗弃第一个空字符出现的后边的所有内容。 举例:
    m \0 s g \0. 如果是 C语言进行二进制转化,只对 m 进行转化; SDS 就不是啦,我们是自己封装的对象,我们能支持二进制的安全性,我能全部进行转化。

  5. C语言的空字符结尾有二进制问题,为什么 SDS 的 buf 里边还是以 空字符结尾呢? 因为SDS 里边毕竟是基于C 语言,时不时的也需要使用 C语言中字符串的一些方法,所以为了兼容一部分C 语言中字符串的操作,所以一空字符结尾。

string最大能支持多大呢

答案是512 M 了;
为啥呢:主要是sds中的len 为int 最大支持 3.2版本之前占4个字节
最大长度是2^32 ,多以最大存储是 2 ^32 /8/1024/1024=512m

字符串的使用场景

我的李姐 ,我们可以用在一下场景:
1 我们的数据是一个不常改变的,序列化的字符串或者是二进制转换的一个大的对象吧
2.做分布式锁 ;setnext key value
3.我们的session 存储,比如cas协议下的sessionid 通过redis来进行存储共享;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值