缓存雪崩、缓存击穿、缓存穿透发生的场景分析及解决

一、简单描述加缓存情形下,数据的读取:

读取某个数据时,先看缓存中是否存在;存在则返回数据;不存在则从数据库中读取,然后放入缓存。

二、缓存雪崩:

缓存雪崩指的是:一大批缓存的数据在同一时间过期,这时去获取数据的话,就会去数据库中进行获取,而此时由于数据量很大,所以可能直接压垮数据库。

举个例子: 我们对商品详情页进行缓存,每个商品id对应一个商品详情页的缓存,如果我们把每个商品对应的缓存过期时间设置一样。在高并发下,当缓存在同一时间失效时,都会去数据库查询数据,因为商详页设计的信息很多很多,并且在多个线程同时下,数据库会很快崩掉。

解决方法:

  1. 在设置过期时间时,再加上一个随机数,根据并发情况,可以调整随机数的范围,并发高时将范围调大。这样就可以防止在同一时间大量缓存失效。
  2. 不设置过期时间(这里要看数据的性质,一般的缓存都是要设置过期时间的,避免内存占用持续增高)

三、缓存击穿:

缓存击穿指的是: 当某个缓存失效时,多个线程判断都为空,就都会去查数据库然后设置缓存。此时虽然只是某一个缓存失效,但由于并发高,数据库会遭受瞬间的高并发压力。

举个例子:上面我们通过在设置过期时间时加了随机值,避免了缓存雪崩。但是假设此时来了20万的并发请求某个商品商详页信息,此时缓存过期,20万的线程同时去查数据库,可怕。。。

解决办法:

  1. 判断某个缓存为空时,先获取锁,再去查数据库。这样就能保证只会有一个线程去查数据库然后设置缓存。
  2. 不设置过期时间

这里加锁时,注意double-check(与单例的DCL实现思想一样):

data=从缓存获取数据;
if(data==null){
    
    
	
	lock.lock();
	
	try{
    
    
		//	这里一定要再次判断,否则第一个线程释放锁后,剩余线程获取锁后又来查库、设置缓存了,相当于没设置锁
		if(data==null){
    
    
			//查库,设置缓存
		}
	}finally{
    
    
		lock.unlock();
	}
	
}

四、缓存穿透:

缓存穿透指的是: 请求的某个缓存不存在,直接去数据库查,数据库也没有,下一次又去数据库查。这里一般发生于恶意用户传入非法的数据进行攻击。

举个例子: 恶意用户传入负的商品ID或者不存在的商品ID来查询商品,这样由于缓存中没有,每次都会去查询缓存。

解决办法:

  1. 参数检验,根据情景,对非法范围的请求参数在上层先进行过滤。
  2. 将在数据库中未查到的商品也加入缓存,即以 商品ID—空值的形式放入缓存。这里应该为这类缓存设置比正常缓存更短的过期时间。
  3. 使用布隆过滤器,预先把商品对应的某类缓存根据skuId放入布隆过滤器。后面查询某个skuId对应的内容时,先通过布隆过滤器查看是否存在,不存在的话直接反馈给前端,存在再去查询Redis或者数据库。

猜你喜欢

转载自blog.csdn.net/qq_40728028/article/details/106576862