2. 缓存基础:本地缓存与分布式缓存的区别、常见缓存中间件(Redis、Caffeine)选型

在微服务架构中,缓存是提升系统吞吐量与降低响应延迟的核心手段。然而,Development环境(开发环境)与生产环境在流量规模、数据一致性要求、运维复杂度上存在显著差异。本章将系统梳理本地缓存与分布式缓存的本质区别,并针对 Redis 与 Caffeine 两款主流中间件给出选型建议,为后续搭建缓存一致性闭环奠定基础。

2.1 本地缓存 vs 分布式缓存:核心差异

缓存按存储位置与共享范围可分为本地缓存与分布式缓存。下表从多个维度对比两者的关键差异:

对比维度 本地缓存(Local Cache) 分布式缓存(Distributed Cache)
存储位置 进程内堆内存(JVM Heap) 独立缓存服务(如 Redis 集群)
数据共享 仅限单进程内可见 多进程/多节点全局共享
访问延迟 纳秒级(0.1~1 μs) 毫秒级(0.5~5 ms,含网络开销)
容量上限 受限于堆内存大小(通常 GB 级) 可水平扩展至 TB 级
数据一致性 天然一致(单进程无并发冲突) 需额外机制保证(如分布式锁、版本号)
持久化 通常不持久化,进程重启即丢失 支持 RDB/AOF 等持久化策略
运维复杂度 零运维,随应用启动 需独立部署、监控、扩缩容
典型场景 热点数据、配置信息、无状态计算 会话共享、全局计数器、跨服务数据

Development 环境选型原则:开发阶段应优先使用本地缓存降低外部依赖,仅在需要验证分布式一致性或跨服务数据共享时引入分布式缓存。避免在开发环境过度依赖 Redis 集群,以减少环境搭建与调试成本。

2.2 常见缓存中间件选型:Redis vs Caffeine

在 Java 技术栈中,Caffeine 是本地缓存的标杆实现,Redis 则是分布式缓存的事实标准。以下从性能、功能、开发友好度三个维度进行对比:

选型维度 Caffeine Redis
定位 进程内高性能缓存库 独立部署的键值存储系统
读写性能 极高(基于 ConcurrentHashMap + 淘汰算法优化) 高(单线程事件循环,纯内存操作)
淘汰策略 W-TinyLFU(近最优命中率) LRU、LFU、TTL、随机淘汰
数据结构 仅支持 Key-Value String、Hash、List、Set、Sorted Set、Bitmap、HyperLogLog、Stream
持久化 不支持 RDB 快照 + AOF 日志
分布式能力 无 主从复制、哨兵、集群分片
开发集成 Spring Cache 原生支持,零配置 需配置连接池、序列化、集群地址
适用阶段 开发、单元测试、单机部署 集成测试、预发、生产环境

选型建议:在 Development 环境中,推荐采用 Caffeine + Redis 双缓存策略——Caffeine 作为一级缓存(L1)处理高频热点读请求,Redis 作为二级缓存(L2)提供跨服务数据共享与一致性锚点。开发阶段可先仅启用 Caffeine,待需要验证分布式场景时再接入 Redis。

2.3 缓存架构选型决策流程

下图展示了在 Development 环境下,从需求分析到中间件选型的完整决策路径:

Development 环境缓存选型决策流程 缓存需求分析 是否需要跨进程/跨服务共享? (会话、全局计数器、数据一致性要求) 否 是 选用 Caffeine 选用 Redis 配置最大容量、过期策略 集成 Spring Cache @Cacheable 配置连接池、序列化方式 搭建单机/哨兵/集群模式 是否需要双缓存(L1 + L2)? 输出:缓存架构选型方案

2.4 双缓存策略在 Development 环境中的落地

在开发阶段,推荐采用 Caffeine(L1)+ Redis(L2) 的双层缓存架构。其核心交互流程如下:

  1. 读请求:优先查询 Caffeine,命中则直接返回;未命中则查询 Redis,若 Redis 命中则回填 Caffeine 并返回;若均未命中则查询数据库,结果依次回填 Redis 和 Caffeine。
  2. 写请求:先更新数据库,再删除 Redis 中的对应缓存(延迟双删策略),最后清除本地 Caffeine 缓存,保证最终一致性。
  3. 缓存失效:Caffeine 设置较短 TTL(如 30~60 秒),Redis 设置较长 TTL(如 5~10 分钟),避免本地缓存长期不一致。

Development 环境避坑提示:

  • 避免在开发环境使用 Redis 集群模式,单机模式足以验证功能,减少网络分区与故障演练的干扰。
  • Caffeine 的最大容量不宜设置过大(建议 1000~5000 条),防止堆内存占用过高导致频繁 GC。
  • 双缓存场景下务必实现缓存穿透保护(布隆过滤器或空值缓存),防止恶意 Key 打穿到数据库。

2.5 代码示例:Spring Boot 集成 Caffeine + Redis 双缓存

以下配置展示了在 Development 环境中快速启用双缓存的关键代码:

// 1. 引入依赖(pom.xml)
// Caffeine
implementation 'com.github.ben-manes.caffeine:caffeine:3.1.8'
// Redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis'

// 2. 缓存配置类
@Configuration
@EnableCaching
public class CacheConfig {

    @Bean
    public CacheManager cacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        cacheManager.setCaffeine(Caffeine.newBuilder()
                .maximumSize(2000)
                .expireAfterWrite(30, TimeUnit.SECONDS)
                .recordStats());
        return cacheManager;
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        return template;
    }
}

// 3. 服务层使用示例
@Service
public class UserService {

    @Autowired
    private CacheManager cacheManager;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Cacheable(value = "userCache", key = "#userId")
    public User getUserById(Long userId) {
        // 先查 Redis
        String redisKey = "user:" + userId;
        User user = (User) redisTemplate.opsForValue().get(redisKey);
        if (user != null) {
            return user;
        }
        // 查数据库
        user = userMapper.selectById(userId);
        if (user != null) {
            redisTemplate.opsForValue().set(redisKey, user, 5, TimeUnit.MINUTES);
        }
        return user;
    }
}

关键点说明:

  • @Cacheable 注解默认使用 Caffeine 缓存,Redis 作为手动回填的二级缓存。
  • 开发阶段建议关闭 Redis 连接超时重试(设置 timeout=2s),避免 Redis 不可用时阻塞主流程。
  • 使用 recordStats() 可在开发时通过 Actuator 端点监控缓存命中率。

2.6 缓存选型总结矩阵

下表汇总了 Development 环境下不同场景的推荐选型:

场景特征 推荐方案 理由
单服务、无状态、高频读 Caffeine 单层 零网络开销,开发调试简单
多服务共享会话/配置 Redis 单层 全局一致性,无需本地同步
热点数据 + 跨服务一致性 Caffeine + Redis 双层 兼顾性能与一致性,开发环境可先只启用 Caffeine
验证分布式锁/计数器 Redis 单层 利用 Redis 原子操作与 Lua 脚本
单元测试/快速原型 Caffeine 单层 无需外部中间件,启动即用