本文将讲述如下内容:
1.Redis 中 Srting 类型的底层实现原理
- 通过 String 底层实现原理的学习,我们可以学习到哪些底层优化方法
3.Redis 中关于 String 命令介绍
我们知道 Redis 是由 C 语言实现的,在介绍 Sring 类型的实现之前我们先复习一下 C 语言的字符串类型。C 语言中的字符串是以空字符结尾的字符数组,详细说明见下图:
C 语言中的字符串
1、Redis 中 Srting 类型的底层实现原理
Redis 中没有直接使用 C 语言的字符串,而是构建了一套自己的抽象类型,名为简单动态字符串,简称 SDS。
如果你看 Redis 源码会发现这样一种结构体:
SDS 的定义
len 记录 buf 数组中已经使用字节的数量,也就是 SDS 类型所保存的字符串的长度。
free 记录了 buf 数组中未使用的字节数量
buf 是存储字节的数组,用于保存字符串从上面的结构我们可以看出:
Redis 的 String 类型封装成 SDS 结构,体现了用空间换时间的算法思想。牺牲了一些空间,来换取更快的查询效率。比如说结构体中 len 的值 5 表示这个 SDS 保存了一个五个字节长的字符串,O (1) 的时间复杂度就可以查询出结果。
Redis 的定位就是数据库层之上的一层缓存层,所以处处都要考虑高效。其实缓存本身也是用空间换时间思想的体现。
解决了 C 字符串容易缓冲区溢出的问题。因为 C 字符串不记录字符串长度,所以通过 C 语言的 strcat 函数拼接字符串的时候,容易造成拼接后的字符串超过了本身申请的字符串的长度,造成缓冲区溢出。SDS 就不会出现这个问题
空间预分配:在申请空间的时候预先分配好一定长度的空间。当空间不够用的时候,通过 SDS 提供的 API 可以重新申请一片更大的空间。
惰性释放空间:当申请的空间不再被使用的时候,不是立刻释放空间,而是在 SDS 中的 free 属性将这些字节的数量记录下来,等待将来使用
二进制安全:封装后的 SDS 解决了二进制安全问题,所以在 Redis 的 String 类型中可以缓存各种类型数据。SDS 的 API 会以处理二进制的方式来处理 SDS 存放在 buf 数组里的数据,不会对其中的数据做任何限制、过滤、或假设,数据在写入时是什么样的,它被读取时就是什么样的。
总结一下上面所说的,主要是两个核心思想。第一是 SDS 这种结构的实现;第二是空间换时间的思想。后面也会有文章专门介绍空间换时间、时间换空间两种思想的具体应用。
2、底层优化方法学习
从上面的介绍我们可以学习到哪些底层优化方法呢?上文反复提到用空间换时间思想,我想大多数开发人员在实际项目开发中都或多或少地使用过这种思想。Redis、Memcache 的设计思路就是这种思想的具体体现。除了 Redis,MySQL 中也有大量运用,比如说索引就是其中之一。在操作系统、计算机体系结构设计中也存在大量这种设计。
除了空间换时间,内存预分配、惰性释放也是很好的优化方法。比如说 PHP-FPM 进程管理方式中的动态方式(Dynamic),启动的时候预先生成 N 个 Worker 进程,当访问量增加时可以增加 Worker 进程的数量,当访问量降下来后再销毁掉或者保留这些增加的 Worker 进程,方面后面使用。
除了以上方法,还有很多值得学习和借鉴的方法,在此不再一一列举。如果这篇文章对你有帮助,欢迎转发给你的朋友,你们可以一起学习成长。如果有错误的地方或者表达不清晰的地方,也欢迎在评论区指出来。大家的支持就是我的动力,希望我们可以一起进步!
3、以下是 Redis 中 String 命令的介绍,可以结合前面讲的原理来学习这些命令,一定会有不一样的体会。