大家好,今天我们一起聊聊Java开发中缓存使用常见的缓存穿透、击穿及雪崩。
大纲

Java开发中的缓存
在Java开发中,缓存是指将数据存储在内存中以便快速访问的数据结构或组件。它用于减少对原始数据源的访问次数,从而提高应用程序的性能和响应速度。缓存通常用于存储那些读取频繁但不经常变化的数据。
为什么要使用缓存
性能提升
缓存可以减少对数据库、文件系统或其他慢速数据源的访问,从而显著提高应用程序的性能。
减轻后端压力
当多个用户或系统组件同时请求相同的数据时,缓存可以减少对后端系统的负载,防止其过载。
减少网络延迟
对于分布式系统或微服务架构,缓存可以减少网络调用的次数,从而降低网络延迟。
提高用户体验
快速响应和流畅的用户界面是提高用户满意度和留存率的关键因素,缓存可以帮助实现这一点。
都有哪些缓存技术
Guava Cache
Google开源的Java库,提供了本地缓存的实现,支持自动加载、过期、移除等特性。
Caffeine
一个高性能的Java本地缓存库,提供了基于LRU(最近最少使用)算法的缓存淘汰策略,以及灵活的缓存配置。
Ehcache
一个广泛使用的Java缓存框架,支持在JVM和集群中缓存数据。
JCache (JSR-107)
Java平台的缓存API标准,提供了统一的缓存操作接口,使得开发者可以更容易地切换不同的缓存实现。
Redis
虽然Redis是一个独立的内存数据存储系统,但它经常与Java应用程序一起使用作为缓存层。Redis支持多种数据结构,并提供了丰富的操作命令,非常适合作为分布式缓存解决方案。
Memcached
一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。
Hazelcast
一个开源的Java内存数据网格,提供了分布式缓存、计算、消息传递等功能。
如何选择缓存
在选择缓存技术时,需要考虑应用程序的需求、数据量、访问模式、数据一致性要求以及系统的扩展性等因素。
例如,对于需要分布式缓存的场景,Redis或Hazelcast可能是更好的选择;而对于简单的本地缓存需求,Guava Cache或Caffeine可能更为合适。
缓存的使用中,也会遇到一些问题,特别是缓存穿透、缓存击穿和缓存雪崩,在使用缓存时,应充分考虑分析,最大限度的避免这三种问题。
缓存穿透
缓存穿透是指查询一个不存在的数据,由于缓存也没有该数据,因此每次请求都会直接打到数据库上,而数据库也没有该数据。这样就造成了缓存和数据库都没有起到应该有的作用,每次请求都要去数据库查询。
图解

解决策略
缓存空对象
当一个不存在的数据请求过来时,缓存层不直接返回null,而是缓存一个空对象。但这个空对象也需要设置一个较短的过期时间,防止数据长时间占用缓存。
布隆过滤器
布隆过滤器是一种数据结构,它利用位数组来表示集合,并允许一定的误判率。通过布隆过滤器,可以快速地判断一个请求的数据是否存在于数据库中,从而避免不必要的数据库查询。
集合过滤
采用缓存集合替代缓存单个对象的方式。
当表内数据量不大,需要根据特定条件做过滤后,判断数据是否合法或获取单条数据时,可采用此种策略,只需确保获取集合的sql语句一定可以查出至少一条记录即可。
此方式是一种有效消除缓存穿透的推荐策略。
缓存击穿
缓存击穿是指某个热点数据(key非常热点)过期时,由于并发用户特别多,同时读缓存没读到数据,都去数据库查询,引起数据库压力瞬间增大,造成过多请求直接打到数据库上。
图解

与缓存穿透的区别
缓存穿透是查询不存在的数据导致的问题;缓存击穿则是查询的数据存在,但因热点数据过期导致的问题
解决策略
互斥锁
使用分布式锁,保证对于每个key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,因此只需要等待即可。这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大。
永远不过期
没有设置过期时间,所以不会出现热点key过期后产生的问题。但这也带来了另外的问题,就是缓存的数据如何更新?此时可以通过消息队列来更新缓存,或者定期使用线程池来更新缓存。
缓存雪崩
缓存雪崩是指在同一时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求直接打到数据库上,瞬间压垮数据库。这通常是由于缓存过期时间设置不当或者缓存服务出现故障导致的。
图解

与缓存击穿的区别
缓存击穿是单个或少量热点数据(key)失效;缓存雪崩则是大量缓存同时失效。
缓存击穿对应用服务的感知较小;缓存雪崩可导致应用服务不可用。
解决策略
缓存预热
在系统启动或者低峰时,将热点数据预先加载到缓存中,避免在系统高峰时请求直接打到数据库上。
分布式缓存
使用Redis集群等分布式缓存系统,避免单点故障,提高系统的可用性和容错能力。
降级策略
当缓存系统出现问题时,可以启动降级策略,比如返回默认数据或者提示用户稍后重试,以减轻对数据库的压力。
三者之间的区别
发生场景
缓存击穿是热点数据过期导致的问题;
缓存穿透是查询不存在的数据导致的问题;
缓存雪崩则是大量缓存同时失效或缓存服务故障导致的问题。
影响范围
缓存击穿和缓存穿透通常影响的是单个或多个特定的数据请求;而缓存雪崩则可能影响整个系统的性能和稳定性。
解决策略
虽然三者都可以通过一些通用的策略进行缓解,如使用互斥锁、缓存预热等,但针对每种问题的特定场景和原因,还需要采取更具体的解决策略。
总结
缓存是在Java开发中,提升应用服务性能必不可少的策略,常用的缓存,有本地应用服务缓存和redis缓存,为了使更新后的数据能及时被使用,一般会给缓存设置一定的有效期,设置了有效期的缓存,可能会存在缓存击穿和缓存雪崩的情况,而查询数据库不存在的数据时,又会引起缓存穿透的问题。在详细了解了缓存使用时存在缓存问题的原因后,可以分别针对不同的问题,采用不同的策略,来避免或降低缓存问题对系统性能的影响,从而确保应用服务的高可用性。
原文始发于微信公众号(扬哥手记):说说缓存穿透、击穿、雪崩的区别及如何避免
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/263215.html