Redis底层数据类型

发布时间 2023-07-14 14:40:35作者: pf666nb

Redis底层基础数据类型

1.SDS的定义

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

img

1.2 SDS 与 C 字符串的区别

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

因为c字符串并不记录自身长度信息,所以为了获取一个c字符串的长度,程序必须遍历整个字符串,对遇到的每个字符进行计数,直到遇到代表字符串结尾的空字符串为止,这个操作的复杂度为O(N),和c字符串不同,因为SDS在len属性中记录了SDS本身的长度,所以获取一个SDS长度的复杂度仅为O(1)。
img

设置和更新SDS长度的工作是由SDS的API在执行时自动完成的,使用SDS无需进行任何手动修改长度的工作,通过使用SDS而不是C字符串,Redis将获取字符串长度所需要的复杂度从O(N)降低到O(1),这确保了获取字符串长度的工作不会成为Redis性能的瓶颈。所以即使我们对一个非常长的字符串使用STRLEN命令,也不会对系统的性能造成任何的影响

1.2.2 杜绝缓冲区溢出

除了获取字符串长度的复杂度高之外,c字符串不记录自身长度带来的另一个问题是容易造成缓存区溢出,与c字符串不同,SDS的空间分配策略完全杜绝了这种可能性,当SDS API 需要对SDS进行修改的时候,API会首先检查SDS的空间是否满足修改的要求,如果不满足会自动的扩展到所需要的大小,

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

c字符串总不记录自身长度,而是采用N+1个字符长度的数组,每次增长或者缩短一个c字符串,程序总要对保存这个c字符串的数组进行一次内衬重分配操作,通过未使用空间,SDS实现了空间预分配和惰性空间释放两种优化策略。

1.2.3.1 空间预分配

空间预分配用于优化SDS的字符串增长的操作,当SDS的API对一个SDS进行修改,并且需要对SDS进行空间扩展的时候,程序不仅会为SDS分配必要的空间,还会为SDS分配额外的空间。额外空间的分配原则是

  1. 如果对SDS进行修改后,SDS的长度将小于1MB,那么程序分配和len属性一样的大小的未使用空间,实际空间将变为 2len+1的空间
  2. 如果对SDS进行修改后,SDS的长度大于1MB,那么程序将分配1MB的未使用空间,空间大小将为 N+1MB+1byte的空间

1.2.3.2 二进制安全

c 字符串中的字符必须符合某种编码,并且除了字符串的末尾之外,字符串里面不能包括空字符,否则,最先被程序读入的空字符将会被认为是字符串的结尾,这些限制使得c字符串将只能保留文本数据,而不能保存图片,音频视频,压缩文件这样的二进制文件,为了确保redis可以适用于不同的场景,SDS的API都是二进制安全的,因为,SDS是使用len属性的值而不是空字符来判断字符串是否结尾,使用二进制安全的SDS,而不是c字符串,使得Redis不仅可以保存文本数据,还可以保存任意格式的二进制数据,

1.2.3.3 兼容部分C字符函数

虽然SDS的API都是二进制安全的,但是他们一样遵循c字符串,以空字符结尾的惯例,这些API,总会将SDS保存的数据的末尾设置空字符串,这是为了让那些保存文本数据的SDS可以重用一部分<string.h>库定义的函数

1.2.4 总结

img