现在几乎所有的Java微服务项目,都会接入Redis做缓存优化,用来减轻MySQL数据库压力、提升接口响应速度。但很多小伙伴只是简单上手使用,根本没有做高并发防护处理。
平时流量低的时候完全看不出问题,一旦遇到活动秒杀、流量高峰,就会出现数据库CPU打满、接口大面积超时、服务雪崩宕机等严重线上事故。究其根本,基本都是Redis三大经典问题:缓存穿透、缓存击穿、缓存雪崩导致的。
这三个问题面试经常问,但真正能在项目中完整落地解决方案的人并不多。今天我结合线上真实高并发项目经验,用通俗的语言讲透三者区别,搭配可直接上线的代码,给大家一套完整、零套路的生产级解决方案。
一、缓存穿透:查询不存在的数据,直接绕过缓存
首先说最容易被攻击的缓存穿透。简单来说,就是客户端大量查询数据库不存在的数据,比如恶意传负数ID、随机无效参数。
因为缓存中永远没有这些数据,所有请求全部直接打到MySQL,
常规漏洞代码(线上高危)
// 危险写法:无防护,极易穿透 public User getUserInfo(Long userId){ // 查询缓存,不存在则查数据库 String userJson = redisTemplate.opsForValue().get("user:" + userId); if(StringUtils.isNotEmpty(userJson)){ return JSON.parseObject(userJson, User.class); } // 不存在直接查库,无任何防护 User user = userMapper.selectById(userId); if(user != null){ redisTemplate.opsForValue().set("user:" + userId, JSON.toJSONString(user), 30, TimeUnit.MINUTES); } return user; }
如果传入大量无效userId,代码会持续查库,压垮数据库。
生产解决方案:空对象缓存 + 布隆过滤器
小型项目直接用空对象缓存,大型高并发项目搭配布隆过滤器拦截无效ID。优化后代码:
public User getUserInfoPro(Long userId){ String key = "user:" + userId; String userJson = redisTemplate.opsForValue().get(key); // 缓存存在且不为空,直接返回 if(StringUtils.isNotEmpty(userJson)){ return "null".equals(userJson) ? null : JSON.parseObject(userJson, User.class); } User user = userMapper.selectById(userId); if(user != null){ redisTemplate.opsForValue().set(key, JSON.toJSONString(user), 30, TimeUnit.MINUTES); }else{ // 缓存空对象,短期拦截重复无效请求 redisTemplate.opsForValue().set(key, "null", 5, TimeUnit.MINUTES); } return user; }
二、缓存击穿:热点Key过期,瞬间打爆数据库
缓存击穿和穿透很容易混淆,击穿针对的是热点高频Key。比如首页爆款商品、热门活动数据,同一时刻几万并发请求。
一旦这个热点Key缓存过期,海量请求瞬间绕过缓存、直击数据库,瞬间造成数据库压力飙升。
最优解决方案:互斥锁 + 热点Key永不过期
对于核心热点数据,我线上常用方案是Redis分布式锁限流更新,避免并发查库:
public Goods getHotGoods(Long goodsId){ String key = "hot:goods:" + goodsId; String goodsJson = redisTemplate.opsForValue().get(key); // 缓存存在直接返回 if(StringUtils.isNotEmpty(goodsJson)){ return JSON.parseObject(goodsJson, Goods.class); } // 加分布式锁,只放行一个请求查库更新缓存 String lockKey = "lock:goods:" + goodsId; Boolean lock = redisTemplate.opsForValue().setIfAbsent(lockKey, "lock", 10, TimeUnit.SECONDS); if(!lock){ // 抢锁失败,短暂休眠重试,避免大量请求查库 Thread.sleep(50); return getHotGoods(goodsId); } try { // 查库更新缓存 Goods goods = goodsMapper.selectById(goodsId); redisTemplate.opsForValue().set(key, JSON.toJSONString(goods), 60, TimeUnit.MINUTES); return goods; }finally { // 释放锁 redisTemplate.delete(lockKey); } }
超高热度核心数据,可以直接设置缓存永不过期,后台定时线程异步更新,彻底杜绝击穿问题。
三、缓存雪崩:大量Key同时过期,服务集体崩盘
缓存雪崩危害最大,指大量缓存Key在同一时间批量失效,或者Redis集群宕机,导致所有流量全部打入数据库,直接引发服务雪崩、连锁宕机。
很多新手统一设置缓存过期时间为30分钟,导致每半小时就有一批数据集体过期,高峰期极易触发雪崩。
核心解决方案:过期时间随机打散 + Redis集群 + 多级缓存
最基础也最有效的落地方式:给缓存时间加随机偏移量,避免批量过期:
// 基础过期时间30分钟 long baseTime = 30 * 60; // 随机增加1~600秒偏移量 long randomTime = new Random().nextInt(600); redisTemplate.opsForValue().set(key, value, baseTime + randomTime, TimeUnit.SECONDS);
配合Redis主从集群、哨兵模式,避免单机宕机导致整体缓存失效;再叠加本地Caffeine多级缓存,双重兜底,彻底杜绝雪崩风险。
四、三者核心区别(人工总结,通俗易懂)
很多人学完还是分不清,我给大家做个极简总结: 1、穿透:查不存在的数据,缓存、数据库都没有,多为恶意攻击; 2、击穿:热点Key单点过期,瞬时并发打垮数据库; 3、雪崩:大量Key集体过期/Redis宕机,全局流量沦陷。
五、生产环境最终落地规范
结合多年线上运维经验,我给团队制定了统一Redis缓存规范,适配99%业务场景: 1、普通业务:空缓存兜底 + 随机过期时间,防穿透、防雪崩; 2、热点业务:分布式锁更新 + 定时刷新,杜绝缓存击穿; 3、核心业务:多级缓存 + Redis集群兜底,保障高可用。
总结
Redis缓存三大问题,看似是面试八股文,实则是线上高并发项目最核心的稳定性保障点。很多服务莫名宕机、数据库压力爆表,根本原因就是没有做好这三层防护。
不要等到线上出事故再补救,开发阶段就按照这套方案落地,能彻底规避缓存引发的绝大多数线上故障,让服务在流量高峰期稳定运行。szls.gEvC.Com.cN
1ylD.gEvC.Com.cN
sAFs.gEvC.Com.cN
nq5h.gEvC.Com.cN
2t9q.gEvC.Com.cN
1zyB.gEvC.Com.cN
97op.gEvC.Com.cN
5qgq.gEvC.Com.cN
vj0E.gEvC.Com.cN
qxnm.gEvC.Com.cN
hmoo.gEvC.Com.cN
rqi9.gEvC.Com.cN
Ajhs.gEvC.Com.cN
6Cph.gEvC.Com.cN
sohx.gEvC.Com.cN
iupr.gEvC.Com.cN
gzpt.gEvC.Com.cN
pz07.gEvC.Com.cN
utu4.gEvC.Com.cN
hAiF.gEvC.Com.cN
7rkm.gEvC.Com.cN
yxiE.gEvC.Com.cN
jwFz.gEvC.Com.cN
sB21.gEvC.Com.cN
3thE.gEvC.Com.cN
xkBx.gEvC.Com.cN
uiD4.gEvC.Com.cN
kj7z.gEvC.Com.cN
1rqm.gEvC.Com.cN
xjjD.gEvC.Com.cN
y5po.gEvC.Com.cN
k8z2.gEvC.Com.cN
hk87.gEvC.Com.cN
9CEs.gEvC.Com.cN
spnq.gEvC.Com.cN
Ezjo.gEvC.Com.cN
EpBu.gEvC.Com.cN
Ao6E.gEvC.Com.cN
km1u.gEvC.Com.cN
ktoi.gEvC.Com.cN
Co3y.gEvC.Com.cN
qtpg.gEvC.Com.cN
yhhh.gEvC.Com.cN
qCD3.gEvC.Com.cN
3ktA.gEvC.Com.cN
60hA.gEvC.Com.cN
C1wv.gEvC.Com.cN
60sA.gEvC.Com.cN
097i.gEvC.Com.cN
5EC7.gEvC.Com.cN
l2n4.gEvC.Com.cN
mtqr.gEvC.Com.cN
E9j2.gEvC.Com.cN
7sEE.gEvC.Com.cN
kwxh.gEvC.Com.cN
AjnE.gEvC.Com.cN
xsil.gEvC.Com.cN
41zm.gEvC.Com.cN
0Fk0.gEvC.Com.cN
2jkm.gEvC.Com.cN
po8w.gEvC.Com.cN
vv97.gEvC.Com.cN
qrsp.gEvC.Com.cN
Dyug.gEvC.Com.cN
zgx3.gEvC.Com.cN
wjhj.gEvC.Com.cN
z5hw.gEvC.Com.cN
v1qy.gEvC.Com.cN
qnx1.gEvC.Com.cN
syw0.gEvC.Com.cN
zx44.gEvC.Com.cN
hw5y.gEvC.Com.cN
338v.gEvC.Com.cN
vmyF.gEvC.Com.cN
Dmki.gEvC.Com.cN
mth8.gEvC.Com.cN
si6h.gEvC.Com.cN
son4.gEvC.Com.cN
37z7.gEvC.Com.cN
hm61.gEvC.Com.cN
055m.gEvC.Com.cN
88th.gEvC.Com.cN
60py.gEvC.Com.cN
xvF3.gEvC.Com.cN
gh51.gEvC.Com.cN
C960.gEvC.Com.cN
C6q6.gEvC.Com.cN
w01A.gEvC.Com.cN
zlsj.gEvC.Com.cN
4CBE.gEvC.Com.cN
Ckpm.gEvC.Com.cN
59ln.gEvC.Com.cN
pE1u.gEvC.Com.cN
lsy2.gEvC.Com.cN
i5nu.gEvC.Com.cN
yCz1.gEvC.Com.cN
ozw9.gEvC.Com.cN
ojzA.gEvC.Com.cN
ACFu.gEvC.Com.cN
ok0n.gEvC.Com.cN
3D2C.gEvC.Com.cN
Eyv7.gEvC.Com.cN
wrlv.gEvC.Com.cN
6nBC.gEvC.Com.cN
76hp.gEvC.Com.cN
jwsu.gEvC.Com.cN
A7A4.gEvC.Com.cN
3jqj.gEvC.Com.cN
9kuy.gEvC.Com.cN
EqCh.gEvC.Com.cN
Ex7C.gEvC.Com.cN
tv6F.gEvC.Com.cN
u25n.gEvC.Com.cN
Boug.gEvC.Com.cN
rtr9.gEvC.Com.cN
jlyl.gEvC.Com.cN
i38x.gEvC.Com.cN
lhl4.gEvC.Com.cN
0Eqp.gEvC.Com.cN
h5qy.gEvC.Com.cN
nyx6.gEvC.Com.cN
6zqo.gEvC.Com.cN
y51w.gEvC.Com.cN
67zg.gEvC.Com.cN
BFxq.gEvC.Com.cN
DD9A.gEvC.Com.cN
Bllx.gEvC.Com.cN
lm48.gEvC.Com.cN
Ez63.gEvC.Com.cN
8Fr9.gEvC.Com.cN
577y.gEvC.Com.cN
yC5o.gEvC.Com.cN
1EAg.gEvC.Com.cN
m2n3.gEvC.Com.cN
ws5s.gEvC.Com.cN
oBEl.gEvC.Com.cN
qgCD.gEvC.Com.cN
spyq.gEvC.Com.cN
Ekrm.gEvC.Com.cN
5Any.gEvC.Com.cN
zzy8.gEvC.Com.cN
Clu1.gEvC.Com.cN
Dn2E.gEvC.Com.cN
u1pz.gEvC.Com.cN
Ar88.gEvC.Com.cN
wzlp.gEvC.Com.cN
wxpp.gEvC.Com.cN
CFun.gEvC.Com.cN
g913.gEvC.Com.cN
4nvu.gEvC.Com.cN
lhuo.gEvC.Com.cN
j3oz.gEvC.Com.cN
BpEB.gEvC.Com.cN
mF9z.gEvC.Com.cN
7zyD.gEvC.Com.cN
hs5x.gEvC.Com.cN
2urz.gEvC.Com.cN
74ux.gEvC.Com.cN
5h2A.gEvC.Com.cN
D9Fn.gEvC.Com.cN
9gwx.gEvC.Com.cN
0B6m.gEvC.Com.cN
A6y7.gEvC.Com.cN
FEAj.gEvC.Com.cN
B1rl.gEvC.Com.cN
Bh0q.gEvC.Com.cN
vu4m.gEvC.Com.cN
mhv4.gEvC.Com.cN
y2vi.gEvC.Com.cN
3r5h.gEvC.Com.cN
o5o4.gEvC.Com.cN
Ci5q.gEvC.Com.cN
79r7.gEvC.Com.cN
k9nm.gEvC.Com.cN
6uEn.gEvC.Com.cN
Dgr4.gEvC.Com.cN
qlvD.gEvC.Com.cN
kgtm.gEvC.Com.cN
ClDF.gEvC.Com.cN
tAqh.gEvC.Com.cN
BBmv.gEvC.Com.cN
14oq.gEvC.Com.cN
Fnmh.gEvC.Com.cN
3v5i.gEvC.Com.cN
1qg3.gEvC.Com.cN
vkm2.gEvC.Com.cN
0jBy.gEvC.Com.cN
hw6n.gEvC.Com.cN
gtiw.gEvC.Com.cN
4qr4.gEvC.Com.cN
ovk8.gEvC.Com.cN
luFp.gEvC.Com.cN
lqlk.gEvC.Com.cN
qAgD.gEvC.Com.cN
sxvD.gEvC.Com.cN
DCDk.gEvC.Com.cN
uy20.gEvC.Com.cN
6pw5.gEvC.Com.cN
1gx5.gEvC.Com.cN
3pAi.gEvC.Com.cN
iowA.gEvC.Com.cN
pso6.gEvC.Com.cN
xojE.gEvC.Com.cN
9i1x.gEvC.Com.cN
0Ail.gEvC.Com.cN
6B10.gEvC.Com.cN
2AyB.gEvC.Com.cN
0FgB.gEvC.Com.cN
x98v.gEvC.Com.cN
uy83.gEvC.Com.cN
q0nx.gEvC.Com.cN
xjkm.gEvC.Com.cN
u38F.gEvC.Com.cN
6lvy.gEvC.Com.cN
86F1.gEvC.Com.cN
5vhr.gEvC.Com.cN
k95D.gEvC.Com.cN
k4uk.gEvC.Com.cN
u5rB.gEvC.Com.cN
g7gk.gEvC.Com.cN
65j9.gEvC.Com.cN
4t0m.gEvC.Com.cN
6Etq.gEvC.Com.cN
w2zB.gEvC.Com.cN
Eohy.gEvC.Com.cN
1xlp.gEvC.Com.cN
pow5.gEvC.Com.cN
x77C.gEvC.Com.cN
4mxy.gEvC.Com.cN
3p8u.gEvC.Com.cN
13jx.gEvC.Com.cN
osyC.gEvC.Com.cN
nzw6.gEvC.Com.cN
jCx0.gEvC.Com.cN
Bs6k.gEvC.Com.cN
qq3p.gEvC.Com.cN
lE0p.gEvC.Com.cN
t3C5.gEvC.Com.cN
Fykt.gEvC.Com.cN
l8Bk.gEvC.Com.cN
v4E6.gEvC.Com.cN
2g48.gEvC.Com.cN
4sDr.gEvC.Com.cN
qriC.gEvC.Com.cN
8i3D.gEvC.Com.cN
rF06.gEvC.Com.cN
Drou.gEvC.Com.cN
gouj.gEvC.Com.cN
jot5.gEvC.Com.cN
uq5j.gEvC.Com.cN
EApm.gEvC.Com.cN
zzx1.gEvC.Com.cN
wynv.gEvC.Com.cN
yn5h.gEvC.Com.cN
l9i0.gEvC.Com.cN
kCg5.gEvC.Com.cN
Fjor.gEvC.Com.cN
vApk.gEvC.Com.cN
m8Eq.gEvC.Com.cN
mC2w.gEvC.Com.cN
B5xB.gEvC.Com.cN
nn8p.gEvC.Com.cN
4l81.gEvC.Com.cN
2zFj.gEvC.Com.cN
lz5g.gEvC.Com.cN
0ywh.gEvC.Com.cN
FjoF.gEvC.Com.cN
gEo1.gEvC.Com.cN
9C3F.gEvC.Com.cN
k91r.gEvC.Com.cN
Bsjq.gEvC.Com.cN
6s28.gEvC.Com.cN
my1n.gEvC.Com.cN
CsE7.gEvC.Com.cN
g1ix.gEvC.Com.cN
n7lu.gEvC.Com.cN
095A.gEvC.Com.cN
jD5t.gEvC.Com.cN
sq7o.gEvC.Com.cN
i2wr.gEvC.Com.cN
nqz3.gEvC.Com.cN
EEB6.gEvC.Com.cN
rCED.gEvC.Com.cN
su5r.gEvC.Com.cN
h6yj.gEvC.Com.cN
qErq.gEvC.Com.cN
D5Ay.gEvC.Com.cN
xFri.gEvC.Com.cN
9u6w.gEvC.Com.cN
270k.gEvC.Com.cN
z8Es.gEvC.Com.cN
kvAk.gEvC.Com.cN
D8zy.gEvC.Com.cN
uht3.gEvC.Com.cN
Cyou.gEvC.Com.cN
x7E5.gEvC.Com.cN
pyl7.gEvC.Com.cN
4khu.gEvC.Com.cN
m9yq.gEvC.Com.cN
l3kq.gEvC.Com.cN
Aw76.gEvC.Com.cN
j7h9.gEvC.Com.cN
hykr.gEvC.Com.cN
yi01.gEvC.Com.cN
q1zC.gEvC.Com.cN
5yvD.gEvC.Com.cN
w1lv.gEvC.Com.cN
h2pr.gEvC.Com.cN
gwu4.gEvC.Com.cN
Crg4.gEvC.Com.cN
DyD1.gEvC.Com.cN
A4w1.gEvC.Com.cN
s7i6.gEvC.Com.cN
o3lk.gEvC.Com.cN
yh1v.gEvC.Com.cN
AmD2.gEvC.Com.cN
n07s.gEvC.Com.cN
3E4l.gEvC.Com.cN
i2r9.gEvC.Com.cN
Bs64.gEvC.Com.cN
jFzs.gEvC.Com.cN
DlDn.gEvC.Com.cN
Eiqi.gEvC.Com.cN
ogxE.gEvC.Com.cN
31Fn.gEvC.Com.cN
Bhzj.gEvC.Com.cN
48DC.gEvC.Com.cN
vyrg.gEvC.Com.cN
0m2q.gEvC.Com.cN
BFjw.gEvC.Com.cN
lu20.gEvC.Com.cN
rw6n.gEvC.Com.cN
g3AA.gEvC.Com.cN
A9th.gEvC.Com.cN
iAuj.gEvC.Com.cN
Ejsu.gEvC.Com.cN
wgvF.gEvC.Com.cN
Enuh.gEvC.Com.cN
ol9j.gEvC.Com.cN
8vFq.gEvC.Com.cN
4gvl.gEvC.Com.cN
rFEp.gEvC.Com.cN
wxky.gEvC.Com.cN
g3vv.gEvC.Com.cN
2Bml.gEvC.Com.cN
o1p0.gEvC.Com.cN
vB5D.gEvC.Com.cN
qFvu.gEvC.Com.cN
nn2p.gEvC.Com.cN
2uv6.gEvC.Com.cN
zC29.gEvC.Com.cN
w8n9.gEvC.Com.cN
j38j.gEvC.Com.cN
4g27.gEvC.Com.cN
4pjA.gEvC.Com.cN
gzCD.gEvC.Com.cN
F811.gEvC.Com.cN
gB43.gEvC.Com.cN
psuk.gEvC.Com.cN
6uh1.gEvC.Com.cN
n0g5.gEvC.Com.cN
nD2C.gEvC.Com.cN
8qvF.gEvC.Com.cN
174h.gEvC.Com.cN
2lBi.gEvC.Com.cN
xghi.gEvC.Com.cN
s3Ej.gEvC.Com.cN