面试题解-Redis的String是如何实现的?

源码共读

共 2077字,需浏览 5分钟

 ·

2021-04-11 22:22

👇👇关注后回复 “进群” ,拉你进程序员交流群👇👇
作者丨安琪拉的博客
来源丨安琪拉的博客

第44题: Redis 的String 是怎么实现的?为什么不直接用c的字符串?

Redis 没有直接使用C 语言的字符串表示,而是自己构建一种简单动态字符串(SDS: simple dynamic string)。

Redis 中的String 都是SDS,例如我们执行这样一条命令:

redis> SET blog angela

那么Redis 在内存中创建了一个键值对,

  • 键:键是一个字符串对象,对应底层实现是一个保存字符串“blog” 的SDS;
  • 值:值也是一个字符串对象,对应底层实现是一个保存字符串是“angela”的SDS。

如果执行

redis> RPUSH blog "angela" "de" "blog"

那么Redis 将在内存中创建一个键值对,键还是一个SDS,存放“blog”,值是一个列表,存放三个SDS,“angela”、“de”、“blog”

SDS如何实现的呢?

首先SDS被定义为这样一个结构体:

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

举个例子:

现有执行redis> SET blog angela 命令后,value值在redis 中存放如下图所示,buf存放字节数组(真实数据),len表示存放字符串的长度(不包括结束符号'\0'),free表示剩余空间,可以看到还剩5个字节。

SDS遵循了C语言字符串以空字符结尾的惯例,保存空字符的1个字节空间不在SDS 的len属性里面。这样做有个好处是我们直接可以复用C 提供的库函数,比如打印字符串,直接用C 提供的printf("%s", s->buf);

那又是为什么不直接用C语言提供的字符串呢?

在C语言中,表示一个“angela” 的字符串如下图所示,结束也是通过空字符表示:

C语言的字符串和SDS的区别如下:

  • 长度获取效率:C语言如果需要获取字符串长度,需要从头开始遍历,时间复杂度O(n),SDS提供len属性,访问时间复杂度O(1), Redis的strlen 获取字符串长度函数性能毫无压力;

  • 杜绝溢出:C字符串不记录自身长度的另一个问题是容易造成缓冲区溢出,比如要做字符串拼接,char *strcat(char *dest, const char *src), 讲src 字符串拼到desc字符串,如果desc忘记提前扩容,就会溢出,而恰好desc后面正好有数据,则会被覆盖;

  • 减少内存重分配:对于Redis这种内存数据库,很多场景会频繁更新value的值,那如果采用C字符串,value长度有变化,就需要频繁分配内存,SDS做了内存的预分配和惰性释放,能有效减少内存分配次数,内存的重分配代价还是很高昂的,对于Redis这种对性能要求非常高的缓存产品,这种性能损耗是不能接受的;

  • 二进制安全:C字符串必须符合某种编码(比如ASCII),除了空字符结尾,字符串中间是不能包含空字符的,否则会被误以为是字符串结尾。这就限定了C字符串不能用来存储类型图片、音频、视频、压缩文件这种二进制书数据,但是SDS可以,SDS设计的API都是二进制安全的。

-End-

最近有一些小伙伴,让我帮忙找一些 面试题 资料,于是我翻遍了收藏的 5T 资料后,汇总整理出来,可以说是程序员面试必备!所有资料都整理到网盘了,欢迎下载!

点击👆卡片,关注后回复【面试题】即可获取

在看点这里好文分享给更多人↓↓

浏览 5
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报