缓存穿透/击穿/雪崩

缓存穿透-击穿-雪崩

缓存穿透:

查询key在缓存和数据库中均不存在数据,就会去请求数据库查询,但是数据库也可能不存在,因此就会每次去请求数据库,导致对数据库服务器造成压力,甚至压垮服务,造成整个服务的宕机。

通常此类数据的出现量是一个较低的值,如果大规模出现,则可能是有人恶意攻击。

解决方法

1)缓存空值
缓存一些经常被访问的key为空值null,这样在访问缓存时就被拦截过滤到,避免去访问数据库,为了避免存储过多空对象,因此需要设置key的过期时间。
2)布隆过滤器(BloomFilter)

BloomFilter是一种数据结构,是由一串很长的二进制向量组成,可以将其看成一个二进制数组,存放是0或1,初始默认值为0。

布隆过滤器,不存在的一定不存在,存在的不一定存在(不确定性来自于哈希冲突)。

优点:优点很明显,二进制组成的数组,占用内存极少,并且插入和查询速度都足够快。

缺点:随着数据的增加,误判率会增加;还有无法判断数据一定存在;另外还有一个重要缺点,无法删除数据(因为删除操作会影响到其他元素的判断)。

redis-key与BloomFilter的结合:

将redis中数据的key都放到BloomFilter中,每次查询的时候都先去BloomFilter判断,没有就直接返回null,有就访问Redis和数据库。由于BloomFilter没有删除操作,若redis中有些key被删除,但BloomFilter仍然判断存在,查询仍旧会经过缓存和数据库,所以对于那些已被删除的key,可以在缓存中缓存null。

使用场景:
1
2
3
4
5
6
7
8
9
10
11
1.过滤用户已经看过的内容

2.过滤爬虫已经爬过的网页。每爬取一个网页先判断是否在布隆过滤器里,如果不在,肯定没有爬取过,爬取网页后把网址放入布隆过滤器;如果在就不爬取了,很小概率误伤

3.过滤黑名单邮件,垃圾邮箱过滤;

4.防恶意流量击穿缓存,把所有的注册用户放在布隆过滤器里,来一个用户先检测是否是我的用户。 如果布隆过滤器返回不在,则判断为恶意攻击;如果判断在,很小的可能性是恶意攻击

5.推荐系统:针对不希望重复推荐的场景,如文章推荐、广告推荐的非重复性推荐场景;

6.秒杀系统:某些商品,一个ID只允许购买一次;

布鲁姆过滤器是一种特殊的哈希表,存放在内存中。

BloomFilter元素清除:

  • Counting Bloom Filter的出现解决了这个问题,它将标准Bloom Filter位数组的每一位扩展为一个小的计数器(Counter),在插入元素时给对应的k(k为哈希函数个数)个Counter的值分别加1,删除元素时给对应的k个Counter的值分别减1,Counting Bloom Filter通过多占用几倍的存储空间的代价,给Bloom Filter增加了删除操作

缓存击穿:

redis中某个key过期了,但该key访问量巨大,多个数据请求从服务器来请求redis数据均未命中,于是redis在短时间内发起大量对数据库中统一数据的访问。

解决方法

1)预先设定:预先设定可能要被大量访问值的key为永久key;
2)现场调整:监控访问量,对自然流量激增的数据延迟过期时间或设置为永久key;
3)后台刷新数据:启动定时任务,高峰期来临之前,刷新数据有效期,确保不丢失;
4)二级缓存:设置不同的失效时间,保障不会被同时淘汰就行;
5)加锁:分布式锁,防止被击穿,但是要注意也会是性能瓶颈。

缓存雪崩

缓存雪崩指的是短时间内,缓存中有大量的key集中过期,此周期内请求访问都向数据库获取数据,数据库同时收到大量的请求无法及时处理,造成redis大量请求被积压,开始出现了超时现象,数据库同时压力剧增,面临崩溃。

解决方法

1)更多的页面静态化处理;
2)构建多级缓存架构:nginx缓存+redis缓存+ehcache缓存;
3)检测mysql严重耗时业务进行优化:对数据库的瓶颈排查(例如超时查询、耗时较高事务等);
4)灾难预警机制:监控redis服务器性能指标、CPU占用、CPU使用率、内存容量、查询平均响应时间、线程数;
5)限流与降级:短时间范围内牺牲一些客户体验,限制一部分请求访问,降低应用服务器压力,待业务低速运转后再逐步放开访问

6)熔断:

  • Redis熔断机制是一种在系统出现异常时,自动采取措施防止系统继续运行的机制。 当系统出现异常时,Redis会自动将客户端连接请求中断,从而避免异常继续扩散,保障系统的稳定运行。 Redis熔断机制主要通过设置超时时间和连接数来实现。 当客户端连接数超过设定的最大连接数时,Redis会自动将客户端连接请求中断。