缓存设计

将原本复杂操作的请求,引导到简单的操作上。以后再来查,不需要经过复杂的计算。

引入缓存就是用空间换时间的行为。

查询过程

  1. 接受到用户的查询请求,计算出 K(查询依据)
  2. 到缓存中进行查询
  3. 得到对应的 V(用户需要的数据)

如果没有在缓存中查询对应的数据,即为无法命中,记得从原数据库中查询到数据并返回给用户,并把此数据记录到缓存中。

1
2
3
数据查询时间:123步骤 + (1-命中率)*查原数据时间

命中率:缓存中的数据/数据库中的原数据

如何提升缓存的收益

从前面的分析来看,减少 123 步骤的时间 和 提高缓存命中率。

并且从公式看出缓存适用于读多写少的场景,而写操作最终也是为读操作服务。还有查询原数据时间特别长的场景。

Key的设计要求

  • 无碰撞:保证 Key 的唯一性,否则相同的 Key 但是对应不同的业务会导致之前的业务数据被替换
  • 高效生成:不需要,提前约定好 Key 的生成规则,比方说 user:login:username:实际用户名,这样只需要根据用户传递的用户名填充上去,然后整体作为 Key 即可
  • 高效比较:Key 尽量简短,通过字符串比较

缓存的更新机制

对于大部分 读多写少 的数据,使用 被动更新,减少缓存维护成本。对于一致性要求高的数据(如 订单状态用户余额),采用 主动更新

还可以结合 缓存淘汰策略(如 LRU)、异步刷新 等优化方案,提高性能。

被动更新

只有当数据 被访问 时,才检查缓存是否存在,若不存在(缓存未命中或过期),则从数据库或其他数据源加载数据,并更新缓存。

适用于 读多写少 的场景,例如用户个人资料、商品信息等。

主动更新

在数据源(数据库)发生变更时,主动 更新缓存,而不是等到缓存失效后再查询数据库。

适用于 写多读多 的场景,例如排行榜、热搜榜、热门商品等。

常见的实现方式就是:数据库更新后,删除对应缓存,下次请求时重新加载最新数据。避免旧数据留在缓存中,但仍然允许短时间的数据不一致。

缓存的位置

客户端缓存

位置:数据存储在客户端设备上,比如浏览器缓存。

适用场景

  • 静态资源缓存(HTML、CSS、JS、图片等)
  • 用户个性化数据(如用户设置、最近访问记录)
  • 移动端离线模式(如 PWA 离线缓存)
1
2
3
4
5
6
7
8
9
优点
✅ 减少服务器请求,降低带宽消耗,提高加载速度
✅ 本地存取,延迟极低,性能最佳
✅ 支持离线模式,即使无网络也能使用部分功能

缺点
❌ 存储空间有限(浏览器 LocalStorage 最大 5MB)
❌ 安全性较低(数据可能被篡改或窃取)
❌ 更新困难(需要额外的缓存策略管理,例如 ETag、Cache-Control)

应用层缓存

位置:存储在应用服务器的内存中,如自己设计的LRU缓存数据结构。

适用场景

  • 计算结果缓存(避免重复计算,减少 CPU 开销)
  • 短生命周期数据(如临时会话数据)
  • 数据库查询缓存(减少数据库压力)
1
2
3
4
5
6
7
8
9
优点
✅ 访问速度最快(数据直接存储在进程内存中,无需网络传输)
✅ 实现简单(适用于单机应用,无需额外的分布式缓存服务)
✅ 避免高频数据库查询,提高应用性能

缺点
❌ 受限于服务器内存(无法存储大规模数据)
❌ 进程重启后数据丢失(非持久化存储)
❌ 不适用于分布式系统(多个实例无法共享缓存)

分布式缓存

位置:缓存存储在专门的缓存服务器,如Redis。

适用场景

  • 高并发、高吞吐量(如秒杀、推荐系统)
  • 数据库前置缓存(减少数据库查询压力)
  • 会话管理(如分布式 Session 共享)
1
2
3
4
5
6
7
8
优点
✅ 支持分布式部署,适用于大规模集群
✅ 高性能读写,特别适合高并发场景
✅ 支持数据持久化(Redis 支持 RDB、AOF)

缺点
❌ 额外运维成本(需要独立的 Redis/Memcached 服务器)
❌ 数据一致性管理复杂(缓存与数据库同步更新问题)

代理层缓存

位置:缓存部署在 CDNNginx、Varnish 这样的代理服务器上,通常用于加速静态资源访问。

适用场景

  • 静态资源缓存(HTML、CSS、JS、图片)
  • 视频流媒体加速
  • API 响应缓存(避免服务器重复计算)
1
2
3
4
5
6
7
8
优点
✅ 减少服务器压力(用户请求先到 CDN,降低源站负载)
✅ 就近访问,减少网络延迟,提高访问速度
✅ 适用于大规模分发(如视频网站、电子商务)

缺点
❌ 适用于静态内容,动态数据管理复杂
❌ 缓存更新延迟(需配置过期时间或主动刷新)

数据库层缓存

位置:缓存存储在数据库内,例如 MySQL Query Cache,减少 SQL 查询执行时间。

适用场景

  • SQL 结果集缓存(避免重复查询)
  • 预计算数据存储(如物化视图)
  • 数据库索引缓存(加速查询)
1
2
3
4
5
6
7
优点
✅ 直接在数据库层优化,无需修改应用代码
✅ 适用于复杂 SQL 计算结果缓存,提高查询效率

缺点
❌ 更新不灵活,某些数据库(如 MySQL 8.0)已移除 Query Cache,因其维护成本高
❌ 数据库负担增加,缓存查询仍然占用数据库资源

总结

业务优先级高,数据访问频繁?➡ Redis 作为分布式缓存。

静态资源加载慢?➡ CDN、Nginx 代理缓存

计算量大,数据短暂有效?➡ 进程内缓存(LRU Cache)。

需要存储计算结果?➡ 数据库缓存(索引)

减少数据库压力?➡ 结合数据库 + Redis 分层缓存