写点什么

Redis 学习笔记 01:SDS 简单动态字符串

发布于: 2021 年 01 月 12 日
Redis学习笔记01:SDS 简单动态字符串

一、背景

1、Redis 是一个 key-value 存储系统,由 C 语言实现的

它支持存储的 value 类型很多(对外经常被用到的 五 种数据结构),包括 string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和 hash(哈希类型) 

2、Redis 数据库里面每个键值对都是由对象组成的:

  • 键:总是一个字符串对象

  • 值:字符串对象 / 列表对象 / 哈希对象 / 集合对象 / 有序集合对象

3、数据结构:SDS、双端链表、字典、压缩列表、整数集合 是内部使用的基础数据结构

这些基础的数据结构不仅和 redisObj 一起构成了对外暴露的 5 种数据结构,还被运用于 redis 内部的各种存储和逻辑交互,支撑起了 redis 的运行。

二、SDS 定义

Redis 没有直接使用 c 语言的字符串,而是自己定义了一个字符串数据结构:SDS(simple dynamic string)作为默认的字符串。我们设置的所有键值基本都是 SDS。


问题 1 :为什么 buf 数组是 字节数组?

(下面会有解答)

问题 2:为什么 Redis 要自己定义一个字符串数据结构,而不是使用 C 字符串呢?

C 字符串是这样的:


答:C 语言使用这种简单的字符串表示方法,并不能满足 Redis 对字符串在安全性、效率性以及功能方面的要求。

问题 3:为什么 C 字符串不能满足 Redis 对字符串在安全性、效率性以及功能方面的要求呢?

下面 三 即答案

三、SDS 与 C 字符串的区别

1、常数复杂度获取字符串长度

C 语言 ———— O(N)

SDS   ———— O(1)

因为其结构中保存了 len 这一属性

并且我们不需要手动修改 len 属性,设置和更新 SDS 长度的工作是由 SDS 的 API 在执行时自动完成的。

2、杜绝缓冲区溢出

C 语言:不记录自身长度,带来问题:容易造成缓冲区溢出

SDS:能做到自动扩展空间,杜绝溢出

           API 需要对 SDS 进行修改时,API 会先检查 SDS 的空间是否满足修改所需要的空间,如果不满足,API 会自动将 SDS 的空间扩展至执行修改所需的大小,然后才执行操作

3、减少修改字符串时带来的内存重分配次数

C 语言:每次处理增长或者缩短操作时,程序会对这个 C 字符串的数组进行一次内存重分配操作,很耗时

SDS:SDS 的 free 属性!

通过 free 属性(未使用空间),SDS 实现了 空间预分配 (场景:字符串增长)和 惰性空间释放 (场景:字符串缩短)两种优化策略!

(1)空间预分配

当 SDS 的 API 对一个 SDS 进行空间拓展时,程序不仅为 SDS 分配修改所需要的空间,还会为 SDS 分配额外的未使用空间,这与 cache 中的一些算法思想相类似,都是认为最近使用过的数据可能会被再次访问或者修改,于是便给其一个预留的未使用空间!

(2)惰性空间释放

当对 SDS 进行缩短时,程序并不立即使用内存重分配回收缩短后多出的字节,而是使用 free 属性将这些字节数量记录下来,等待未来可能的增长操作。

四、二进制安全

Redis 作为数据库,就必须确保能够在各种场景中使用,所以 SDS 的 API 都是二进制安全的!这里的各种各样场景指的是,保存的音频、图片、视频等等数据。

所以 SDS 的 buf 属性被称为字节数组——Redis 保存的数据不是“字符”,而是二进制数据!(问题 1 答案


Thanks for reading!


发布于: 2021 年 01 月 12 日阅读数: 41
用户头像

坚持分享接地气儿的架构技术文章! 2018.02.26 加入

同名微信公众号「架构精进之路」,专注软件架构研究,技术学习与职业成长!坚持原创总结、沉淀和分享,希望能带给大家一些引导和启发,感谢各位的支持(关注、点赞、分享)!

评论

发布
暂无评论
Redis学习笔记01:SDS 简单动态字符串