Redis——缓存穿透、缓存击穿、缓存雪崩

缓存穿透、缓存击穿、缓存雪崩

  • 缓存流程
  • 缓存穿透
        • 解决方案:
  • 缓存击穿
        • 解决方案:
  • 缓存雪崩
        • 解决方案:

缓存流程

前台请求,后台先从缓存中取数据,取到直接返回结果,取不到时从数据库中取,数据库取到更新缓存,并返回结果,数据库也没取到,直接返回空结果。
Redis——缓存穿透、缓存击穿、缓存雪崩_第1张图片

缓存穿透

缓存穿透就是当用户访问一条数据时,缓存和数据库中都不存在,就会不断的发起请求。如果用户是攻击者,会导致数据库压力过大。

解决方案:

  1. 缓存空对象:当第一次访问查询不到数据时,将该key和对应的空值放入缓存,并设置较短的失效时间,以应对短时间的大量该key的访问。设置较短的失效时间是因为该空值可能会影响正常情况下对该key的访问。
    Redis——缓存穿透、缓存击穿、缓存雪崩_第2张图片

  2. 布隆过滤器:类似于哈希表的一种算法,用所有可能的查询条件生成一个bitmap,在进行数据库查询之前会使用这个bitmap进行过滤,如果不在其中则直接过滤,从而减轻数据库层面的压力。

缓存击穿

缓存击穿是指缓存中没有但数据库有的数据(一般是缓存过期),由于并发用户特别多,同时读缓存没有数据,又同时访问数据库,引起数据库压力瞬间增大,造成过大压力。

解决方案:

  1. 设置热点数据永不过期
    从redis上看,确实没有设置过期时间,这就保证了,不会出现热点key过期问题,也就是物理不过期。但是它会遇到一个数据更新的问题,或者说数据不一致的问题。

    在value中存储过期时间,在编码处理的时候,有条件(过期时间小于一分钟)对缓存数据进行更新,这个方案对性能最佳。

  2. 加互斥锁

public static String getData(String key) throw InterruptedException{
     
	//从缓存读取数据
	String result = getDataFromRedis(key);
	//当缓存中不存在
	if(result == null){
     
		//获取锁,获取成功,则去数据库查询数据
		if(reenLock.tryLock()){
     
			try{
     
				result = getDataFromMysql(key);
				if(result != null){
     
					//更新缓存
					setDataToCache(key,result);
				}
			}finally{
     
				//释放锁
				reenLock.unlock();
			}
		}else{
     
			//获取锁失败时,延迟100ms重新获取数据
			Thread.sleep(100);
			result = getData(key);
		}
	}
	return result;
}

缓存雪崩

缓存雪崩是指当缓存中大批量的数据过期或者缓存挂掉时,所有请求直接访问数据库,造成数据库访问量大增,引起数据库压力过大或者宕机。雪崩和击穿的区别在于:击穿是查询同一条数据,而雪崩是许多不同的数据都查不到。

解决方案:

  1. 避免缓存设置相近的有效期;为有效期增加随机值;统一规划有效期,失效时间均匀分布。
  2. redis有可能挂掉,多增加几台redis实例,(一主多从或者多主多从),这样一台挂掉之后其他的还可以继续工作,其实就是搭建的集群。
  3. 在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量,对某个key只允许一个线程查询数据和写缓存,其他线程等待。
  4. 对于一些热门数据的持续读取,这种缓存数据也可以采取定时更新的方式来刷新缓存,避免自动失效。
  5. 缓存永不过期,异步更新。

你可能感兴趣的