暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Redis安全:缓存雪崩、击穿、穿透的区别与解决方法

YiluPHP 2021-06-22
2177
关于Redis,我相信各位在面试、或者实际开发过程中对Redis缓存雪崩穿透击穿并不陌生,就算没遇到过你肯定听说过吧。下面直接简述三者产生的原因和解决方法。


缓存雪崩

产生原因:
假设数据库最大能承受每秒6000个请求,上午10点有个抢购活动大量用户涌入,假设当时每秒有1万个请求,而所有缓存刚好都在上午10点失效刷新的,那么在10点整的时候1万个请求将全部查询数据库,数据库必然扛不住,导致系统缓慢而报警,真实情况可能DBA都没反应过来就直接挂了,之后DBA很着急,重启数据库,但数据库马上又被新的流量给压跨了。这就是缓存雪崩
同一时间大面积缓存效,那一瞬间跟没有Redis一样个数量级求直接打到数据库,这个灾难性的,因为此时不只是抢购功能没法使用,其它依赖此数据库的接口也是瘫痪的果没有等策略基本上瞬间挂一片

解决方法:
处理缓存雪崩很简单,只要确保所有Redis缓存数据不会在同一时间失效就行了,这里给出以下四点措施:
  1. 假如有多条数据在同一时间存入Redis,可以给失效时间加一个随机数,让它们不会在同一时间失效。

  2. 针对热点数据可以设置更长的失效时间,直到它们不再热为止。

  3. 如果是Redis集群部署,可以将热点数据均匀分布在不同的Redis库中,这样可以防止因一台Redis宕机而全部热数据失效的问题。

  4. 对同一ip做请求频率的限制,例如每一秒限制100个请求,每一分钟限制1000个请求,具体的频率限制根据你的系统业务特点和用户群体而定,注意一个公司几百号人的ip可能是一样的,得允许同一个公司的多人同时发起请求。这一点是一个网站必须要做的,防止缓存雪崩、击穿、穿透,包括其它的防范都能用上。


缓存穿透

产生原因:


缓存穿透是指查询缓存中不存在的数据,这样必定要查询数据库,缓存穿透可以绕开缓存访问数据库。这是怎么做到的呢?举例说明:假如数据库的id是从1开始自增的,当前最大的id是1000,如果此时发起id为-1或者5000的数据请求,数据库中是没有此数据的,缓存中也没有此数据。请求过程是先去缓存中找数据,发现没有就会查数据库。攻击者可以利用这些不存在的数据发起大量请求进行数据库的攻击,致使数据库缓慢甚至击垮数据库。

解决方法:

可以用以下五种方法解决缓存穿透的问题:
  1. 校验请求参数,明显不存在或者不合法的参数直接返回错误,如id为-1的参数。

  2. 访问权限校验,如果无权访问则直接返回错误。

  3. 当查询到数据库中不存在的数据(例如id为1001的参数)时,也在Redis中做标识,例如存一个空值到Redis中,下次再访问时就知道此数据是不存在的,不用再查数据库了。这里需要注意的是,当新增了数据时记得清一次缓存里的标识,例如新增了id为1001的数据时,要把Redis中id为1001的无数据标识给清理掉。

  4. 同一ip做请求频率的限制,例如每一秒限制100个请求,每一分钟限制1000个请求,具体的频率限制根据系统业务特点用户群体定,注意一个公司几百号人的ip可能是一样的,得允许同一个公司的多人同时发起请求这一点是一个网站必须要做的,防止缓存雪崩、击穿、穿透,包括其它的防范能用

  5. Redis在4.0版本推出了 module 的形式,可以将 module 作为插件额外实现Redis的一些功能。官网推荐了一个 RedisBloom 作为 Redis 布隆过滤器(Bloom Filter)的 Module,这个也能很好的防止缓存穿透的发生,它的原理也很简单就是利用高效的数据结构和算法快速判断出一个Key是否在数据库中存在,若不存在直接返回就好了,若存在就去查DB刷新KV,再返回数据。


缓存击穿

产生原因:

缓存击穿缓存雪崩有点像不同的是缓存雪崩是因为大面积的缓存失效,而缓存击穿是指在一个Key失效的瞬间,持续的大并发就穿破缓存,直接访问数据库。这就像在一个完好无损的桶上凿开了一个洞。

缓存击穿缓存穿透的不同点是,缓存击穿是在访问正常存在的数据发生,而缓存穿透是在访问不存在的数据时发生。


解决方法:

缓存击穿的解决方法如下:
  1. 把热点数据的缓存失效时间设置长一点,直到它不热为止。

  2. 对于单个ip或者单个用户访问单个id数据的频率做限制,例如每1秒最多请求30次,具体频率根据系统业务特点和用户情况而定。注意一个公司几百号员工的ip是一样的,得允许同一个公司的多人同时发起请求。这样可以防止攻击用户反复用同一个id暴力攻击。

  3. 加Redis锁,当缓存失效时只允许一个请求去访问数据库和更新缓存,其它请求等待Redis缓存中的数据。具体的PHP代码实现我会在后面的文章中分享,关注YiluPHP的微信公众号,不错过精彩的干货分享。


总结

正常的系统和正常的用户是不需要防范的,需要防范的是调用者的程序出现BUG、非正常用户的恶意攻击。上面提到的系统熔断策略、单个ip请求频率的限制、单个ip对单个页面的请求频率限制都是常用的方法,对于访问频率超出阈值的IP给直接返回友好提示或者拉黑。
我们知道单机PHP的并发量是很有限的,与Nginx的并发量相比相差甚远,因此我们可以在Nginx层做ip访问频率的限制,我会在后面的文章中分享方法和源码,关注YiluPHP的微信公众号,不错过精彩的干货分享。

有小伙伴可能要问了:如果黑客有很多个IP同时发起攻击怎么办呢?这个就是DDOS洪水攻击,可以网上搜索“DDOS洪水攻击的原理和防范”进行了解。
文章转载自YiluPHP,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论