1. 缓存基础概念:什么是缓存、为什么需要缓存、缓存的工作原理、缓存与数据库的关系

1.1 什么是缓存?说白了就是「快照」

缓存这个概念,其实你每天都在用。CPU 有 L1/L2/L3 缓存,浏览器有本地缓存,DNS 有解析缓存。到了后端服务层面,缓存就是把数据放在一个读写更快的存储介质里,下次再用的时候直接取,不用重新算一遍。

我个人习惯把缓存理解成「快照」。你想想看,数据库里存的是全量数据,但大部分请求只关心最近、最热的那一小部分。缓存就是把这些热数据拍个快照,放在离应用程序更近的地方。

核心定义:缓存是一种用空间换时间的策略。用额外的存储空间,换取更快的读取速度。

1.2 为什么需要缓存?

我在项目中遇到过好几次这样的场景:数据库 CPU 飙到 90%,慢查询堆积,接口响应时间从 10ms 变成 2s。一查,全是重复查询同一个热点数据。加了一层缓存之后,数据库负载直接降到 20%。

具体来说,缓存解决了三个核心问题:

  • 性能瓶颈:数据库的磁盘 I/O 再快,也快不过内存。缓存把数据放在内存里,读取速度能差两个数量级。
  • 高并发压力:一个数据库实例能扛的并发连接数有限。缓存层可以挡住 90% 以上的读请求,让数据库专心处理写操作。
  • 响应延迟:用户等不了 500ms 的接口响应。缓存能把延迟降到 1ms 以内,用户体验完全不一样。
对比维度 数据库(MySQL) 缓存(Redis)
读写速度 毫秒级(磁盘 I/O) 微秒级(内存操作)
并发能力 几百~几千 几万~十万
存储成本 低(磁盘便宜) 高(内存贵)
数据持久性 强(ACID 事务) 弱(宕机丢数据)

1.3 缓存的工作原理

缓存的工作流程其实很简单,就三步:

  1. 查缓存:请求来了,先去缓存里找数据。
  2. 缓存命中:找到了,直接返回,完事。
  3. 缓存未命中:没找到,去数据库查,然后把结果写回缓存,再返回。

嗯,这里要注意一个关键点:缓存未命中时的回源操作。如果并发请求同时发现缓存里没数据,全部打到数据库上,这就是缓存穿透的雏形。后面我们会专门讲怎么防。

我的经验:缓存未命中时,一定要加「互斥锁」或者「分布式锁」,保证只有一个请求去查数据库,其他请求等待。否则高并发下数据库瞬间就挂了。

下面这张图展示了缓存读写的完整流程:

缓存读写流程 客户端请求 缓存层(Redis) 数据库(MySQL) ① 查缓存 ② 命中直接返回 ③ 未命中,回源 ④ 写回缓存 ⑤ 返回数据给客户端 关键说明: • 步骤②是「缓存命中」,性能最好,延迟通常在 1ms 以内。 • 步骤③④⑤是「缓存未命中」,需要回源数据库,延迟可能到 50ms+。 • 高并发下,步骤③必须加锁,否则多个请求同时回源,数据库扛不住。

1.4 缓存与数据库的关系

很多人觉得缓存和数据库是「替代关系」,其实不是。它们是互补关系。数据库负责数据的完整性和持久性,缓存负责数据的读取速度和并发能力。

我曾经接手过一个项目,团队把所有数据都放在 Redis 里,连订单数据都不落库。结果 Redis 宕机了一次,丢了 3 个小时的订单数据。嗯,从那以后我深刻理解了:缓存不是数据库的替代品,而是数据库的加速器。

避坑指南:千万不要把缓存当成「万能存储」。缓存的数据可以丢,但数据库的数据不能丢。缓存只存「可重建」的数据,比如从数据库查出来的结果、计算后的中间值。原始数据一定要落库。

它们的关系可以用一句话总结:

  • 读多写少的场景,缓存挡在前面,数据库做兜底。
  • 写多读少的场景,缓存做异步写入的缓冲层,数据库做最终持久化。
  • 数据一致性要求高的场景,缓存只做「读加速」,写操作直接走数据库。

下面这张表总结了常见的缓存策略:

策略 读流程 写流程 适用场景
Cache-Aside 先查缓存,未命中查 DB 再回写 先写 DB,再删除缓存 通用场景,最常用
Read-Through 缓存层自动回源 DB 直接写 DB 需要缓存层封装逻辑
Write-Through 同 Read-Through 先写缓存,缓存同步写 DB 强一致性要求
Write-Behind 同 Read-Through 先写缓存,异步批量写 DB 写性能要求高,可接受延迟
我的建议:刚开始做缓存设计,直接用 Cache-Aside 模式最稳妥。它逻辑清晰,容易排查问题。等你对业务和数据一致性要求有了更深的理解,再考虑其他模式。

最后说一句:缓存不是银弹。加缓存之前,先问问自己——这个数据真的需要缓存吗?如果每秒只有几十次查询,数据库完全扛得住,加缓存反而增加了系统复杂度和维护成本。我见过太多「为了缓存而缓存」的项目,最后缓存比数据库还难维护。