Redis之字符串

:本篇博客为阅读《Redis设计与实现》的读书笔记

1 底层实现

Redis 的字符串是利用 SDS 来表示的,其底层具体实现如下:

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

2 与 C 字符串区别

2.1 获取长度复杂度

C 的字符串并没有保存长度,因此,每当需要获取一个字符串的长度时,需要进行一次遍历,每次遍历 +1,当遍历到 ‘\0’ 字符时停止,这个时间复杂度为 O(N)。而 Redis 已经存储了字符串的长度,因此获取长度的时间复杂度为 O(1)。

2.2 杜绝缓冲区溢出

因此 Redis 字符串中利用 free 保存了还可以存储的字符串,当需要添加字符串时,会根据这个变量判断是否有足够的空间,如果没有的话,就会对 buf 数组进行扩展,这样就可以避免缓冲区泄漏的问题了。

2.3 内存重分配

因为 Redis 中的数据是要被频繁修改的,因此 SDS 需要在频繁的修改下还能保持一定的性能,那么可以从哪些地方优化呢?当需要添加一个字符串,并且该字符串的长度大于剩余的空间(由 free 变量标识)时,Redis 需要对 buf 数组进行扩充,怎么样才能减少扩充 buf 数组的次数呢?Redis 提供了两种分配策略:

  • 空间预分配
    当添加一个字符串之后,Redis 会给该字符串预留同等长度的空间。例如 SDS 存储了 “Redis” 的字符串,现在没有剩余空间,因此 free 字段为 0,当需要再添加一个 “hello” 字符串时,SDS 先扩充为可以存储 10 字符的数组,将 hello 存储进 buf 数组后,还会为 buf 数组额外添加 10 个字节作为存储空间。
    这是 SDS 存储字符小于 30MB 的情况,当 SDS 存储长度大于 30MB 时,其额外提供的空间为 1 MB。
  • 惰性空间释放
    上面的分配策略是在添加字符串时提供的,当字符串需要删除其中的一些字符时,SDS 并不会将这些空间释放出来,而是直接作为未使用空间保存下来,这样,当需要再次添加字符串时,这些空间就可以用上了。

2.4 二进制安全

C 的字符串是根据 ‘\0’ 来判断是否到达字符串末尾,因为这个特性它是不能保存图片、音频、视频等二进制数据的,而 Redis 中的字符串是根据 len 变量判断数据是否到达末尾了,因此它保存二进制数据并且可以读取出来。

3. SDS API

这一部分可以查看官方文档,就不一一列出了。

猜你喜欢

转载自blog.csdn.net/FireFox1997/article/details/82743858