缓存处理流程:
前台请求,后台先从缓存中取数据,取到直接返回结果,取不到时从数据库中取,数据库取到更新缓存,并返回结果,数据库也没取到,那直接返回空结果。
目录
一. 缓存雪崩
1.1 概念
缓存雪崩是指缓存中数据大批量同时过期,而同时查询数据量巨大,导致请求直接打到数据库,引起数据库压力过大甚至down机。
1.2 发生场景
目前大部分电商首页以及热点数据都会去做缓存 ,一般缓存都是定时任务去刷新,或者是查不到之后去更新,定时任务刷新就有一个问题。举个简单的例子:如果所有首页的Key失效时间都是12小时,中午12点刷新的,零点有个秒杀活动大量用户涌入,假设当时每秒 6000 个请求,本来缓存在可以扛住每秒 5000 个请求,但是缓存当时所有的Key都失效了。此时 1 秒 6000 个请求全部落数据库,数据库必然扛不住,它会报一下警,真实情况可能DBA都没反应过来就直接挂了。此时,如果没用什么特别的方案来处理这个故障,DBA 很着急,重启数据库,但是数据库立马又被新的流量给打死了。这就是所谓的缓存雪崩。
同一时间缓存大面积失效,那一瞬间Redis跟没有一样,这个数量级别的请求直接打到数据库几乎是灾难性的,如果打挂的是一个用户服务的库,那其他依赖他的库所有的接口几乎都会报错,如果没做熔断等策略基本上就是瞬间挂一片,怎么重启用户都会把数据库打挂掉。
1.3 解决方案
- 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
setRedis(Key,value,time + Math.random() * 10000);
- 如果缓存数据库是分布式部署(集群部署),将热点数据均匀分布在不同的缓存数据库中。
- 设置热点数据永远不过期。有更新操作就更新缓存(比如更新首页商品,直接刷缓存即可)。
二. 缓存击穿
2.1 概念
缓存雪崩是因为大面积的缓存失效,打崩了DB,而缓存击穿是指一个Key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个Key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个完好无损的桶上凿开了一个洞。
2.2 发生场景
例如双十一大促,首页设置茅台秒杀活动,大量用户访问同一条数据,这时候缓存过期,大QPS直接打到DB,导致DB崩溃。
2.3 解决方案
- 设置热点数据永远不过期。
- 加互斥锁,互斥锁参考代码如下:
三. 缓存穿透
3.1 概念
缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大,严重会击垮数据库。
3.2 发生场景
未对查询参数做校验,例如id>0校验,攻击者大量的发起请求,可能导致数据库崩溃。
3.3 解决方案
1.从缓存取不到的数据,在数据库中也没有取到,这时也可以将对应Key的Value对写为null、位置错误、稍后重试等,或者看具体的场景,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。
2.代码校验,遇到不合法查询直接返回错误或者null.
3.网关层配置,大对单个IP每秒访问次数超出阈值的IP拉黑等。
四.总结
一般避免以上情况发生从三个时间段去分析下:
事前:Redis 高可用,主从+哨兵,Redis cluster,避免全盘崩溃。
事中:本地 ehcache 缓存 + Hystrix 限流+降级,避免MySQL崩溃。
事后:Redis 持久化 RDB+AOF,一旦重启,自动从磁盘上加载数据,快速恢复缓存数据。
限流组件,可以设置每秒的请求,有多少能通过组件,剩余的未通过的请求,怎么办?走降级!可以返回一些默认的值,或者友情提示,或者空白的值。
好处:
数据库绝对不会死,限流组件确保了每秒只有多少个请求能通过。 只要数据库不死,就是说,对用户来说,3/5 的请求都是可以被处理的。 只要有 3/5 的请求可以被处理,就意味着你的系统没死,对用户来说,可能就是点击几次刷不出来页面,但是多点几次,就可以刷出来一次。
这个在目前主流的互联网大厂里面是最常见的。例如某明星爆出什么事情,去微博怎么刷都空白界面,多刷几次又出来了,那是做了降级,牺牲部分用户的体验换来服务器的安全。