参考文章、视频
视频:什么是Redis缓存雪崩、穿透、击穿,十分钟给你讲的明明白白
1.缓存击穿
情形概述
缓存中某个key失效的瞬间,大量请求并发涌入,所有请求都打向了MySQL数据库,没等到Redis重建缓存便已宕机。
解决方案
- 设置永不过期:如果全部key都如此处理,可能导致OOM;
- 分布式锁。
2.分布式锁
原理概述
多线程并行访问时,第一个线程将抢到锁并重建缓存,其他线程没能抢到锁则进入休眠,待唤醒后从缓存中获取数据。
分布式锁特征
- 互斥性:只有一个线程持有锁,即一个key只能被一个线程锁住;
- 避免死锁:万一抢到锁的线程崩溃,锁能自动解开;
- 解铃还须系铃人:只有抢到锁的线程可以解开锁;
- 加锁与解锁都必须具有原子性:加锁可用set <key> <value> NX EX <expireSeconds>,解锁则使用lua脚本。
- 正常执行时锁不能自动失效:在上锁后,开启watch dog线程定期续锁。
分布式锁核心技术点实现:
-
互斥性、避免死锁、解铃还须系铃人
– 上锁时,使用NX保证每个key只有一个值(即一个key只有一把锁);
– 上锁时,使用EX <expireSeconds>避免因线程崩溃导致死锁;
– 上锁时,以用户id作为value,在解锁时需要对value进行验证,确保上锁与解锁的为同一个人。
# 示例:用户3119004000对3号商品上锁,锁有效时间为30s set product:3 3119004000 NX EX 30
-
加锁与解锁必须具有原子性
– 上锁不能用setNx,因为该指令不能设置有效时间,无法保证原子性;
– 解锁只能用Lua脚本实现,因为解锁分为两步:
------ 验证:通过get指令获取value(用户id),判断上锁与解锁的人是否为同一个;
------ 解锁:通过del指令解锁(删除key)
-
正常执行时锁不能自动失效
在成功执行上锁(set …)之后,开启子线程,每隔一定时间(10s)判断主线程是否崩溃;若未崩溃,重新使用上锁指令来为锁续期。