一、先从整体上看:Redis 在后端系统里到底扮演什么角色
如果只用一句最通俗的话来概括 Redis,那么可以这样说:Redis 是一个高性能的内存键值存储系统,同时也是一个内存数据结构服务。
第一,Redis 的数据主要放在 内存 里。
这意味着它访问速度非常快,因为内存比磁盘快得多。但这也意味着它不是一个“无限存储”的地方,内存贵,而且容量有限,所以 Redis 从设计上就不适合存放所有数据,它更适合存放那些“最值得快”的数据。
第二,Redis 是 key-value 型的。
也就是通常通过一个 key 去找到对应的 value。和 MySQL 那种“表、行、列、复杂 SQL、事务、多表关联”的模式不一样,Redis 更强调“快速、直接、高频”的读写访问。
第三,Redis 不只是“存字符串的缓存工具”。
它其实支持很多数据结构,比如 String、Hash、List、Set、ZSet 等,这使它不仅能存数据,还能方便地做计数器、排行榜、去重、限流、分布式锁等功能。所以更准确地说,Redis 既是缓存层,也是高性能数据结构工具箱。
从整个后端系统的视角看,Redis 的角色通常不是替代 MySQL,而是和 MySQL 分工协作:
- MySQL 负责核心数据的长期、稳定、结构化存储
- Redis 负责热点数据加速、临时状态存储、部分高并发能力支撑
可以理解为:MySQL 负责“存得住”,Redis 负责“跑得快”。
二、Redis 为什么会成为后端高频组件
Redis 之所以在后端开发里这么常见,是因为现代系统普遍都有这样几类需求:
- 请求量很大,希望访问足够快
- 热点数据很多,希望不要每次都查数据库
- 有些状态数据变化频繁,适合放在内存里处理
- 需要一些轻量但高性能的能力,比如计数、排序、去重、锁、限流
如果这些事情全交给 MySQL,也不是完全做不了,但代价会比较高。因为 MySQL 更擅长的是结构化存储、事务、一致性和复杂查询,不擅长承担所有高频简单读写的压力。
于是,Redis 就成了后端系统里非常自然的一层:
- 对热点数据做缓存
- 把高频读请求挡在前面
- 降低 MySQL 压力
- 提供一些关系型数据库不太擅长的高性能数据处理能力
所以 Redis 的价值,本质上是:加速
三、Redis 为什么快
原因一
它把数据主要放在内存里。
内存比磁盘快很多,所以当 Redis 读写数据时,不像磁盘型数据库那样需要频繁处理慢速磁盘 IO。这是 Redis 高性能的基础。
但如果只说“因为它在内存里”,其实还不够完整。Redis 快,不只是因为数据在内存中,还因为它整个系统设计都在尽量减少额外成本。
原因二
Redis 的操作模型很简单。
Redis 的很多操作本质上是:
- 根据 key 直接取 value
- 对某个数做自增
- 对集合做增删查
- 对排行榜按 score 排序
它不像 MySQL 那样,经常要走 SQL 解析、执行计划、索引选择、事务判断这些更重的路径。所以 Redis 不只是“取数据快”,而是“做事也比较直接”。
原因三
Redis 提供了多种高效的数据结构。
比如:
- String 适合简单值和计数
- Hash 适合对象字段
- Set 适合去重
- ZSet 适合排序和排行榜
它不是把所有问题都塞到一个通用容器里,而是根据不同业务提供了适合的数据结构,所以很多场景天然就能高效处理。
原因四
Redis 的核心命令执行路径采用了比较简洁的线程模型。
常见的说法是 Redis 单线程,但更准确地说,Redis 的核心命令执行路径通常是单线程串行处理的。这样做的好处是减少了锁竞争、线程切换和并发同步带来的额外成本。对于 Redis 这种“单次操作短、逻辑直接、内存访问快”的系统来说,这种设计反而很高效。
原因五
Redis 的网络事件处理也比较高效。
它可以在轻量的模型下处理大量连接,而不是每来一个请求就创建复杂线程模型去处理,这也减少了系统运行成本。
总结
Redis 快,不是因为某一个神奇点,而是因为它把“数据位置、操作模型、数据结构、执行路径、网络处理”这些环节都尽量做得更短、更轻、更直接。
四、Redis 的常见数据类型
很多人学 Redis 的数据类型时,容易变成背命令。但真正重要的不是命令,而是:看到一种业务需求时,你能不能想到对应的数据结构。
Redis 最常见的几种数据类型:
String 最基础也最通用的类型。
它适合存单个值、数字、JSON 字符串、序列化对象,也很适合做计数器,比如阅读数、点赞数、访问次数。很多缓存场景第一反应都可以先想 String。
Hash 更适合存对象。
比如用户信息、商品基础信息、配置信息等。如果一个对象有多个字段,而且你经常想单独读写其中某一个字段,那么 Hash 往往比把整个对象序列化成 String 更灵活。
List 适合维护有顺序、可重复的一组数据。
它常见于简单消息队列、最新消息列表、最近浏览记录等场景。它的核心特点不是去重,也不是排序分值,而是“有先后顺序”。
Set 适合“无序且不重复”的数据。
比如点赞用户集合、参加活动的用户集合、标签集合等。它特别适合去重、成员判断和集合运算。
ZSet 适合排序任务。
它是在 Set 的基础上,给每个元素再配一个 score,然后按 score 排序。所以它特别适合做排行榜、热度榜、活跃榜、优先级排序等场景。
所以学 Redis 数据结构的关键不是死记定义,而是形成一种条件反射:
- 存单值、计数,用 String
- 存对象字段,用 Hash
- 要顺序列表,用 List
- 要去重和成员判断,用 Set
- 要排名和排序,用 ZSet
五、Redis 最核心的应用场景:缓存,以及它和 MySQL 的配合关系
Redis 在后端系统里最经典的身份,仍然是:缓存
缓存的本质,可以理解成一句话:把未来可能还会被重复访问的数据,提前放到一个更快的位置。
后端里之所以需要缓存,是因为大量业务请求都具有“热点访问”的特点。比如热门商品、热门文章、首页推荐、用户资料、热搜榜等,它们在短时间内会被很多用户反复读取。如果每次都直接查 MySQL,就会给数据库带来很大的压力。
所以 Redis 和 MySQL 的典型配合关系是:
- MySQL 作为正式数据底座,存放核心业务数据
- Redis 作为前置高速层,缓存热点数据副本
最经典的读取流程是:
- 请求先查 Redis
- 如果 Redis 里有,直接返回,这叫缓存命中
- 如果 Redis 里没有,再去查 MySQL,这叫缓存未命中
- MySQL 查到后,把结果回填到 Redis
- 后续请求再优先走 Redis
这套模式的核心价值在于:
- 降低 MySQL 压力
- 提高接口响应速度
- 提升高并发场景下的系统承载能力
但你也必须意识到,缓存并不是白来的。因为一旦你把 MySQL 的一份数据又在 Redis 里存了一份副本,就会出现一个新的核心问题:Redis 和 MySQL 的数据,什么时候可能不一致?这就是缓存带来的工程复杂度。
所以 Redis 做缓存,其实是在用副本换性能,但也要承担副本一致性的管理成本。
六、缓存穿透、缓存击穿、缓存雪崩
这一组问题很高频,主要是是在考你有没有“缓存不是永远可靠的”这种系统意识。
这三者本质上都和一个问题有关:缓存层失去了原本对数据库的保护作用。
但三者失效的方式不同。
缓存穿透
请求的数据本来就不存在,所以 Redis 里没有,MySQL 里也没有。这样的话,请求每次都会绕过缓存直接打到数据库。如果这种请求很多,就会给数据库带来无谓压力。它的关键点是:查的是根本不存在的数据。
常见解决思路是缓存空值、布隆过滤器、参数校验等。
缓存击穿
某一个非常热点的 key,在某一时刻突然失效了,于是大量并发请求同时去查 MySQL。这通常发生在一个热点 key 过期的瞬间。它的关键点是:一个特别热的 key 突然没了。
常见解决思路是热点 key 不过期、互斥锁或分布式锁控制缓存重建、逻辑过期等。
缓存雪崩
大量 key 在同一时间一起失效,或者 Redis 整体不可用了,于是大批请求同时冲向数据库。它的关键点是:不是一个点破了,而是一大片一起出问题。
常见解决思路包括过期时间加随机值、缓存预热、Redis 高可用、应用层限流降级等。
总结
一句话区分三者:穿透是查不到,击穿是一个热点突然失效,雪崩是一大批缓存同时出问题。这三道题背后真正考察的是:你是否知道缓存系统也会出故障,以及出故障后数据库会承受什么后果。
七、Redis 的持久化,到底是在平衡什么
很多人一开始会觉得 Redis 是内存数据库,那数据不是应该都在内存里吗,为什么还要持久化?其实一点都不矛盾。Redis 把数据放在内存里,是为了快;而 Redis 做持久化,是为了在快的基础上尽量减少数据丢失风险。因为内存有一个天然特点:它是易失性的。
Redis 进程一挂、机器一断电、系统一重启,内存里的数据就可能消失。所以 Redis 需要持久化,把内存中的数据以某种方式保存到磁盘上,以便重启后恢复。
Redis 的两种主流持久化方式是:RDB 和 AOF
RDB
可以理解成“快照式持久化”。 它会在某个时间点,把当前 Redis 内存里的整体数据状态保存成一个快照文件。所以它更像是“定期拍一张全景照片”。它的优点是文件紧凑、适合备份、恢复通常比较直接;缺点是如果刚拍完快照后 Redis 就挂了,那么这之后的数据可能会丢失。
AOF
可以理解成“操作日志式持久化”。 它不是保存某一刻的整体状态,而是把写操作按顺序记录下来。这样 Redis 重启时可以通过重新执行这些写命令来恢复数据。它更像“流水账”。它的优点通常是数据丢失窗口更小;缺点是文件可能越来越大,恢复时也可能要重放很多操作。
可以把两者理解成:
- RDB 像存档快照
- AOF 像操作日志
它们在性能、恢复速度、数据安全性之间做不同侧重点的平衡。很多工程场景里甚至会结合使用两者,而不是只用其中一个。
八、过期删除策略和内存淘汰策略
过期删除策略:
解决的问题是:已经设置过期时间的 key,到期了之后怎么处理。
Redis 支持给 key 设置 TTL,这是它很适合做缓存的重要原因之一。但 key 到期,不代表 Redis 一定会“秒删”。因为如果它要为每个 key 都维护一个精确到点就删除的定时任务,成本会很高。
所以 Redis 更现实的做法是组合处理:
- 惰性删除:访问某个 key 时,才顺手检查它是否过期,如果过期了就删除。
- 定期删除:Redis 后台会周期性抽查一部分设置了过期时间的 key,把已经过期的删掉。
这两者结合起来的意义在于:
- 惰性删除省 CPU
- 定期删除减少长期无人访问的过期 key 占用内存
内存淘汰策略:
解决的问题是:如果 Redis 内存真的不够用了,该牺牲谁。
注意,这时候有些 key 可能还没过期,但 Redis 还是装不下了。那么它就必须根据策略做选择:
- 是直接拒绝写入
- 还是删除一部分旧数据腾空间
- 如果删除,删哪些
常见的理解思路有几类:
- 不淘汰,直接报错
- 只从设置过期时间的 key 中淘汰
- 从所有 key 中淘汰
- 按最近最少使用、最不经常使用或随机方式挑选
怎么区分这两个概念:过期删除看的是时间规则,内存淘汰看的是空间压力。一个是“该失效的数据怎么清”,另一个是“内存不够时不得不删谁”。
九、Redis 分布式锁
Redis 分布式锁和缓存是两种完全不同的使用思路。缓存是在讲性能,而分布式锁是在讲:多个服务实例同时处理某件事时,如何避免它们互相冲突。
在单机程序里,我们可以用本地锁控制多个线程;但在分布式系统里,请求可能落到不同机器、不同实例上,本地锁就管不住了。所以这时候需要一个所有实例都能看到的共享状态,来协调谁能执行、谁要等待。
Redis 之所以适合做分布式锁,是因为它满足几个关键条件:
- 所有服务实例都能访问它
- 性能高
- 支持原子操作
- 支持设置过期时间
Redis 分布式锁最基本的思路是:
- 某个锁对应一个 key
- 只有 key 不存在时,才能设置成功
- 设置成功就表示拿到锁
- 同时还要设置过期时间,防止持锁者崩溃后锁永远不释放
但真正难的地方不在“加锁”,而在异常情况下怎么保证正确。
最经典的坑有两个:
-
误删别人的锁
如果服务 A 持有的锁超时过期了,服务 B 重新拿到了这把锁,这时 A 才执行完业务并去删除 key,就可能把 B 的锁误删掉。所以成熟实现不会只存一个简单值,而是会存一个唯一标识。释放锁时必须确认“现在这把锁还是不是我的”。
-
锁过期了,但业务还没执行完
如果 TTL 太短,而业务执行时间太长,那么锁可能提前过期,其他请求就会再次拿到锁,导致同一段逻辑被并发执行。所以工程上常会考虑合理 TTL 或锁续期机制。
因此,Redis 分布式锁的真正理解应该是:它不是简单 set 一个 key,而是一套需要同时考虑加锁原子性、锁归属、自动过期、释放安全和异常场景的互斥机制。
十、Redis 的高可用:主从复制、哨兵、集群
单机 Redis 的问题主要有:
- 单点故障
- 容量有限
- 读压力有限
- 一旦维护或重启风险很高
所以 Redis 在线上系统中,需要从“一个点”升级为“一套更抗风险的系统”。
主从复制
它的核心是让主节点把数据同步给一个或多个从节点。这样做的价值是:
- 数据有副本,降低单点风险
- 可以由从节点分担读请求
所以主从复制偏向解决的是:副本备份和读扩展。但主从复制还不够,因为如果主节点挂了,谁来发现?谁来决定新的主节点是谁?谁来让客户端切换?答案是:哨兵
哨兵
哨兵 本身不是存数据的,它更像监控者和管理者。
它负责:
- 监控主从节点状态
- 判断主节点是否故障
- 在主节点故障后完成自动故障转移
所以哨兵解决的是:主节点挂了之后,谁来组织自动切换。它是建立在主从复制之上的管理机制,不是平行替代关系。
再往后,如果系统继续变大,问题就不只是“主节点挂了怎么办”,而是:
- 一台机器内存装不下了
- 一个主节点写压力太大了
这时候就要考虑:集群。
集群
集群的核心思想是数据分片。也就是把不同数据分散到多个 Redis 节点上存储和处理,而不是所有数据都压在一个主节点上。这样就能实现:
- 容量扩展
- 性能扩展
- 避免单机瓶颈
总结:
- 主从复制:复制副本
- 哨兵:管理和切换
- 集群:分片和扩展
十一、完整主线
到这里,我们可以把 Redis 这一整部分重新用一条主线串起来。
在真实后端系统里,MySQL 很重要,但它不是专门用来处理所有高频、低延迟、热点数据访问的。于是 Redis 作为一个高性能内存系统,被放到 MySQL 前面或旁边,用来承担缓存、计数、排行、锁、临时状态存储等工作。
Redis 之所以能承担这些工作,是因为它快。而这个“快”来自于它把数据放在内存中、采用了简单直接的 key-value 操作模型、提供了高效的数据结构,并通过较轻的执行路径减少了额外开销。
当 Redis 进入实际业务后,它最典型的角色是缓存。它和 MySQL 配合,形成“先查 Redis、再查 MySQL、查到后回填 Redis”的经典模式。这种模式能明显降低数据库压力,但同时也引入了缓存穿透、击穿、雪崩,以及缓存与数据库一致性等问题。
再往后,为了让 Redis 不只是快,还能更稳,系统会考虑持久化,让内存数据尽量能在宕机后恢复;会考虑过期删除和内存淘汰,让有限的内存资源能被更合理地管理;还会利用 Redis 做分布式锁,解决分布式系统中的互斥问题。
最后,当 Redis 不再只是一个小组件,而是一个线上核心基础设施时,还需要进一步考虑高可用和扩展能力,于是就有了主从复制、哨兵和集群。
所以,Redis 这一整部分不是几道零散题,而是一条非常完整的系统设计链路:先解决快,再解决稳,再解决大。
十二、总结
Redis 在后端系统里,最核心的价值是为系统提供一层高性能的内存能力。它通过把热点数据和高频操作从磁盘型数据库中分流出来,大幅提升了系统的响应速度和并发承载能力。
同时,由于它支持多种数据结构,所以它不只是一个缓存组件,也常常承担计数、排行、去重、分布式锁等角色。但 Redis 并不是一个“越用越好”的万能工具,因为它的快来自内存,而内存是昂贵且有限的;它的缓存能力能换来性能提升,但也会引入一致性问题;它能做锁和高可用,但这些能力都有工程边界和设计成本。
所以真正学懂 Redis,是要知道:Redis 是在现代后端系统中,用来平衡速度、资源、可靠性和复杂度的一个关键组件。