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!
版权声明: 本文为 InfoQ 作者【架构精进之路】的原创文章。
原文链接:【http://xie.infoq.cn/article/9d9fa295d4f5f488623417e5c】。文章转载请联系作者。
评论