本文将会从以下三个方面介绍:
1、是什么?
2、导致问题的原因是什么?
3、何如避免?
缓存击穿(Cache Breakdown)、缓存穿透(Cache Penetration)、缓存雪崩(Cache Avalanche)
1 缓存击穿(Cache Breakdown):
缓存击穿是指在一个缓存系统中,某个热门数据过期失效后,正好在这段时间内有大量的并发请求访问这个数据,导致所有请求都绕过缓存直接访问数据库。这会导致数据库承受了巨大的压力,可能引起数据库性能问题。
造成缓存击穿的主要原因是:
当某个热门数据过期后,其他请求在获取这个数据时发现缓存失效,于是并发地去数据库查询,由于并发量大,导致数据库压力骤增,影响系统的性能。
如何避免?
使用互斥锁或分布式锁来保证只有一个线程去数据库查询,其他线程等待查询结果。
在缓存失效时,立即触发后台线程去异步更新缓存,避免在请求到来时才更新缓存。
2 缓存穿透(Cache Penetration):
缓存穿透是指在一个缓存系统中,有大量的请求访问一个不存在于缓存中的数据,而且这些请求都会直接访问数据库。这可能是因为恶意攻击或者客户端错误,请求了不存在的数据。
造成缓存穿透的主要原因是:
当请求访问一个不存在的数据时,缓存并没有命中,请求会绕过缓存直接访问数据库。由于请求的数据根本不存在,所以每个请求都会直接查询数据库,导致数据库压力骤增。
如何避免?
1、在缓存中预先设置一个空值或者哨兵值,表示该数据不存在,当查询数据库后得到空结果时,也将空值缓存起来,设置一个较短的过期时间,这样在接下来的请求中可以直接命中缓存,减轻对数据库的查询压力。
2、对请求参数进行合法性检查,过滤掉不符合要求的请求,避免非法请求直接访问数据库。(布隆过滤器,可以参考这个 https://zhuanlan.zhihu.com/p/96093916)
3 缓存雪崩(Cache Avalanche):
大量缓存数据在同一时间内失效,导致大规模的数据库查询。这通常是因为缓存数据设置了相同的过期时间,导致同时失效。
可能发生的原因:
当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,会给后端系统带来很大压力。导致系统崩溃。
如何应对?
1、使用互斥锁或分布式锁来避免缓存击穿,保证在缓存失效时只有一个线程去数据库查询,其他线程等待查询结果。
2、在缓存失效时,立即触发后台线程去异步更新缓存,避免在请求到来时才更新缓存,减少缓存击穿的可能性。
3、控制失效时间均匀,不同的key,设置不同的过期时间、或者使用随机的方式设置过期时间,避免所有缓存数据在同一时间过期。
4、缓存主动预热,异步线程独立刷新
5、可以采用分级分片缓存策略,将数据多副本分散存储在不同的缓存服务器上,减少单点失效带来的影响;可以使用JVM堆内缓存。
4 热点数据问题:
某些热门数据的访问频率非常高,可能导致缓存失效频繁或缓存容量不足,影响系统性能。
如何应对?解决缓存的热点数据问题需要采取一些策略来有效地缓解热点数据访问带来的压力。下面列出了一些解决热点数据问题的方法:
1、缓存预热:在系统启动时或者是数据更新时,预先加载热门数据到缓存中。这样,当请求到来时,缓存中已经存在热门数据,可以直接命中缓存,减少对数据库的查询。
2、数据分片:将热门数据按照一定的规则进行分片,将不同的数据分散存储在多个缓存服务器上。这样,每个缓存服务器只负责一部分热门数据,减少单个缓存服务器的压力。
3、热点数据加权随机算法:针对热点数据,可以给予更高的缓存权重,使得缓存服务器在处理请求时更倾向于缓存热点数据。加权随机算法可以平衡热点数据和非热点数据的访问压力。
4、LRU(Least Recently Used)算法:采用LRU算法来淘汰一些长时间没有被访问的缓存数据,优先保留经常被访问的热点数据。这样可以保持缓存中主要是热门数据,减少冷数据的占用。
5、设置合理的缓存过期策略:对于热门数据,可以设置较长的过期时间,避免频繁地失效和更新。而对于不常用的数据,可以设置较短的过期时间,让其自然过期或在更新时才更新缓存。
6、本地缓存 + 分布式缓存:将热门数据同时存储在本地缓存和分布式缓存中。本地缓存可以快速响应部分请求,而分布式缓存则提供全局缓存服务。当本地缓存失效时,仍然可以从分布式缓存中获取数据。
7、使用异步缓存更新:对于热点数据,可以采用异步缓存更新的方式,在缓存失效时异步地去更新缓存,避免阻塞主线程,提高系统的响应性能。
总结:
缓存击穿是因为缓存中的热门数据过期导致,并发请求绕过缓存直接访问数据库。
缓存穿透是因为请求访问不存在的数据导致,所有请求都绕过缓存直接访问数据库。
缓存雪崩是指大量缓存数据在同一时间内失效,导致大规模的数据库查询。
缓存击穿的解决方案主要是在缓存失效时采取措施避免并发请求直接查询数据库。
缓存穿透的解决方案主要是预先设置缓存空值或者对请求参数进行合法性检查。
避免缓存雪崩的措施包括使用不同的过期时间和加锁或者分布式锁来控制并发查询。
缓存雪崩与缓存击穿的区别在于失效的规模,缓存击穿通常是某个热门数据过期导致,并发请求绕过缓存查询数据库,而缓存雪崩是大量缓存数据同时失效导致大规模的数据库查询。
总的来说,为了避免这些问题,可以采取一些解决方案:
使用互斥锁或分布式锁来避免缓存击穿,保证在缓存失效时只有一个线程去数据库查询,其他线程等待查询结果。
在缓存失效时,立即触发后台线程去异步更新缓存,避免在请求到来时才更新缓存,减少缓存击穿的可能性。
对于缓存穿透问题,可以在缓存中预先设置一个空值或哨兵值,表示该数据不存在,避免对数据库进行无效查询。并且对请求参数进行合法性检查,过滤掉不符合要求的请求。
避免缓存雪崩,可以采取设置不同的过期时间,或者使用随机的方式设置过期时间,避免所有缓存数据在同一时间过期。另外,可以采用分级缓存策略,将数据分散存储在不同的缓存服务器上,减少单点失效带来的影响。
对于热点数据,可以采取缓存预热策略,即在系统启动时或者是数据更新时,预先加载热门数据到缓存中,避免在请求到来时才进行缓存加载。
综合考虑系统的需求和特点,合理使用缓存并采取适当的缓存优化措施,可以显著提升系统的性能和稳定性。
-End-