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

Redis到底怎么跑的?深入聊聊它背后的那些运行逻辑和原理

Redis之所以能这么快,核心秘密就在于它把绝大多数操作都放在了内存里完成,内存的读写速度是硬盘的几十上百倍,这就好比从你桌上拿一张纸和跑去图书馆找一本书的差别,但光是内存快还不够,它背后有一整套精妙的设计来支撑其高性能和稳定性。

单线程的真面目:为什么不怕堵车?

很多人一听说Redis是单线程的,第一反应是:那不会很慢吗?处理一个请求时,其他的不得干等着?这其实是个关键误解,Redis的核心网络请求处理和数据操作模块确实是单线程的(指主线程),你可能会想,现在的服务器都是多核CPU,这不是浪费吗?

Redis的作者有自己的考量,他选择单线程主要是为了避免多线程带来的复杂性竞争问题,多线程编程需要处理锁,而锁的获取和释放本身就是开销,搞不好还会导致线程死锁,让程序卡住,单线程就没这个烦恼,它像一个聪明的收银员,虽然一次只服务一位顾客(一个命令),但手脚极其麻利,而且永远不会算错账(数据永远一致)。

那它怎么应对海量连接呢?这就依赖于高效的I/O多路复用技术(来源:Redis官方文档),你可以把它想象成一个大堂经理,这个经理同时监听餐厅里所有桌位(网络连接)的呼叫铃,有哪一桌需要点菜(有数据可读)或者上菜(可以发送数据),经理就立刻通知后厨(主线程)去处理,这样,一个线程就能高效处理成千上万的网络连接,避免了为每个连接创建一个线程的巨大开销,单线程模型在Redis的语境下,反而成了高并发能力的功臣。

Redis到底怎么跑的?深入聊聊它背后的那些运行逻辑和原理

数据的“快照”与“日记”:如何保证数据不丢?

既然数据都在内存里,服务器一断电或者重启,数据不就全没了吗?没错,这是内存数据库的“阿喀琉斯之踵”,Redis提供了两种主要的持久化机制来解决这个问题,就像给内存中的数据上了双重保险。

第一种叫RDB(快照),你可以把它理解为给整个数据库拍一张全景照片,然后把这张照片保存到硬盘上(生成一个.rdb文件),这张照片记录了某个时间点Redis里所有数据的完整状态,RDB的优点是恢复速度快,文件也比较紧凑,缺点是如果两次拍照之间服务器宕机,那么最后一次快照之后的数据就丢失了。

第二种叫AOF(追加日志),它不像拍照,而更像是写日记,每执行一条会改变数据的命令,Redis就把这条命令原原本本地追加到AOF文件的末尾,当Redis重启时,它会把“日记”从头到尾重新执行一遍,从而还原出内存中的数据状态,AOF的优点是数据安全性高,最多丢失一秒的数据(可配置),缺点是文件通常会比RDB大,而且恢复速度慢。

Redis到底怎么跑的?深入聊聊它背后的那些运行逻辑和原理

在实际生产中,通常会将两者结合使用,用AOF来保证数据安全,定期用RDB来做灾难恢复的备份。

“过期”的秘密:如何自动清理无用数据?

Redis可以给键值对设置一个存活时间(TTL),时间一到,数据就自动被删除,这个功能是怎么实现的呢?它主要用了两种策略(来源:Redis官方文档关于过期键的删除策略)。

一种是惰性删除,当客户端尝试访问一个键时,Redis才会顺便检查一下这个键是否已经过期,如果过期了,就立刻删除,然后返回空值,这就像你只有去冰箱拿牛奶时,才会发现它已经变质了然后扔掉,这种方式很及时,但缺点是如果过期键永远不被访问,它就永远占着内存,成了“垃圾”。

Redis到底怎么跑的?深入聊聊它背后的那些运行逻辑和原理

另一种是定期删除,Redis会每隔一段时间(默认100毫秒)随机抽取一部分设置了过期时间的键进行检查,并删除其中已过期的,这就像你定期巡视冰箱,主动清理掉过期的食物,这种方式是惰性删除的补充,帮助清理那些不被访问的垃圾。

通过这两种方式的结合,Redis在性能和内存回收之间取得了很好的平衡。

丰富的数据结构:为什么不只是简单的键值对?

Redis的强大,还在于它不仅仅是简单的key-string存储,它支持字符串、列表、哈希、集合、有序集合等多种数据结构,这些数据结构不是花瓶,而是直接对应着各种复杂的业务场景。

列表可以轻松实现消息队列;用哈希可以完美存储一个对象的多个字段(如用户信息);用有序集合可以直接做排行榜功能,最关键的是,Redis为这些数据结构提供了丰富的、原子性的操作命令,这些命令都是在单线程中执行的,所以不存在并发修改的问题,保证了操作的原子性。

总结一下

Redis的运行逻辑可以概括为:以内存为核心舞台,用单线程加I/O多路复用来避免并发冲突、高效处理请求,再通过RDB和AOF两种持久化机制将数据持久到硬盘以防丢失,并利用惰性与定期删除策略管理内存空间,最后通过丰富的数据结构直接赋能各种业务场景。 这一套组合拳,共同造就了Redis在数据存储领域的独特地位。