Redis
是基于 C
语言进行开发的,而 C
语言中的字符串是二进制不安全的,所以 Redis
就没有直接使用 C
语言的字符串,而是自己编写了一个新的数据结构来表示字符串,这种数据结构称之为:简单动态字符串(Simple dynamic string),简称 SDS
。
什么是二进制安全的字符串
在 C
语言中,字符串采用的是一个 char
数组(柔性数组)来存储字符串,而且字符串必须要以一个空字符串 \0
来结尾。而且字符串并不记录长度,所以如果想要获取一个字符串的长度就必须遍历整个字符串,直到遇到第一个 \0
为止(\0
不会计入字符串长度),故而获取字符串长度的时间复杂度为 O(n)
。
正因为 C
语言中是以遇到的第一个空字符 \0
来识别是否到了字符串末尾,因此其只能保存文本数据,不能保存图片,音频,视频和压缩文件等二进制数据,否则可能出现字符串不完整的问题,所以其是二进制不安全的。
Redis
中为了实现二进制安全的字符串,对原有 C
语言中的字符串实现做了改进。如下所示就是一个旧版本的 sds
字符串的结构定义:
struct sdshdr{
int len;//记录buf数组已使用的长度,即SDS的长度(不包含末尾的’\0’)
int free;//记录buf数组中未使用的长度
char buf[];//字节数组,用来保存字符串
}
经过改进之后,如果想要获取 sds
的长度不用去遍历 buf
数组了,直接读取 len
属性就可以得到长度,时间复杂度一下就变成了 O(1)
,而且因为判断字符串长度不再依赖空字符 \0
,所以其能存储图片,音频,视频和压缩文件等二进制数据,不用担心读取到的字符串不完整。
需要注意的是,sds
依然遵循了 C
语言字符串以 \0
结尾的惯例,这么做是为了方便复用 C
语言字符串原生的一些API,换言之就是在 C
语言中会以碰到的第一个 \0
字符当做当前字符串对象的结尾,所以如果一些二进制数据就会可能出现读取字符串不完整的现象,而 sds
会以长度来判断是否到字符串末尾。
在 Redis 3.2
之后的版本,Redis
对 sds
又做了优化,按照存储空间的大小拆分成为了 sdshdr5
、sdshdr8
、sdshdr16
、sdshdr32
、sdshdr64
,分别用来存储大小为:32
字节(2
的 5
次方),256
字节(2
的 8
次方),64KB
(2
的 16
次方),4GB
大小(2
的 32
次方)以及 2
的 64
次方大小的字符串(因为目前版本 key
和 value
都限制了最大 512MB
,所以 sdshdr64
暂时并未使用到)。 sdshdr5
只被应用在了 Redis
中的 key
中,value
中不会被使用到,因为sdshdr5
和其他类型也不一样,其并没有存储未使用空间,所以其是比较适用于使用大小固定的场景(比如 key
值):