什么是缓存穿透、雪崩、击穿以及解决方案

导读:本篇文章讲解 什么是缓存穿透、雪崩、击穿以及解决方案,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

1、缓存穿透

描述:
在查询一个数据时,在缓存中不存在,将去数据库进行查询并且数据库中也不存在数据,使得缓存中一直不会存在数据,导致在请求时每次都会到数据库中进行查询,那么失去了缓存意义。

解决:
将数据库中查询出来为null的数据,写入到缓存中并且设置较短的过期时间。
伪代码:

// 出现问题情况
main(){
	String id = "123";
	Object obj = Redis.get(id);
	if(obj ==null){
		// redis获取数据为空,查询数据库
		Object dbObj = db.get(id);
		if(dbObj!=null){
			Redis.set(id,dbObj);
		}
		return dbObj;
	}
	return obj;
}
// 解决方案
main(){
	String id = "123";
	Object obj = Redis.get(id);
	if(obj ==null){
		// redis获取数据为空,查询数据库
		Object dbObj = db.get(id);
		if(dbObj!=null){
			Redis.set(id,dbObj);
		}
		// 如果数据库也为null,将null存入缓存,设置较短过期时间(10S)
		Redis.set(id,dbObj,10,Seconds);
        return dbObj;
	}
	return obj;
}

2、缓存雪崩

描述:
指设置缓存时的大量的key采用了相同的过期时间,在不同的请求进入时缓存的中大量的key刚好过期,导致请求全部转发到数据库中,使得数据库因为压力过大而崩溃。

解决:
在原有过期时间的基础上,加上一个随机值,比如1~60S,使得key的过期时间减少重复性。
伪代码:

// 模拟从数据库查询到大量不同类型数据
main(){
	List<Object> list = db.getData();
	// 原有过期时间
	long expireTime = 10;
	for(Object obj : list){
		// 加一个随机值(1~60S)
		long newTime= expireTime  + (long) (Math.random() * 60);;
		Redis.set(key,obj ,newTime,Seconds);
	}
}

3、缓存击穿

描述:
对于一些设置了过期时间的key,这些key被访问的频率非常高,在大量请求同时请求某个key时刚好出现过期的情况,那么对这个key的请求都会转发到数据库中,这就是缓存击穿。
解决:
在大量请求访问某个key时,进行加锁处理,使得其中某一个请求去查询数据库,其他请求进行等待,然后将查询出的数据写入缓存中,再解锁,那么后续的请求就会从缓存中查询到数据,而不是请求数据库。
伪代码:

main(){
	// 从redis中获取数据,在请求redis前进行加锁,加锁机制根据实际情况定
	// lock()方法为伪代码,表示加锁,只允许一个请求向下执行
	lock();
	// redis获取数据
	Object obj = Redis.get(id);
	if(obj == null){
		// 请求数据库
		Object dbObj = db.get(id);
		// 写回到缓存中
		Redis.set(id,dbObj);
	}
	// unlock()方法为伪代码,表示解锁,使得其他请求继续执行
	// 在其他请求执行Redis.get(id)时,缓存中已经有了数据,不会再去数据库查询
	unlock();
}

4、区别总结

  • 穿透
    原因:查询redis时查询不到数据,然后去查询数据库也查不到数据,这将导致redis中一直不能缓存到数据。
    解决:将查询为null的数据也放入缓存,并且设置较短的过期时间。

  • 雪崩
    原因:多个key同时失效,高并发下redis查询不到数据,导致大量请求进入到数据库。
    解决:对同一类型不同值的key设置不同的失效时间(比如:对手机类型的各条记录(key)设置不同的过期时间)。

  • 击穿
    原因:对于本该存在于redis中的key,在高并发时key刚好失效,导致大量请求进入到数据库。
    解决:让请求加锁的查询redis,如果没有数据再查询数据库,并且将数据库结果加入到缓存中,后续查询时只能等待上次查询释放锁,再后续请求获取到锁时redis缓存中就已经有了数据,所以不用查询数据库。

5、加锁实现

加锁实现,参考代码《Redis实现分布式锁》

总结:
穿透 — 缓存和数据库中都不存在数据,导致数据一直无法进行缓存;雪崩 — 大量的不同key同时过期,导致大量不同请求访问数据库;击穿 — 大量请求同访问某个在缓存中的key,刚好失效,导致所有请求进入数据库;

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/18150.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!