3. 缓存策略入门:本地缓存与分布式缓存对比

缓存是提升数据库读取性能、降低后端负载的核心手段。根据数据存储位置与共享范围,缓存分为本地缓存(进程内缓存)与分布式缓存(独立缓存服务)。本节从架构、性能、一致性、适用场景四个维度进行系统性对比。

3.1 本地缓存:Guava Cache 与 Caffeine

本地缓存运行在应用进程内,数据直接存储在 JVM 堆内存中,具有零网络开销、极低延迟的特点。Java 生态中最常用的实现是 Guava Cache 和 Caffeine。

特性 Guava Cache Caffeine
首次发布 2012 2018
淘汰算法 LRU(最近最少使用) W-TinyLFU(窗口化最小频率使用)
并发性能 分段锁 无锁读 + 细粒度写锁
命中率 基准 高并发下命中率提升 15%–25%
内存开销 较高(额外对象头) 更低(引用链优化)
异步加载 不支持 支持 AsyncLoadingCache
推荐场景 低并发、简单缓存 高并发、低延迟、生产级
生产建议:新项目优先选择 Caffeine。其 W-TinyLFU 算法能有效抵抗“突发热点”导致的缓存污染,在秒杀、Feed 流等场景下命中率显著优于 Guava Cache。

3.1.1 Caffeine 核心配置示例

Cache<String, UserProfile> userCache = Caffeine.newBuilder()
    .maximumSize(10_000)               // 最大条目数
    .expireAfterWrite(5, TimeUnit.MINUTES) // 写入后过期
    .expireAfterAccess(1, TimeUnit.MINUTES)// 访问后过期
    .recordStats()                      // 开启命中率统计
    .build();

// 手动加载
UserProfile profile = userCache.get("user:1001", key -> {
    return userDao.findById(1001);      // 缓存未命中时回调
});
避坑:本地缓存无法跨进程共享。当应用部署多实例时,每个节点持有独立副本,可能出现数据不一致。务必为每个缓存键设计合理的 TTL,避免“僵尸数据”长期驻留。

3.2 分布式缓存:Redis 与 Memcached

分布式缓存作为独立中间件部署,所有应用节点共享同一缓存池,天然解决数据一致性问题。Redis 和 Memcached 是两大主流方案。

对比维度 Redis Memcached
数据结构 String、Hash、List、Set、ZSet、Stream 等 仅 Key-Value(String)
持久化 RDB / AOF 支持 不支持(纯内存)
高可用 主从 + Sentinel / Cluster 客户端分片,无原生高可用
内存淘汰 8 种策略(LRU、LFU、TTL 等) LRU 为主
网络模型 单线程 Reactor(6.0+ 支持多线程 I/O) 多线程(每个核一个线程)
典型延迟 0.1–1ms(内网) 0.1–0.5ms(内网)
适用场景 复杂数据结构、排行榜、分布式锁、消息队列 简单 KV 缓存、Session 共享
选型原则:如果只需要“存/取”字符串且对持久化无要求,Memcached 在纯读场景下延迟略低;一旦涉及计数器、排行榜、分布式锁或需要数据恢复,Redis 是唯一选择。

3.3 本地缓存 vs 分布式缓存:架构对比图

下图展示了两种缓存模式在微服务架构中的部署位置与数据流向。

本地缓存与分布式缓存架构对比 本地缓存 vs 分布式缓存架构对比 本地缓存模式(进程内) App 实例 A Caffeine 缓存 (JVM 堆内) App 实例 B Caffeine 缓存 (JVM 堆内) MySQL 数据库 ⚠ 数据不一致:A 更新后 B 不可见 需自行实现缓存失效广播 分布式缓存模式(独立服务) App 实例 C 无本地缓存 App 实例 D 无本地缓存 Redis Cluster 共享缓存池 MySQL 数据库 ✓ 数据全局一致 ✓ 支持持久化与高可用

3.4 多级缓存策略:本地 + 分布式组合

生产环境中,单一缓存模式往往无法兼顾性能与一致性。推荐采用多级缓存架构:本地缓存扛热点,分布式缓存做共享与兜底。

3.4.1 多级缓存读取流程

  1. L1 本地缓存:优先查询 Caffeine,命中则直接返回(延迟 < 0.1ms)。
  2. L2 分布式缓存:本地未命中,查询 Redis,命中后回填本地缓存。
  3. L3 数据库:Redis 也未命中,查询 MySQL,回填 Redis 与本地缓存。
性能收益:在典型读多写少场景下,多级缓存可将 90% 以上的请求拦截在 L1 层,数据库 QPS 降低 80%–95%。但需注意本地缓存 TTL 不宜过长(建议 1–5 秒),避免数据长期不一致。

3.5 缓存选型决策矩阵

决策条件 推荐方案 理由
单机部署、低并发 Guava Cache 简单够用,无额外依赖
单机部署、高并发 Caffeine W-TinyLFU 算法抗热点,命中率高
多实例、数据一致性要求高 Redis 共享缓存池,天然一致
多实例、纯 KV 且可接受最终一致 Memcached 多线程模型,简单场景延迟更低
高并发 + 数据一致性折中 Caffeine + Redis 多级缓存 本地扛热点,Redis 做兜底与同步
关键提醒:任何缓存方案都无法替代数据库的 ACID 特性。缓存是性能加速器,不是数据保险箱。写入操作必须保证数据库为先(Cache-Aside 模式),避免缓存与数据库双写不一致。