将原本复杂操作的请求,引导到简单的操作上。以后再来查,不需要经过复杂的计算。
引入缓存就是用空间换时间的行为。
查询过程
- 接受到用户的查询请求,计算出 K(查询依据)
- 到缓存中进行查询
- 得到对应的 V(用户需要的数据)
如果没有在缓存中查询对应的数据,即为无法命中,记得从原数据库中查询到数据并返回给用户,并把此数据记录到缓存中。
1 |
|
如何提升缓存的收益
从前面的分析来看,减少 123 步骤的时间 和 提高缓存命中率。
并且从公式看出缓存适用于读多写少的场景,而写操作最终也是为读操作服务。还有查询原数据时间特别长的场景。
Key的设计要求
- 无碰撞:保证 Key 的唯一性,否则相同的 Key 但是对应不同的业务会导致之前的业务数据被替换
- 高效生成:不需要,提前约定好 Key 的生成规则,比方说
user:login:username:实际用户名
,这样只需要根据用户传递的用户名填充上去,然后整体作为 Key 即可 - 高效比较:Key 尽量简短,通过字符串比较
缓存的更新机制
对于大部分 读多写少 的数据,使用 被动更新,减少缓存维护成本。对于一致性要求高的数据(如 订单状态、用户余额),采用 主动更新。
还可以结合 缓存淘汰策略(如 LRU)、异步刷新 等优化方案,提高性能。
被动更新
只有当数据 被访问 时,才检查缓存是否存在,若不存在(缓存未命中或过期),则从数据库或其他数据源加载数据,并更新缓存。
适用于 读多写少 的场景,例如用户个人资料、商品信息等。
主动更新
在数据源(数据库)发生变更时,主动 更新缓存,而不是等到缓存失效后再查询数据库。
适用于 写多读多 的场景,例如排行榜、热搜榜、热门商品等。
常见的实现方式就是:数据库更新后,删除对应缓存,下次请求时重新加载最新数据。避免旧数据留在缓存中,但仍然允许短时间的数据不一致。
缓存的位置
客户端缓存
位置:数据存储在客户端设备上,比如浏览器缓存。
适用场景:
- 静态资源缓存(HTML、CSS、JS、图片等)
- 用户个性化数据(如用户设置、最近访问记录)
- 移动端离线模式(如 PWA 离线缓存)
1 |
|
应用层缓存
位置:存储在应用服务器的内存中,如自己设计的LRU缓存数据结构。
适用场景:
- 计算结果缓存(避免重复计算,减少 CPU 开销)
- 短生命周期数据(如临时会话数据)
- 数据库查询缓存(减少数据库压力)
1 |
|
分布式缓存
位置:缓存存储在专门的缓存服务器,如Redis。
适用场景:
- 高并发、高吞吐量(如秒杀、推荐系统)
- 数据库前置缓存(减少数据库查询压力)
- 会话管理(如分布式 Session 共享)
1 |
|
代理层缓存
位置:缓存部署在 CDN 或 Nginx、Varnish 这样的代理服务器上,通常用于加速静态资源访问。
适用场景:
- 静态资源缓存(HTML、CSS、JS、图片)
- 视频流媒体加速
- API 响应缓存(避免服务器重复计算)
1 |
|
数据库层缓存
位置:缓存存储在数据库内,例如 MySQL Query Cache,减少 SQL 查询执行时间。
适用场景:
- SQL 结果集缓存(避免重复查询)
- 预计算数据存储(如物化视图)
- 数据库索引缓存(加速查询)
1 |
|
总结
业务优先级高,数据访问频繁?➡ Redis 作为分布式缓存。
静态资源加载慢?➡ CDN、Nginx 代理缓存。
计算量大,数据短暂有效?➡ 进程内缓存(LRU Cache)。
需要存储计算结果?➡ 数据库缓存(索引)。
减少数据库压力?➡ 结合数据库 + Redis 分层缓存。