缓存雪崩
大量缓存在同一时间失效,导致大量请求同时访问数据库,从而造成数据库压力过大甚至宕机。
TIP
Redis宕机也属于雪崩
栗子
假设有 Redis:
user:1
user:2
user:3
goods:1001
goods:1002
shop:001
config:system平时命中率 95%,数据库压力很小。
在设定中数据的过期时间是 30分钟,在系统启动时同时进行了缓存。
例如:12:00 进行缓存,那么数据将在 12:30 过期。
此时有 50000 个请求同时到达,由于缓存已经过期,这些请求全都打到了数据库上,数据库瞬间被压垮。
这就是
缓存雪崩
缓存穿透 / 击穿 / 雪崩 的区别
| 问题 | Key数量 | 数据是否存在 |
|---|---|---|
| 缓存穿透 | 很多不存在的Key | 不存在 |
| 缓存击穿 | 一个热点Key | 存在 |
| 缓存雪崩 | 大量Key | 存在 |
解决方案
方案1:随机过期时间(最常用)
不要设定成同一的过期时间,当在同一时间缓存时很容易造成缓存雪崩。
而是通过 固定时间 + 随机数 的方式设置过期时间。
例如
java
// 30分钟 + 随机数
int ttl = 30 + Random.nextInt(10);
redis.set(key, value, ttl, TimeUnit.MINUTES);方案2:热点数据永不过期
适用于:
- 系统配置
- 店铺信息
- 省市数据
- 菜单数据
这些很长时间都不会发生变化的数据,完全可以设置成 永久缓存。
修改时删除缓存,等待下载重新加载即可。
方案3:多级缓存
浏览器缓存
↓
Nginx缓存
↓
Redis
↓
MySQL不把鸡蛋放在同一个篮子里,即使 Redis 挂掉,前面还有其他缓存,大型网站经常这样做。
方案4:限流降级
数据库压力过大:
比如有 1000000 个请求进入,只接受其中 1000 个请求,其余的返回错误信息。
json
{
"msg":"系统繁忙,请稍后重试"
}常见组件:
- Sentinel
- Gateway 限流