Redis读写分离需主从复制并显式配置读取策略,否则触发READONLY错误;多级缓存须统一入口、错开TTL、重试写入并按数据维度分层。

Redis 读写分离必须配主从复制,否则 READONLY 错误会直接中断请求
Spring Boot 应用里配置了 spring.redis.sentinel.master 或 spring.redis.cluster.nodes,不代表自动开启读写分离。Redis 官方驱动(Lettuce/Jedis)默认所有命令都发往主节点,除非你显式启用从节点读取能力。
常见错误现象:READONLY You can't write against a read only replica —— 这不是权限问题,而是你把写操作误发到了只读从节点;或者反过来,读请求被强制打到主节点,失去分流意义。
- 使用 Lettuce 时,需在
LettuceClientConfigurationBuilderCustomizer中设置readFrom(ReadFrom.REPLICA_PREFERRED) - 若用 Jedis,必须手动构造
JedisSentinelPool并传入new JedisPoolConfig()+ReadMode.SLAVE(注意:Jedis 4.x 才支持) - 主从延迟不可忽略:电商商品库存类数据不建议走从节点读,但用户资料、类目树这类低频变更数据可安全启用
Caffeine 本地缓存不能简单套 @Cacheable,否则会绕过 Redis 同步更新逻辑
Spring 的 @Cacheable(cacheNames = "local") 和 @Cacheable(cacheNames = "redis") 是两个完全隔离的缓存命名空间。如果只在方法上叠加双注解,本地缓存命中后根本不会触发 Redis 查询,导致 L1/L2 数据错位。
正确做法是统一入口控制缓存层级,例如封装一个 MultiLevelCacheService.get(key, loader) 方法:
- 先查
CaffeineCache.getIfPresent(key),命中则返回 - 未命中则调用
redisTemplate.opsForValue().get(key),命中后调用caffeineCache.put(key, value)回写 - Redis 也未命中,才执行 loader(如 DB 查询),并按顺序写入 Redis → Caffeine
特别注意:Caffeine 的 refreshAfterWrite 和 Redis 的 TTL 必须错开,比如 Caffeine 设为 10s,Redis 设为 60s,避免两者同时过期引发雪崩。
本地缓存失效时,Redis 写失败会导致 L1/L2 永久不一致
典型场景:Caffeine 缓存过期,请求穿透到 Redis 层,但此时 Redis 网络抖动或连接池耗尽,redisTemplate.opsForValue().set(key, value, timeout) 抛出 RedisConnectionFailureException。如果代码没做兜底,这个 key 就再也不会进 Redis,后续所有实例的本地缓存都会持续 miss,最终压垮数据库。
- 必须对 Redis 写操作加重试(建议最多 2 次)+ 降级开关(如通过
FeatureToggle控制是否跳过 Redis 写入) - 推荐在写 Redis 失败时,记录一条告警日志,包含
key、exception.message、stackTrace,方便定位是网络问题还是序列化异常 - 不要依赖“下次请求自然回填”——高并发下,多个请求可能同时穿透,造成 DB 多次查询和重复写入
多级缓存不是越深越好,L0(CDN)和 L1(Caffeine)之间存在语义冲突风险
CDN 缓存静态资源(如商品图、详情页 HTML 片段)没问题,但若把用户登录态、购物车数量这类个性化数据也塞进 CDN,会直接导致不同用户看到彼此数据。这不是技术做不到,而是业务语义不允许。
真正需要分层的是数据维度本身:
- 全局不变数据(如省市区字典)→ 放 Caffeine + 长 TTL Redis(86400s)
- 用户私有数据(如订单列表)→ 只放 Redis,禁用 Caffeine(避免内存爆炸)
- 半公共数据(如首页 Banner)→ Caffeine + 短 TTL Redis(300s)+ 主动刷新机制
最易被忽略的一点:Caffeine 的最大容量设为 10000,不代表它真能存下 10000 个对象——如果每个对象含大量嵌套字段或未实现 hashCode/equals,可能导致内存泄漏或淘汰策略失效。上线前务必用 caffeine.stats() 监控 hitRate 和 evictionCount。


















