当前位置:首页 > 问答 > 正文

Redis核心技术那些事儿,带你慢慢捋清楚底层原理和关键点

主要参考自《Redis设计与实现》一书、Redis官方文档以及多位技术博主如“程序员小灰”、“小林coding”等对Redis核心原理的解读)

Redis之所以这么快,很多人第一反应就是“因为它基于内存”,这话没错,但只说对了一半,内存操作固然比硬盘快成千上万倍,但Redis的快,还隐藏着许多精妙的设计,咱们今天就慢慢捋一捋这些底层原理和关键点。

第一件事儿:高效的数据结构是基石

你可以把Redis想象成一个超级快的“键值对”大仓库,但它的厉害之处在于,这个“值”可以是各种各样的数据结构,比如字符串(String)、列表(List)、哈希(Hash)、集合(Set)等等,Redis并没有直接使用像C语言里那种简单的链表或哈希表,而是为每种数据结构都做了深度优化。

举个例子,Redis的字符串(String)不光是存文本,还能存数字、甚至二进制数据,它采用了一种叫“简单动态字符串(SDS)”的结构(来源:《Redis设计与实现》),这个SDS和C语言自带的字符串比,有什么好处呢?主要有三点:1. 获取字符串长度特别快,直接读一个属性就知道,而C语言需要遍历整个字符串去数,2. 避免了“缓冲区溢出”的安全问题,因为SDS在拼接字符串时会先检查空间够不够,3. 减少了修改字符串时带来的内存重新分配次数,通过“预分配空间”和“惰性空间释放”的策略,提升了效率。

Redis核心技术那些事儿,带你慢慢捋清楚底层原理和关键点

再比如,Redis的哈希(Hash)类型,在存储少量键值对时,使用的是一种叫“ziplist”(压缩列表)的紧凑型结构,而不是直接上哈希表,这种结构将所有数据紧挨着存放,能极大地节省内存,只有当数据量超过一定阈值时,才会转换成真正的哈希表来保证操作效率,这种“看人下菜碟”的设计思想,贯穿了Redis的许多数据结构。

第二件事儿:单线程模型怎么反而快了?

这是Redis最让人困惑也最精妙的一点,是的,Redis处理网络请求和执行命令的核心模块是单线程的,你可能会想,现在都是多核CPU的时代了,单线程不是浪费吗?为什么还能这么快?

关键在于,Redis的主要性能瓶颈不在于CPU,而在于内存和网络I/O,多线程虽然能利用多核,但会带来复杂的并发控制问题,比如锁竞争,处理不好反而会降低性能,Redis的单线程模型省去了这些烦恼,带来几个巨大优势:

Redis核心技术那些事儿,带你慢慢捋清楚底层原理和关键点

  1. 没有锁竞争开销:所有操作都是顺序执行的,不存在需要加锁解锁的场景,非常纯粹。
  2. 避免了线程切换和竞态条件的消耗:CPU不用在不同的线程间来回切换,可以专注处理当前的请求。

单线程如何应对海量并发连接呢?Redis使用了I/O多路复用技术(参考技术博主“小林coding”的解读),你可以把这个技术理解成一个超级高效的门卫,这个门卫(比如epoll、kqueue等系统调用)会同时监听成千上万个客户端的请求,当某个客户端有命令到达时,门卫就把它记下来,然后统一交给Redis唯一的工作线程去按顺序处理,这样,一个线程就轻松管理了无数个连接,既高效又简单。

Redis也不是完全的单线程,在进行持久化操作(后面会讲)或一些大键删除时,会用到后台线程来处理,以避免阻塞主线程。

第三件事儿:持久化——如何把内存数据存到硬盘?

既然数据都在内存里,一断电不就全没了吗?Redis提供了两种主要的持久化机制,把数据保存到硬盘上,保证数据安全。

Redis核心技术那些事儿,带你慢慢捋清楚底层原理和关键点

一种是RDB(快照),就像是给当前的内存数据拍一张完整的照片,然后保存成一个文件(dump.rdb),这个过程可以定时执行,比如每隔5分钟拍一次,它的优点是生成的备份文件非常紧凑,恢复大数据集时速度极快,缺点是可能会丢失最后一次快照之后的数据(比如刚拍完照,服务器就宕机了)。

另一种是AOF(追加日志),它不拍照片,而是把每一次写命令都记录到一个日志文件里,当Redis重启时,会重新执行一遍AOF文件里的所有命令,从而恢复数据,这种方式数据安全性高,最多丢失一秒的数据(可以配置),缺点是日志文件会越来越大,而且恢复速度比RDB慢,所以Redis提供了AOF重写机制,定期根据当前内存数据生成一个精简的新AOF文件替换老的。

在实际生产中,通常两者会结合使用,用AOF来保证数据不丢失,用RDB来做冷备和快速恢复。

第四件事儿:过期键的删除策略

我们经常给Redis的key设置一个过期时间,那Redis是怎么知道哪个key过期了并把它删掉的呢?它用了两种策略结合的办法(来源:《Redis设计与实现》)。

  1. 惰性删除:当客户端尝试访问一个key时,Redis会先检查它是否过期,如果过期就立刻删除,然后返回空值,这就像是你只有去抽屉里找东西时,才发现它已经坏了然后扔掉。
  2. 定期删除:光靠惰性删除不行,万一有些过期key永远没人访问,不就成了“僵尸key”永远占着内存吗?所以Redis会每隔一段时间(默认100毫秒)随机抽取一批设置了过期时间的key,检查并删除其中已过期的,通过限制执行的时长和频率,来减少对主线程的影响。

这两种策略配合,既不会过度消耗CPU,又能及时清理掉大部分过期数据。

Redis的高性能不是单一因素决定的,而是精妙优化的数据结构、高效的单线程I/O模型、可配置的持久化方案以及合理的内存管理策略等多个核心技术点共同作用的结果,理解这些底层原理,能帮助我们在实际使用时做出更合理的配置和问题排查。