Redis缓存击穿_使用本地锁还是分布式锁效果更好
缓存击穿时,本地锁为何失效?分布式锁如何选型?

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈
当缓存击穿发生时,一个常见的误区是试图用本地锁解决问题。实际上,本地锁在跨进程场景下根本不起作用。更有效的方案是采用基于Redis原子命令(如SET NX EX)或Redission的tryLock实现的分布式锁,并配合空值缓存、key收敛、过期时间随机偏移等策略进行综合治理。
缓存击穿发生时,本地锁根本不起作用
想象一下这个场景:多个请求同时发现某个热点key在Redis中不存在(比如一个爆款商品的详情页),它们都去查询数据库,并且在查完后准备回写缓存。如果此时仅仅依赖本地锁(比如Ja va里的synchronized或ReentrantLock),会发生什么?每个独立部署的应用实例都拥有自己的锁,它们之间互不感知。结果就是,三台机器上可能各有线程在自己的JVM里“成功”加锁,然后各自查询一次数据库,再各自回写一次缓存。数据库压力瞬间翻倍,缓存也被重复刷入。问题的根源在于,本地锁的有效范围仅限于单进程,而缓存击穿恰恰是一个典型的跨进程、跨节点并发问题。
分布式锁必须满足“互斥 + 自动释放”两个硬条件
选择分布式锁方案,关键不在于技术是否新颖,而在于它能否切实解决并发回源的问题。市面上常见的方案各有侧重:
- Redis原子命令:使用
SET key value EX seconds NX是最轻量且通常足够的选择。但这里有个细节必须注意:一定要使用这个原子命令,而不能将其拆分成先SETNX再EXPIRE两个操作。因为在两个命令执行的间隙如果进程崩溃,会导致锁无法自动释放,形成死锁。 - Redission客户端:使用这个成熟的客户端时,尽量避免直接调用不带超时参数的
lock()方法。更稳妥的做法是使用tryLock(waitTime, leaseTime, TimeUnit),明确指定等待获取锁的时间和锁的自动释放时间,以防网络抖动导致锁被永久持有。 - ZooKeeper:基于临时顺序节点的方案虽然能提供强一致性保证,但也意味着引入了额外的运维组件,并且延迟相对较高。对于纯粹的缓存防击穿场景,其性价比可能不如Redis方案。
更推荐“逻辑层兜底 + 简单分布式锁”组合
单纯依赖一把锁,往往只能治标。线上环境追求的是稳定可靠,因此更推荐组合拳策略:
- 获取锁与重试:首先尝试用
SET lock:key token EX 60 NX获取分布式锁。如果获取失败,说明已有其他线程在处理,当前线程可以主动sleep一个短暂时间(例如10到50毫秒)后重试,避免无意义的自旋消耗CPU。 - 锁的释放:成功拿到锁的线程执行数据库查询,并将结果写入缓存。完成后,应立即通过
DEL命令删除锁的key。虽然Redission有看门狗机制自动续期,但手动释放能让控制粒度更细。 - 空值缓存:这是一个关键兜底策略。当数据库查询结果本身为
null时,也应在缓存中写入一个特定的空值对象(例如字符串"null"),并设置一个较短的TTL(比如2分钟)。这能有效防止大量请求穿透到数据库。当然,业务层需要约定好如何识别和处理这个空值标记。 - 异步回写:如果业务对极短时间内的数据一致性要求不高,甚至可以采取更彻底的“异步回写”方案:线程查询数据库后直接返回结果给用户,同时发送一条消息到队列,由独立的消费者异步完成缓存写入,从而完全避开锁竞争。
锁粒度和 key 设计不当,比选哪种锁更容易翻车
技术选型正确只是第一步,锁的使用姿势同样重要。一个典型的反例是:将锁直接套在getProductDetail(long id)这样的方法外部,而方法参数id直接来自前端URL。攻击者如果批量请求/product/1到/product/100000,瞬间就会创建出十万个不同的锁key,导致Redis内存暴涨,系统QPS断崖式下跌。正确的做法是:
- Key收敛设计:锁的key必须具有收敛性。例如,统一使用
lock:product:{id}这样的格式,确保同一个商品id永远对应同一个锁key,而不是生成海量不同的key。 - 放弃锁,采用随机偏移:对于一些访问高频但对一致性要求不苛刻的数据(比如用户头像),可以放弃使用锁。取而代之的是采用“过期时间随机偏移”策略,在设置缓存过期时间时加上一个随机值,例如
EX 3600 + random(0, 600),让大量key的失效时间自然分散开,避免同时失效引发击穿。 - 合理配置 watchdog:如果使用Redission,务必确认
lockWatchdogTimeout(锁看门狗超时时间)配置合理。时间太短可能导致锁在业务执行中被误释放;时间太长则会影响故障场景下的恢复速度。
说到底,锁本身只是一个工具。真正决定系统能否扛住缓存击穿的,是你对并发边界的控制是否清晰、锁的key设计是否可预测、以及空值等边缘情况是否被妥善处理。这些地方哪怕只疏忽一点,换用任何高级的锁方案都无济于事。
相关攻略
Redis缓存雪崩后如何快速恢复:主从切换与数据降级策略应用 Redis缓存雪崩发生时,主从切换能自动扛住吗? 答案是否定的。这里需要厘清一个关键概念:主从切换(无论是通过Redis Sentinel还是Redis Cluster的故障转移机制)主要解决的是「节点宕机」这类硬件或进程故障问题。当缓存
Redis内存淘汰策略导致的延迟问题如何解决?升级Redis 6 0并启用异步删除 在Redis 6 0及以上版本中,通过设置 lazyfree-lazy-eviction yes 参数,可以将内存淘汰策略触发的大Key释放操作交由后台线程异步执行,从而避免主线程因同步释放内存而被阻塞,显著提升服务
哨兵节点至少需部署3个且分属不同物理机或可用区,quorum值须满足过半原则;配置中down-after-milliseconds建议设为10000ms并据网络RTT微调;客户端必须通过哨兵列表动态获取主库地址,禁用DNS IP缓存。 哨兵节点必须至少部署3个,且不能全在一台机器上 这里有个常见的理
Redis内存使用率突然飙升怎么办?先排查大对象 Redis内存使用率毫无征兆地飙升,这事儿在运维圈里太常见了。十有八九,背后是某个或多个“大块头”在作祟——这里说的“大”,可不是指Key的名字长,而是它存储的Value体积过大,或者集合里的元素数量惊人。想要快速定位,redis-cli --big
怎么利用 PreparedStatement setFetchSize() 优化从数据库读取大数据集的性能 setFetchSize() 不是“一次查多少条”,而是“一次从网络拿多少条” 先澄清一个常见的误解:很多人以为 setFetchSize() 是给数据库下达指令,让它只返回指定数量的行。其实
热门专题
热门推荐
你一直认为自己是个无与伦比的职工 不迟到、不早退、准时完成工作,对单位里的大小文具从不顺手牵羊——这当然是职业素养的基石。不过,衡量工作成绩的优劣,有时并不仅仅看个人表现,与周围环境的协调能力同样是重要的考察维度。一味地严于律己固然好,但若与同事龃龉过多,这些不经意间埋下的“暗礁”,很可能成为阻碍你
Pharos Network公共主网正式上线:一条聚焦合规与互操作性的新公链启航 Web3市场的发展一日千里,用户对既高效又合规的金融基础设施的渴求,从未像今天这样迫切。正是在这样的背景下,基于权益证明机制、兼容EVM的第一层区块链——Pharos Network,于今日正式向公众敞开了大门。通过一
基本原则 职业女性的着装,从来不是一件小事。它像一张无声的名片,必须精准地传达出你的个性、体态特征、职位角色,更要与你所处的企业文化、办公环境乃至个人志趣相契合。 这里有个常见的误区:认为展现权威就得向男同事的着装看齐。其实恰恰相反,真正的“女强人”魅力,源于“做女人真好”的自信心态。充分发挥女性特
现代社会中,智慧与才华成为职业生涯的决定因素 工业化和高科技的浪潮,正悄然改变着职场的力量格局。一个显著的趋势是,男性的体力优势在众多领域逐渐变得不那么关键,这为女性更广泛、更深入地参与社会财富创造打开了大门。如今在工作中,“人”的属性越来越超越性别属性。那句广为流传的宣言——“没有专门只给男人或者
在办公室里,同事每天见面的时间最长,谈话可能涉及到工作以外的各种事情,讲错话常常会给你带来不必要的麻烦。同事与同事间的谈话,如何掌握分寸就成了人际沟通中不可忽视的一环。 办公室里最好不要辩论 职场里总有些人,似乎天生就喜欢争论,凡事都要争个高低对错才肯罢休。如果你恰好也具备这种“才华”,那么真心建议





