您的位置:首页 > 数据库 > Redis

【Redis面试篇】缓存雪崩、穿透、击穿

2020-07-20 15:59 169 查看

缓存雪崩:

理论:

缓存在同一时间大面积的过期(失效),接着来的一大波请求瞬间都落在了数据库中导致连接异常(崩掉)。

例子:

电商首页以及热点数据都会做缓存 ,一般缓存都是

定时任务去刷新
,或者是
查不到之后去更新
的,
定时任务刷新有一个
问题
。如下面的例子:

  • 如果所有首页的Key失效时间都是12小时,中午12点刷新的,我零点有个秒杀活动大量用户涌入,假设当时每秒 6000 个请求,本来缓存在可以扛住每秒 5000 个请求,但是缓存当时所有的Key都失效了。此时 1 秒 6000 个请求全部落数据库,数据库必然扛不住,它会报一下警,真实情况可能DBA都没反应过来就直接挂了。此时,如果没用什么特别的方案来处理这个故障,DBA 很着急,重启数据库,但是数据库立马又被新的流量给打死了。这就是缓存雪崩。
  • 再吊的项目都不允许这么大的QPS直接打DB去,不过没慢SQL加上分库,大表分表可能还算能顶,但是跟用了Redis的差距还是很大
  • 同一时间大面积失效,那一瞬间Redis跟没有一样,那这个数量级别的请求直接打到数据库几乎是灾难性的,如果挂的是一个用户服务的库,那其他依赖他的库所有的接口几乎都会报错,如果没做熔断等策略基本上就是瞬间挂一片,你怎么重启用户都会把你打挂.
解决
办法
  • 1.在批量往Redis存数据的时候,把每个Key的失效时间都加个
    随机值
    ,这样可以保证数据不会在同一时间大面积失效。
  • setRedis(Key,value,time + Math.random() * 10000)
  • 2.如果Redis是
    集群部署
    ,将热点数据均匀分布在不同的Redis库中也能避免全部失效的问题,不过在生产环境中操作集群的时候,单个服务都是对应的单个Redis分片,是为了方便数据的管理,但是也同样有了可能会失效这样的弊端,失效时间随机是个好策略。
  • 3.或者设置热点数据永远不过期,有更新操作就更新缓存就好了(比如运维更新了首页商品,那刷下缓存就完事了,不要设置过期时间),电商首页的数据也可以用这个操作,保险。
  • 事前:尽量保证整个 redis 集群的高可用性,发现机器宕机尽快补上。选择合适的内存淘汰策略。
  • 事中:本地ehcache缓存 + hystrix限流&降级,避免MySQL崩掉。
  • 事后:利用 redis 持久化机制保存的数据尽快恢复缓存。

缓存穿透:

理论:

一般是恶意用户故意请求缓存中不存在的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量请求而崩掉。

例子:

缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,

  • 1.数据库的 id 都是1开始自增上去的,如发起为id值为 -1 的数据或 id 为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大,严重会击垮数据库。
  • 2.如果不对参数做校验,数据库id都是大于0的,我一直用小于0的参数去请求你,每次都能绕开Redis直接打到数据库,数据库也查不到,每次都这样,并发高点就容易崩掉了。
解决办法:
  • 1.在接口层增加校验,比如用户鉴权校验,参数做校验,不合法的参数直接代码Return,比如:id 做基础校验,id <=0的直接拦截等。
  • 2.在开发程序的时候都要有一颗“不信任”的心,就是不要相信任何调用方,比如你提供了API接口出去,你有这几个参数,那我觉得作为被调用方,任何可能的参数情况都应该被考虑到,做校验.
  • 3.从缓存取不到的数据,在数据库中也没有取到,这时也可以将对应Key的Value对写为null、位置错误、稍后重试等这样的值,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。
    防止
    攻击用户反复用同一个id暴力攻击,正常用户不会在单秒内发起这么多次请求的,
    网关层
    Nginx有配置项,可以让运维对单个IP每秒访问次数超出阈值的IP都拉黑。
  • 4.高级用法布隆过滤器(Bloom Filter)能很好的防止缓存穿透的发生,原理就是利用高效的数据结构和算法快速判断出你这个Key是否在数据库中存在,不存在直接return,存在就去查DB刷新KV再return。(将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被 这个bitmap截掉,从而避免了对底层存储系统的查询压力)

缓存击穿:

理论:

一个Key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个Key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库。

解决办法:
  • 设置热点数据永远不过期。或者加上互斥锁

缓存并发问题

理论:

1.Redis为单进程单线程模式,采用队列模式将并发访问变为串行访问。Redis本身没有锁的概念,Redis对于多个客户端连接并不存在竞争,但是在Jedis客户端对Redis进行并发访问时会发生连接超时、数据转换错误、阻塞、客户端关闭连接等问题,这些问题均是由于客户端连接混乱造成。

2.这里的并发指的是多个redis的client同时set key引起的并发问题。比较有效的解决方案就是把redis.set操作放在队列中使其串行化,必须的一个一个执行。对此有2种解决方法:

解决办法:
  • 1.客户端角度,为保证每个客户端间正常有序与Redis进行通信,对连接进行池化,同时对客户端读写Redis操作采用内部锁synchronized。
  • 2.服务器角度,利用setnx实现锁。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: