一、什么是缓存击穿
1.缓存击穿的定义
缓存击穿:给某一个key设置了过期时间,当key过期的时候。恰好这时间点对这个key有大量的并发请求过来,这些并发的请求可能会瞬间把DB压垮。
2.图片理解
二、那么应该如何解决呢
1.方案一:互斥锁
就是在缓存过期的时候,查询缓存没有数据,就立马加锁,当线程1获取锁后,其他线程先休眠一下,当线程1查询数据库重建缓存数据并且已经加入缓存后,才会释放锁,线程2在重试的时候,就可以获取到了缓存数据。
优点:强一致。缺点:性能差。
2.方案二:逻辑过期
逻辑过期核心就是不设置缓存的过期时间,而是在value中加入逻辑过期时间的字段。
线程1在查询缓存的时候,发现逻辑时间已经过期,就会获取互斥锁,然后会开启新线程(线程2),线程2则会查询数据库重建缓存数据,并写入缓存,重置逻辑过期时间,最后释放锁,而线程1并不会获取新的缓存数据。而是返回原来过期的数据。由于线程3获取不到锁,所以也会直接返回过期数据。而线程4会在线程2之后,可以获取新的数据。
优点:高可用,性能好。缺点:数据可能不一致。
3.实际用哪种呢
一般涉及到钱什么的用方案一。一般互联网行业,注重用户体验,会使用方案二。具体情况具体分析。
三、面试的时候应该怎么说
面试官:什么是缓存击穿 ? 怎么解决 ?
候选人:
缓存击穿的意思是对于设置了过期时间的key,缓存在某个时间点过期的时候,恰好这时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端 DB 加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把 DB 压垮。
解决方案有两种方式:
第一可以使用互斥锁:当缓存失效时,不立即去load db,先使用如 Redis 的 setnx 去设置一个互斥锁,当操作成功返回时再进行 load db的操作并回设缓存,否则重试get缓存的方法。
第二种方案可以设置当前key逻辑过期,大概是思路如下:
①:在设置key的时候,设置一个过期时间字段一块存入缓存中,不给当前key设置过期时间
②:当查询的时候,从redis取出数据后判断时间是否过期
③:如果过期则开通另外一个线程进行数据同步,当前线程正常返回数据,这个数据不是最新
当然两种方案各有利弊:
如果选择数据的强一致性,建议使用分布式锁的方案,性能上可能没那么高,锁需要等,也有可能产生死锁的问题。
如果选择key的逻辑删除,则优先考虑的高可用性,性能比较高,但是数据同步这块做不到强一致。