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

Redis到底怎么跑起来的?揭秘那些让它快到飞起的底层逻辑和技巧

Redis之所以能快到飞起,绝不是偶然,而是其设计者在每一个关键环节都做了精心的选择和优化,咱们就抛开那些难懂的专业术语,像剥洋葱一样,一层层看看它到底是怎么跑起来的。

第一层:把家安在内存里——速度的基石

这其实是Redis最快最根本的原因,简单到令人发指,想象一下,你去图书馆找一本书,如果这本书就放在你手边的书桌上(内存),你伸手就能拿到,但如果这本书存放在图书馆地下三层的密集书库里(硬盘),你就得先申请,然后等管理员花时间下去找,再给你送上来,这个等待的时间差,可能就是几千甚至几万倍。

Redis选择把所有数据都放在内存(RAM)里操作,就是选择了“伸手就拿”的极致速度,内存的读写速度是纳秒级别的,而硬盘(即使是SSD)是毫秒级别的,这根本不是一个量级的较量,根据Redis官方文档(Antirez在《Redis宣言》中的阐述),他们坚信内存的成本在不断下降,而数据的价值在不断提升,用内存换取极致的性能是完全值得的,任何试图在磁盘上运行的数据库,在纯粹的速度上,先天就无法与基于内存的Redis竞争。

第二层:单线程干活——意想不到的利大于弊

很多人一听“单线程”就觉得它落后,会慢,但Redis的单线程设计,恰恰是保证其高性能和简单性的一个妙招,你可以把Redis想象成一个非常高效的、只有一个窗口的银行柜台,这个柜员(主线程)业务能力超强,处理一笔业务的速度极快。

单线程的好处是什么呢?

Redis到底怎么跑起来的?揭秘那些让它快到飞起的底层逻辑和技巧

  1. 省去了“锁”的烦恼:如果是多线程,多个柜员同时操作同一个客户的账户,就得互相协调,比如用“锁”来保证不会算错钱,这个加锁、解锁的过程本身就有开销,而且搞不好还会发生“死锁”(几个柜员互相等着,谁都干不了活),单线程根本不存在这个问题,所有操作都是排着队一个一个来,天然就是线程安全的。
  2. 避免了CPU切换的消耗:多线程在单核CPU上运行需要频繁切换,这个切换动作(上下文切换)本身也要消耗CPU资源,单线程就没这个开销,可以心无旁骛地干活。

这个设计有个前提:每个业务必须处理得飞快,不能有慢操作堵住后面所有人,所以Redis要求所有操作都是原子性的,并且要避免那些耗时很长的命令,那有人会问,现在都是多核CPU,单线程不是浪费吗?Redis在后续版本也做了优化,比如用额外的线程去处理一些耗时的后台任务(比如持久化、大键删除),但最核心的接收命令、执行命令、返回结果这个流程,依然是由那个最强悍的单线程柜员负责,以保证全局的简单和高效。

第三层:高效的数据组织——“巧妇”的秘诀

Redis快,还因为它是个“巧妇”,它用了特别适合内存的数据结构来存储数据,它不仅仅是简单的key-value存储,它的value可以是多种类型,比如String(字符串)、List(列表)、Hash(哈希字典)、Set(集合)等。

这些数据结构在底层实现上非常精炼,比如它的Hash类型,在数据量小的时候,采用的是类似数组的ziplist(压缩列表) 结构,这种结构将所有数据和键值紧挨着存放,能极大地减少内存占用,因为内存不仅贵,而且容量有限,减少内存使用意味着可以在同样的内存里放下更多数据,并且减少访问内存的次数(CPU缓存命中率更高),这反过来又提升了速度,只有数据量变大时,它才会转换成更适用于大量数据的哈希表,这种灵活的结构选择,确保了在任何场景下都能保持高效。

Redis到底怎么跑起来的?揭秘那些让它快到飞起的底层逻辑和技巧

第四层:持久化的智慧——鱼与熊掌兼得

数据全放在内存里,万一服务器断电了,数据不就全没了吗?Redis当然考虑了这一点,它提供了两种主要的持久化机制,相当于给内存中的数据拍照存档。

  • RDB(快照):就像给数据库拍一张全景照片,在特定时间点,Redis会fork出一个子进程,将当前内存中的数据完整地写入一个压缩过的二进制文件,这个方式恢复数据很快,文件也小,但缺点是可能会丢失最后一次快照之后的数据。
  • AOF(追加日志):就像记日记,把每一个写命令都记录在一个文件里,当Redis重启时,重新执行一遍日记里的所有命令,就能恢复数据,这种方式数据安全性高,最多丢失一秒的数据,但日志文件会越来越大,恢复速度也慢。

Redis允许你同时使用两者,用AOF来保证数据安全,用RDB来方便备份和快速恢复,为了解决AOF文件过大的问题,Redis会定期进行AOF重写,也就是根据当前内存中的数据,重新生成一个最精简的AOF日志,去掉中间多余的操作命令。

第五层:网络的极致利用——单线程的完美搭档

Redis使用了I/O多路复用技术,这听起来复杂,但理解起来不难,还是那个银行柜员的例子,单线程柜员怎么知道哪个客户先来呢?他不需要主动去问,而是有一个叫“叫号器”(多路复用器,如epoll)的帮手,这个帮手会帮他盯着所有来办理业务的人(网络连接),当某个人准备好要办业务时(数据就绪),叫号器才通知柜员来处理,这样,一个柜员就能同时应对成百上千的客户,而不会傻等着某一个人,这使得Redis的单线程模型在网络I/O这个最容易阻塞的环节上,依然能保持极高的吞吐量。

Redis的快是一个系统工程的结果:内存作为主战场提供了基础速度,单线程模型避免了内部竞争带来的损耗,精妙的数据结构提升了内存和CPU的利用效率,灵活的持久化方案在速度和数据安全间取得了平衡,而I/O多路复用则让单线程能高效地处理海量网络连接,这些设计环环相扣,共同造就了Redis这个速度传奇。