Redis学习系列(一) -- 简单动态字符串概述

听过 Redis 大名的人可能很多吧?多多少少都知道 Redis 的快,能抗住很高的并发量。也知道 Redis 是单线程,操作都是原子性的。下面我们看看 Redis 中字符串的设计。

Redis 为什么那么快!

  1. Redis 是基于内存的数据库,我们知道在内存中的访问速度不是硬盘可以比拟的,纯粹的内存操作也让性能更高。
  2. 单线程的优势。单线程可以避免多线程环境中存在的上下文切换问题,也不需要去考虑线程安全的问题(加锁)。
  3. 强大的数据结构,Redis 专门设计的数据结构,可以应对大量频繁修改的请求。
  4. 最核心的一点 – IO 多路复用(这个还没学完)。

下面我们来看一下 Redis 对字符串的设计。

Redis 字符串的设计
我们知道 Redis 使用的是 C 语言编写的。但是,却不是使用 C 语言传统的字符串(传统字符串可以说是数组了,每个字符放入字符数组中)。

我们先来看看 C 字符串的设计存在的几个小问题:

  1. 效率问题:
    C 字符串是不会记录当前字符串的长度的,当我们需要获取字符串长度时,会遍历整个字符串,直到遇到结束标识 “\0” 为止。
    在这里插入图片描述
    长度计算就想上面图示样子了!遍历对每个字符进行计数,而且还是每次来都要计数,如果字符串特长,那效率就很低了。

  2. 缓冲区溢出问题:
    数组的创建每次都要指定长度,这也是 C 字符串不记录长度所带来的问题之一。C 语言中有个函数 strcat 会将该字符串拼接到上一个字符串的末尾。由于 C 语言不记录字符串长度,修改字符串内容时,分配的空间不足以容纳新字符串,这就会造成缓冲区溢出问题。

举个例子:
假设内存中有两个相邻的字符串 s1 和 s2。字符串如下:
s1 和 s2 字符串
这时,我们要修改 s1 的字符串,将原来的 REDIS 字符串修改成 REDIS TEST 如果在修改时,没有对空间进行扩容。那可能会出现溢出现象,我们 s1 溢出到 s2 的位置,导致原来 s2 的数据被 s1 的内容覆盖。
被覆盖的 s2 字符串

Redis 的解决方案
为了解决这个 C 字符串的带来的问题,redis 设计时使用的不是传统的 C 字符串,而是使用另一种方式 – SDS。

SDS 设计之初,在字符串构建完成时,已经记录下了字符串的长度,并有一个位置记录剩余的空间。在修改字符串时,会先验证当前空间是否能容纳下新字符串。如果不能,则对空间进行扩容,这样一来就解决了 C 字符串所带来的问题。下面我们举个例子来学习一下 SDS:

我们有一个字符串 Redis,字符串长度为 5,没有剩余的空间 ,具体如下:
在这里插入图片描述
这时,我们调用 SDS API 中字符串添加的函数 sdscat 。将字符串 " Cluster" 追加到原字符串末尾。上面说过 在追加前会进行空间检查,空间不足情况下会进行扩容。
在这里插入图片描述
我们从上面两个图可以看出,长度变为了 len=13, 剩余空间也变成 free=13。这时,我们在添加一个新字符串 " Temp"(字符串前面有空格,占用一个字节),字符串在添加前还是会进行校验,由于剩余空间 13 > 5 字节,所以不需要扩容,直接添加进去。
在这里插入图片描述
由上面的图解,我们大致了解了 SDS 的扩容与追加。在这里笔者具体来解释一下 freelen

len
主要目的是记录字符串的长度,Redis 作为一个高效的内存数据库。每次去计算长度无疑是效率低下的表现,记录下来也方便读取。

free
这个字段也是为了提高性能而设计的,Redis 中数据会被频繁的修改。如果每次修改都重新分配一次内存。光是每次分配内存都耗去一大堆的时间,这无疑也是降低 Redis 的性能,这是不可接受的。为此添加了 free 字段,记录剩余空间。

如上面所说,开始时,只有 REDIS 这占 5 字节的字符串。接下来寄来的 “ Cluster” 字符串进来时,发现空间不够,就会扩容。扩容后会为 free 也分配一个额外的空间 。free 空间的大小和 len 的长度一致(1m 以内是一致)。最后实际占用空间为 13 + 13 + 1 =27 个字节。多出的那个 1 字节为占位符。

上面介绍了增加的情况,SDS 还要一种惰性释放空间的方式。

惰性释放空间
我们还是以下图 Redis 字符串为例:
在这里插入图片描述
当我们对字符串进行缩减时,SDS 不会直接释放空间,而是留出 free 空间,应对下一次对字符串的修改。尽可能减少空间的扩容。
在这里插入图片描述
上面就是 Redis 动态字符串的简单讲解,我们知道 Redis 中还有很多的数据结构,比如:链表,字典,跳跃表。这些内容将在后续章节慢慢讲解。

总结:
本章我们主要是学习了 Redis 中简单动态字符串的设计。了解了 Redis 为什么会那么快,当然,Redis 能那么快,肯定不止如此,还需要继续深入学习。

有兴趣的同学可以关注公众号!
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值