什么是缓存雪崩,缓存击穿,缓存穿透,缓存预热,缓存更新,缓存降级?

什么是缓存雪崩,缓存击穿,缓存穿透,缓存预热,缓存更新,缓存降级?

一、缓存雪崩

由于原有缓存失效,新缓存未到期间(例如我们设置缓存采用了一样的过期时间,在同一时刻造成了所有的缓存失效),所有原本应该去访问缓存的请求都去查询数据库,
对数据库CPU和内存造成了巨大的压力,严重的会造成数据库宕机。

缓存雪崩的解决方案:
(1)如果并发量不是特别多的话,使用最多的方案是加锁排队。

public void getAllList(){
	int cacheTime = 30;
	String cacheKey = "list_key";
	String lockKey = cacheKey;
	
	String value = CacheHelper.get(cacheKey);
	if(value != null){
		// 如果缓存有值,就直接取出来即可
		return value;
	}else{
		synchronized(lockKey){
			value = CacheHelper.get(cacheKey);
			if(value != null){
				return value;
			}else{
				// 这里一般是SQL查询语句
				value = GetListFromDB();
				// 把查询结果放入缓存
				CacheHelper.Add(cacheKey,value,cacheTime)
			}
		}
		return value ;
	}
}

(2)批量往Redis存数据的时候,把每个key设置一个随机失效时间,这样可以保证数据不会在同一时间大面积失效。

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

缓存标记:记录缓存数据是否过期,如果过期,则会通知另外的线程在后台去更新实际key的值。

缓存数据:缓存数据的过期时间比缓存标记的时间延长一倍,如果,缓存标记过期时间是30分钟,缓存数据的过期时间是60分钟,这样当缓存标记过期后,还能把缓存中放的旧数据返回给调用端,直到另外的线程再后台更新完成后才会返回新缓存。

二、缓存击穿

缓存击穿跟缓存雪崩很像,缓存雪崩是大面积缓存失效,所有请求都访问数据库,导致数据库压力过大而崩掉。

缓存击穿是指一个key特别热门,大并发请求不停的队这个key进行访问,当这个key失效的时候,持续的大并发就冲破缓存直接访问数据库,导致数据库崩掉。

解决方案:
(1)使用互斥锁
当获取key的值为空时,先锁上,再从数据库加载,加载完毕,释放锁。若其他线程获取锁失败,则睡眠50ms后重试。

String get(String key) {  

   String value = redis.get(key);  

   if (value  == null) {  

    if (redis.setnx(key_mutex, "1")) {  

        // 3 min timeout to avoid mutex holder crash  

        redis.expire(key_mutex, 3 * 60)  

        value = db.get(key);  

        redis.set(key, value);  

        redis.delete(key_mutex);  

    } else {  

        //其他线程休息50毫秒后重试  

        Thread.sleep(50);  

        get(key);  

    }  

  }  

}  

(2)异步构建缓存
该方法redis自己维护一个失效时间,当失效时间小于System.currentTimeMillis()时,则进行缓存更新,否则直接返回value值。

优点:性能最佳,用户无需等待
缺点:无法保证缓存一致性

三、缓存穿透

缓存穿透是指用户在数据库查询查不到,在缓存中自然也不会有,这样就导致每次用户查询的时候在缓存查不到,在数据库也查不到,相当于进行了两次无用查询。

缓存穿透解决方案
(1)采用布隆过滤器。将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。

布隆过滤器
布隆过滤器相当于一个不怎么精确的set结构,布隆过滤器有两个基本指令,bf.add添加元素,bg.exits查询元素是否存在。要想一次添加多个元素,用bf.madd指令。
要一次查找是否存在多个元素,用bf.mexits指令。

布隆过滤器的原理如图:
在这里插入图片描述
每个布隆过滤器对应到Redis的数据结构里面就是一个大型的位数组和几个不一样的无偏hash函数,所谓无偏就是能把hash值算的比较均匀。

向布隆过滤器中添加key值时,会使用多个hash函数对key值进行hash算法取得一个哈希值,然后对数组长度进行取模运算得到一个下标位置,每个hash函数都会得到一个不同的位置,最后得到多个位置,再把位数组的这几个位置都置为1就完成了add操作。
向布隆过滤器中查询某个key值时,也跟add操作一样,算出来hash的几个位置,看看这几个位置是否都为1,有一个为0就说明布隆过滤器中该值不存在。如果这几个位置都是1,
也不一定说明这个key存在,也有可能是别的key值存在导致。

Redis中使用布隆过滤器:
布隆过滤器可能存在误判的情况,Redis中有两个值可以决定布隆过滤器的准确率。

  • error_rate:允许布隆过滤器的错误率,这个值越低过滤器的位数组的大小越大,占用空间就越大。
  • initial_size:布隆过滤器可以存储的元素个数,当实际存储的元素个数超过这个值之后,过滤器的准确率会下降。

Redis中有一个命令可以来设置这两个值:

bf.reserve urls 0.01 100

三个参数的含义:

  • 第一个是过滤器的名字
  • 第二个是error_rate的值
  • 第三个是initial_size的值
    使用这个命令要注意,执行这个命令之前这个过滤器应该是不存在的,如果存在的话会报错。

(2)如果一个查询的数据为空,我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。这样下一次访问缓存就有值了,而不会继续访问数据库。

四、缓存预热

缓存预热就是系统上线后,提前将相关的缓存数据直接加载到缓存系统中,避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题。
解决方案:
(1)直接写个缓存页面,上线时手工操作下
(2)数据量不大,可以在项目启动的时候自动加载
(3)定时刷新缓存

五、缓存更新

除了缓存自带的缓存失效策略之外,我们还可以进行自定义的缓存淘汰策略,常见的策略有两种:
(1)定期去清理过期的缓存
(2)当有用户请求过来时,再判断这个请求用到的key是否过期,过期的话就去获取新数据并更新缓存。

六、缓存降级

当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时,仍然需要保证服务还是可用的,即使是有损服务。

系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级。

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值