美文网首页
Redis雪崩、击穿、穿透

Redis雪崩、击穿、穿透

作者: zhaoyanping | 来源:发表于2020-04-16 10:28 被阅读0次

    雪崩

    目前电商首页以及热点数据都会去做缓存 , 一般缓存都是定时任务去刷新,或者是查不到之后去更新的,
    定时任务刷新就有一个问题。
    举个简单的例子:
    如果所有首页的 Key 失效时间都是 12 小时,中午 12 点刷新 的,我零点有个秒杀活动大量用户涌入,假设当时每秒 6000 个请求,本来缓 存在可以扛住每秒 5000 个请求,但是缓存当时所有的 Key 都失效了。此时 1 秒 6000 个请求全部落数据库,数据库必然扛不住,它会报一下警,真实情况可能 DBA 都没反应过来就直接挂了。此时,如果没用什么特别的方案来处理这 个故障,DBA 很着急,重启数据库,但是数据库立马又被新的流量给打死了。 这就是我理解的缓存雪崩。
    我做过的项目感觉再吊的都不允许这么大的 QPS 直接打 DB 去, 不过没慢 SQL 加上分库,大表分表可能还还算能顶,但是跟用了 Redis 的差距还是很大

    Redis雪崩.jpg
    同一时间大面积失效,那一瞬间 Redis 跟没有一样,那这个数量级别的请求直 接打到数据库几乎是灾难性的,你想想如果打挂的是一个用户服务的库,那其他依赖他的库所有的接口几乎都会报错,如果没做熔断等策略基本上就是瞬间 挂一片的节奏,你怎么重启用户都会把你打挂,等你能重启的时候,用户早就 睡觉去了,并且对你的产品失去了信心,什么垃圾产品。

    雪崩解决方案:
    处理缓存雪崩简单,在批量往 Redis 存数据的时候,把每个 Key 的失效时间都 加个随机值就好了,这样可以保证数据不会在同一时间大面积失效,我相信, Redis 这点流量还是顶得住的。

    setRedis(Key,value,time + Math.random() * 10000);
    

    如果 Redis 是集群部署,将热点数据均匀分布在不同的 Redis 库中也能避免全 部失效的问题,不过我在生产环境中操作集群的时候,单个服务都是对应的 单个 Redis 分片,是为了方便数据的管理,但是也同样有了可能会失效这样的弊 端,失效时间随机是个好策略。
    或者设置热点数据永远不过期,有更新操作就更新缓存就好了(比如运维更新了 首页商品,那你刷下缓存就完事了,不要设置过期时间),电商首页的数据也可以用这个操作,保险。

    缓存穿透和击穿

    缓存穿透是指缓存和数据库中都没有的数据, 而用户不断发起请求,我们数据库的 id 都是 1 开始自增上去的,如发起为 id值为 -1 的数据或 id 为特别大不存在的数据。这时的用户很可能是攻击者,攻 击会导致数据库压力过大,严重会击垮数据库。


    Redis穿透.jpg

    小点的单机系统,基本上用 postman 就能搞死,比如我自己买的阿里云服务。像这种你如果不对参数做校验,数据库 id 都是大于 0 的,我一直用小于 0 的参数去请求你,每次都能绕开 Redis 直接打到数据库,数据库也查不到,每次都 这样,并发高点就容易崩掉了。

    至于缓存击穿嘛,这个跟缓存雪崩有点像,但是又有一点不一样,缓存雪崩是因 为大面积的缓存失效,打崩了 DB,而缓存击穿不同的是缓存击穿是指一个 Key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个 Key 在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个完好无损的桶上凿开了一个洞。
    

    解决方案

    缓存穿透我会在接口层增加校验,比如用户鉴权校验,参数做校验,不合法的参 数直接代码 Return,比如:id 做基础校验,id <=0 的直接拦截等。

    这里我想提的一点就是,我们在开发程序的时候都要有一颗“不信任”的心,就是 不要相信任何调用方,比如你提供了 API 接口出去,你有这几个参数,那我觉 得作为被调用方,任何可能的参数情况都应该被考虑到,做校验,因为你不相信 调用你的人,你不知道他会传什么参数给你。
    举个简单的例子,你这个接口是分页查询的,但是你没对分页参数的大小做限制, 调用的人万一一口气查 Integer.MAX_VALUE 一次请求就要你几秒,多几个并 发你不就挂了么?是公司同事调用还好大不了发现了改掉,但是如果是黑客或 者竞争对手呢?在你双十一当天就调你这个接口会发生什么,就不用我说了吧。 这是之前的 Leader 跟我说的,我觉得大家也都应该了解下。

    从缓存取不到的数据,在数据库中也没有取到,这时也可以将对应 Key 的 Value 对写为 null、位置错误、稍后重试这样的值具体取啥问产品,或者看具体的场景, 缓存有效时间可以设置短点,如 30 秒(设置太长会导致正常情况也没法使用)。
    这样可以防止攻击用户反复用同一个 id 暴力攻击,但是我们要知道正常用户是 不会在单秒内发起这么多次请求的,那网关层 Nginx 我也记得有配置项, 可以让运维大大对单个 IP 每秒访问次数超出阈值的 IP 都拉黑。
    其他办法
    还有我记得 Redis 还有一个高级用法布隆过滤器(Bloom Filter)这个也能很好
    的防止缓存穿透的发生,他的原理也很简单就是利用高效的数据结构和算法快速 判断出你这个 Key 是否在数据库中存在,不存在你 return 就好了,存在你就去 查了 DB 刷新 KV 再 return。

    那又有小伙伴说了如果黑客有很多个 IP 同时发起攻击呢?这点我一直也不是很 想得通,但是一般级别的黑客没这么多肉鸡,再者正常级别的 Redis 集群都能抗 住这种级别的访问的,小公司我想他们不会感兴趣的。把系统的高可用做好了, 集群还是很能顶的。

    缓存击穿的话,设置热点数据永远不过期。或者加上互斥锁就能搞定了

    相关文章

      网友评论

          本文标题:Redis雪崩、击穿、穿透

          本文链接:https://www.haomeiwen.com/subject/apwlvhtx.html