Redis字符串类型为什么能存整数,浮点型甚至是二进制位(使用SETBIT等命令)

2,679 阅读2分钟

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

比如,客户端执行命令:

redis>SET msg "hello world";
ok

那么Redis将在数据库中创建两个SDS分别存储键和值。

SDS的定义

每个sds.h/sdshrd结构表示一个SDS值:

struct sdshrd{
    // 记录buf数组中已使用字节的数量
    // 等于SDS所保存字符串长度
    int len;
    // 记录buf数组中未使用的字节数量
    int free;
    // 字节数组,用于保存字符串
    char buf[];
}

所以上面set msg "hello world",值在的SDS中的样子如下:

hello world的SDS
SDS遵循C语言以空字符串结尾的惯例,保存空字符串的一个字节不计算在len属性当中,并且为空字符串分配额外的一个字节空间,以及添加空字符串到字符串末尾等操作,都是由SDS函数自动完成的。遵循空字符串结尾这一特性的好处是可以复用一部分C字符串函数库中的函数。

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

C字符串获取长度需要遍历整个字符串,复杂度为O(N),而是用SDS的话,因为使用了一个len属性来记录字符串长度,所以获取长度的复杂度为O(1)。

SDS 其他特性这里暂不介绍

二进制安全

C字符串中的字符必须符合某种编码(比如ASCII),并且除了字符串的末尾之外,字符串里面不能包含空字符串,否则最先被程序读入的空字符串会被误认为是字符串末尾,这些限制使得C字符串只能保存文本数据,不能保存像图片、音频、视频等这样子的二进制数据。

Redis中的SDS的api都是二进制安全的,会以二进制的方式来处理SDS存放buf数组里的数据,程序不会对其中的数据做任何限制、过滤等,数据在写入时是什么样的,它被读取时就是什么样子。

使用SDS来保存之前提到的特殊数据格式(比如音频,视频等)就没有任何问题,因为SDS使用len属性的值而不是字符串来判断字符串是否结束。所以使用二进制安全的SDS,使得Redis不仅考验保存文本数据,还可以保存任意格式的二进制数据。

参考书籍:《Redis设计与实现》