读写分离无法解决缓存击穿,因其本质是热点key过期瞬间的并发穿透,需在缓存层通过互斥锁或逻辑过期等机制拦截,而非依赖数据库读写分离。

读写分离根本挡不住缓存击穿
数据库读写分离解决的是“写压力分散”和“读节点横向扩容”问题,不是缓存层该干的活。缓存击穿本质是单个 key 过期瞬间被海量并发请求同时打穿,这些请求在毫秒级内全部落到主库或从库——而读写分离的从库本身没有缓存能力,也无法拒绝重复查询、无法加锁、无法提前预热。你让从库扛 1000 QPS 的 SELECT * FROM user WHERE id = 12345,它照样会慢、会堵、会连不上。
Redis 的互斥锁(setnx)为什么必须在缓存层实现
因为锁的粒度和生命周期必须绑定到 key 的缓存生命周期上。如果把锁下推到数据库层(比如用 SELECT FOR UPDATE),代价太高:每次未命中都要开启事务、加行锁、等锁释放,数据库连接池会迅速耗尽。而 Redis 的 SET key value EX 60 NX 是原子操作,失败直接返回,成功才允许查库回填——这个判断必须发生在缓存入口,不能绕过 Redis 去数据库里“再试一次”。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
-
NX保证只有一个请求能拿到锁,其余请求要么等待、要么走降级逻辑 - 锁的过期时间(
EX)必须短于业务预期加载时间,否则会造成死锁假象 - 若业务查库超时,必须主动删除该锁,否则后续请求会被永久阻塞
逻辑过期方案依赖 Redis 的原子读写能力
逻辑过期(即缓存值里自带一个 expireTime 字段,不依赖 Redis 的 TTL)之所以可行,是因为它把“是否需要重建缓存”的判断逻辑完全留在 Redis 内部:GET 出来后解析字段,发现已逻辑过期,再用 SETNX 尝试占位,成功者异步刷新,失败者直接返回旧值。这个流程全程不触碰数据库,更不依赖读写分离的任何组件。一旦把这个逻辑挪到应用层去做(比如 Java 里用 ConcurrentHashMap 存逻辑过期时间),就失去了分布式一致性——多实例之间无法共享状态,击穿照样发生。
读写分离 + Redis 是协作关系,不是替代关系
真正健壮的架构里,读写分离负责扛住“可预测的读流量”,Redis 负责拦截“不可预测的热点穿透”。比如双11期间,商品详情页的 item:10086 每秒 5w 请求,其中 99% 由 Redis 直接响应;剩下 1% 因 key 过期触发击穿,靠 Redis 锁控流 + 异步回源;而数据库读写分离只是默默承载那 1% 中最终落到 DB 的那几百次查询。漏掉 Redis 这一层,等于把所有不确定性全甩给数据库——无论分多少从库,都只是在给雪崩铺路。










