1.guava cache和caffeine cache流程分析和总结
2.本地缓存无冕之王Caffeine Cache
3.Java高性能缓存-CaffeineCache
4.Redis+Caffeine两级缓存,让访问速度更加流畅
5.④优雅的缓存框架:SpringCache之多级缓存
6.caffeine_redis二级缓存实现Spring接口
guava cache和caffeine cache流程分析和总结
本文将对Java中两种常用的缓存相关流程进行分析与总结,即Guava Cache和Caffeine。
在缓存机制中,我们通常会将数据缓存在内存或快速设备中,以便在获取数据时减少对慢速设备的芋道源码 怎么阅读源码访问,提高系统性能。Guava Cache采用了一种在获取数据时可以免锁的机制,对于内存缓存的数据,get操作可以避免锁的使用。这一特性是通过原子替换的方式实现的,即在操作哈希表的冲突链时,不会修改冲突链,因此并发的get操作仍然可以获取到完整的数据。插入和删除操作仅涉及新建或复制冲突链,利用Java的垃圾回收(GC)机制,不再使用的entry将被GC回收。以下是一个插入和删除操作的示例,其中“4’”代表“4”的原子替换操作。
Guava Cache的实现细节可以在github.com/google/guava... 查阅。
Caffeine是一个基于Java8开发的高性能缓存库,它在缓存和ConcurrentMap之间提供了一定的灵活性。ConcurrentMap会持有所有加入到缓存中的元素,直到它们被手动移除。而Caffeine的缓存Cache通常会配置为自动驱逐缓存中的元素以限制内存使用。在某些场景下,LoadingCache和AsyncLoadingCache因其自动加载缓存的能力变得非常实用。
Caffeine提供了一个灵活的构造器来创建具有特定特性的缓存,包括但不限于:
缓存和ConcurrentMap有些相似,但它们之间存在根本区别:ConcurrentMap将持有所有加入缓存中的元素直到手动移除,而Caffeine的缓存Cache通常配置为自动驱逐元素以限制内存占用。
在Caffeine中,写Buffer和读Buffer具有不同的设计和使用场景。读Buffer在高并发读取的场景下具有优势,允许延迟或丢失某些操作,而写Buffer在写操作时不允许丢失,要求尽快执行。Caffeine使用MPSC(Multiple Producer / Single Consumer)作为缓冲数组,实现MpscGrowableArrayQueue类,此设计借鉴了开源项目JCTools的MpscGrowableArrayQueue。
MPSC允许无锁的高并发写入,但只允许一个消费者,这牺牲了部分操作效率。
Caffeine中的W-TinyLFU(Wide Tiny Least Frequently Used)缓存策略使用了三个LRU队列:新写入的数据被放入WINDOW队列,试用期队列为PROBATION,而保护队列PROTECTED用于存放访问频率较高的元素。WINDOW队列的大小占1%,而PROTECTED队列占%,其中%为保护队列,%为试用期队列。
元素从一个队列迁移到另一个队列的逻辑遵循特定规则,根据访问频率进行调整。此外,Caffeine使用Count-Min Sketch算法记录访问频率,这是一种布隆过滤器的变种。Count-Min Sketch使用二维数组实现,但Caffeine只使用了一维数组。对于数值类型的频率记录,通常使用int或long存储,访客机系统源码Caffeine认为访问频率不需要达到太高的值,一般认为次视为较高频率,且提供了一种机制来使频率衰退减半。对于达到最大频率值的table,元素值将减少一半。
Caffeine的LICENSE遵循Apache License 2.0。
对比Guava Cache和Caffeine,两种缓存解决方案在功能和性能上各有优势和不足。Guava Cache在免锁机制方面表现突出,但具体功能实现细节需要查阅相关文档。Caffeine提供更灵活的缓存配置选项,并在内存使用和自动驱逐策略方面提供了更多灵活性。用户在选择缓存库时应根据具体需求和场景进行权衡。
本地缓存无冕之王Caffeine Cache
Caffeine Cache,作为本地缓存领域的佼佼者,以其高性能和可扩展性赢得了“本地缓存之王”的美誉。它是一个专为Java设计的缓存库,旨在优化计算速度、内存效率和实用性,满足现代软件开发的迫切需求。在Spring Boot 1.x版本中,Guava Cache是默认的本地缓存选项,然而,随着Spring5(SpringBoot 2.x版本)的发布,Spring官方选择性能更优的Caffeine作为默认缓存组件,这无疑是对Caffeine的巨大肯定。
本文将深入探讨Caffeine Cache的特性和应用,并指导如何将其无缝集成至您的项目中。在解析Caffeine Cache之前,我们先来了解一下缓存淘汰算法。一个优秀的淘汰算法对于提升缓存效率至关重要。其中,先进先出(FIFO)算法依据数据进入缓存的顺序进行淘汰,而最近最少使用(LRU)和最不经常使用的(LFU)算法则基于数据的访问频率和时间进行决策。在Caffeine中,采用了一种称为“Window TinyLFU”的淘汰策略,它在面临缓存换页问题时,通过统计频率信息来选择最佳的候选项进行替换,从而实现了近乎最佳的命中率。
Caffeine提供了四种类型的缓存,每种类型对应着不同的加载策略,分别为普通缓存、自动加载缓存、异步缓存和异步加载缓存。普通缓存无需指定加载方式,通过手动调用`put()`方法进行加载;自动加载缓存允许在缓存不存在或已过期时自动调用`CacheLoader.load()`方法加载最新值;异步缓存的响应结果均为`CompletableFuture`,适用于异步编程;而异步加载缓存则是自动加载与异步操作的结合,支持以异步方式自动加载缓存。
在处理缓存淘汰策略时,Caffeine提供了基于大小、基于时间、基于引用的三种回收策略,以满足不同场景的需求。基于大小的策略分为基于缓存大小和基于权重两种方式,而基于时间的策略则包括了短时过期、长期过期和永久过期等选项。基于引用的策略则依赖于Java中的四种引用类型,包括强引用、分销系统的源码软引用、弱引用和虚引用。
为了确保数据持久性,Caffeine提供了`CacheWriter`方法,允许将缓存中的所有数据写入到第三方存储中,避免数据在服务重启时丢失。同时,Caffeine内置了数据收集功能,通过`Caffeine.recordStats()`方法打开数据收集功能,进而使用`Cache.stats()`方法获取缓存的统计指标,如命中率、容量使用情况等。
在SpringBoot项目中集成Caffeine Cache相对简单。首先,您需要在`pom.xml`文件中添加Spring Boot Starter Cache和Caffeine的Maven依赖。然后,创建一个配置类并创建`CacheManager` Bean,根据需求配置Caffeine的参数。您可以选择使用建造者模式或配置文件的方式进行配置。配置完成后,使用注解`@Cacheable`、`@CachePut`、`@CacheEvict`等进行缓存操作。
注解使用方式丰富多样,包括了`@Cacheable`、`@CachePut`和`@CacheEvict`等,这些注解允许您指定缓存的名称、键生成器、过期时间、同步模式等配置。此外,Spring Cache还支持Spring Expression Language (SpEL) 表达式,通过SpEL可以在缓存名称或键中插入动态值。
在多线程环境下,您可以通过设置`sync=true`来实现缓存同步模式,确保只有一个线程执行方法并将结果存储在缓存中,避免缓存击穿问题。Caffeine支持基于大小、基于时间、基于引用的回收策略,使得缓存管理更加灵活。同时,Caffeine还提供了写入外部存储和数据收集功能,确保数据的持久性和性能监控。
总之,Caffeine Cache以其强大的功能和高效的设计,在本地缓存领域占据领先地位。通过本文的介绍,您不仅能够深入了解Caffeine Cache的工作原理和特性,还能够掌握如何在SpringBoot项目中有效集成和利用Caffeine Cache。希望本文能够为您的项目带来性能上的提升,并激发您在缓存管理方面的创新思考。
如果您有任何关于Caffeine Cache的疑问或需要进一步的帮助,请随时通过微信公众号「Java 随想录」与我联系。期待与您共同探讨Java技术的精彩世界。
Java高性能缓存-CaffeineCache
Java高性能缓存库CaffeineCache是一款强大的内存缓存解决方案,旨在提升应用程序的数据访问速度。其突出特点包括:高效性能: CaffeineCache运用高效数据结构和算法,pcm与源码区别通过堆外内存和快速哈希表,减少内存和CPU开销,实现快速的缓存访问。
内存管理: 提供灵活配置选项,如最大缓存大小、条目数和过期策略,适应不同应用程序的需求。
策略多样性: 支持多种缓存策略,如时间、大小、引用和自定义策略,以优化应用程序的特定需求。
异步加载: 通过异步接口和回调机制,实现并发加载,减少缓存未命中时的延迟。
缓存监听: 提供缓存事件监听,确保缓存一致性,便于应用程序响应缓存变化。
尽管CaffeineCache功能强大,但也存在一些限制,如内存消耗大、不支持分布式缓存的强一致性、依赖于时间的过期策略等。在选择使用时,需根据具体场景权衡其优点和不足。 如何使用CaffeineCache呢?首先添加库依赖,然后在Spring Boot项目中配置Caffeine Cache,通过@Cacheable注解轻松集成到你的代码中。如需自定义缓存容量或淘汰策略,可以深入理解其提供的配置选项和接口。Redis+Caffeine两级缓存,让访问速度更加流畅
在高性能的服务架构设计中,缓存是一个不可或缺的环节。通过使用 Redis 或 MemCache 等缓存中间件存储热点数据,能显著提升访问速度并降低数据库压力。随着技术的发展,单一的远程缓存架构已不足以满足需求,引入本地缓存作为补充成为可能。这样,通过结合本地缓存如 Guava Cache 或 Caffeine,以及远程缓存如 Redis,形成两级缓存架构,能进一步提升程序响应速度与服务性能。
两级缓存架构的实现流程可简单表示如下:首先,访问本地缓存获取数据,若未命中,再尝试访问远程缓存;若远程缓存也未命中,则最终查询数据库并更新缓存。
使用两级缓存相比单纯使用远程缓存,主要优势在于数据访问速度的提升,以及对数据库压力的减轻。然而,在设计过程中还需考虑数据一致性问题,以及缓存过期时间、过期策略、多线程访问等复杂因素。
在代码层面,实现两级缓存管理主要涉及以下步骤:使用如 Caffeine 的源码资本股东变更本地缓存和 Redis 作为远程缓存,整合后通过 Spring Boot 项目搭建环境,并配置 Redis 连接信息。接下来,通过 V1.0 版本实现手动操作缓存逻辑,包括在业务代码中注入和使用缓存,实现数据的读取和存储。
V1.0 版本示例中,首先创建 Cache 对象并配置参数,如过期时间。然后在业务方法中使用 get 方法检查缓存,若命中则直接返回数据;若未命中,则执行数据库查询并更新缓存。通过测试验证了缓存的有效性,包括数据访问、修改和删除场景。
V2.0 版本则利用 Spring 的 CacheManager 和注解简化缓存操作,使得业务代码更加简洁,同时利用 @Cacheable、@CachePut 和 @CacheEvict 注解自动管理缓存,减少手动操作的负担。此外,V3.0 版本通过自定义注解与切面编程实现对业务代码完全无入侵的缓存管理,进一步优化了代码结构,增强了可维护性。
总结而言,针对不同业务需求和架构设计,合理使用本地缓存与远程缓存的结合,能够有效提升系统性能与响应速度。在实际应用中,还需综合考虑数据一致性、并发控制、缓存策略等问题,以实现更为稳定、高效的服务架构。
④优雅的缓存框架:SpringCache之多级缓存
多级缓存策略能够显著提升系统响应速度并减轻二级缓存压力。本文采用Redis作为二级缓存,Caffeine作为一级缓存,通过多级缓存的设计实现优化。
首先,进行多级缓存业务流程图的声明,并通过LocalCache注解对一级缓存进行管理。具体源码地址如下。
其次,自定义CaffeineRedisCache,进一步优化缓存性能。相关源码地址提供如下。
为了确保缓存机制的正确执行,自定义CacheResolver并将其注册为默认的cacheResolver。具体实现细节可参考以下源码链接。
在实际应用中,通过上述自定义缓存机制,能够有效地提升系统性能和用户体验。为了验证多级缓存优化效果,我们提供实战应用案例和源码。相关实战案例和源码如下链接。
实现多级缓存策略的完整源码如下:
后端代码:<a href="github.com/L1yp/van-tem...
前端代码:<a href="github.com/L1yp/van-tem...
欲加入交流群讨论更多技术内容,点击链接加入群聊: Van交流群
caffeine_redis二级缓存实现Spring接口
在项目优化阶段,发现缓存机制对提升性能至关重要。尤其在数据更新主要由数据人员流程驱动,而非频繁操作的场景中,使用切面编程和自定义注解成为实现缓存的合适方式。接下来,我们将探讨如何实现通用型的二级缓存,实现Spring接口规范。
在研究过程中,JSR/JCache缓存机制得到了解。这些规范提供了一致的缓存接口,让不同厂商的实现兼容。Spring Cache抽象类层次结构图展示了这一整合机制。
为了实现二级缓存,我们基于Spring中的`AbstractValueAdaptingCache`抽象接口,通过继承该接口来实现所需的缓存逻辑。该接口为缓存操作提供了基础封装,简化了实现过程。集成Redis等缓存解决方案时,`Cache`和`Redis`相关属性成为必要,通过`Properties`类实现配置的可扩展性和灵活性。
`lookup`方法在使用`@Cacheable`注解时执行,用于查询缓存数据。与之紧密相关的`put`方法则在更新数据或数据不存在于缓存中时调用,确保数据一致性。`evict`方法用于删除指定缓存数据,并通知其他节点进行同步更新。`clear`方法则负责清理所有缓存数据,同样触发节点间的数据同步。
在实际应用中,应考虑禁用`redis.keys`命令以避免安全风险,因此使用`scan`命令替代,确保数据安全性。`get`方法在使用缓存注解时不会直接调用,而是依赖父类的实现确保数据同步。
`CacheManager`类作为缓存管理器,负责初始化和维护缓存实例。在方法调用时,首先通过管理器获取缓存实例,确保操作的一致性和协调性。当数据发生变动时,通过`getCache`方法实现分布式缓存管理,确保数据的一致性。
测试环节中,构建了简单的Controller来验证`@Cacheable`、`@CachePut`、`@CacheEvict`和`@CacheClear`等注解在实际应用中的效果。通过集成测试,确保了缓存机制在不同场景下的正确性和高效性。
综上所述,通过合理设计和实现二级缓存机制,结合Spring接口规范和Redis等缓存解决方案,可以有效提升项目性能,实现数据的高效管理和一致性控制。在此过程中,充分考虑安全性和扩展性,确保系统在实际部署中的稳定性和可靠性。
本地缓存解决方案-Caffeine Cache
本地缓存解决方案:Caffeine Cache Caffeine Cache是Google Guava Cache的Java 8版本重写,旨在提高效率与性能。其支持基于容量、时间和引用的缓存回收策略。Caffeine提供了一个灵活的缓存构造器CacheBuilder,可通过此构建器轻松配置各种参数,实现丰富多样的本地缓存方案。 相比于IO操作,Caffeine Cache能提供更快的速度和更高的效率。相较于分布式缓存Redis,Caffeine Cache更适用于本地场景,因其避免了网络延迟的影响,更符合“近水救火”的原则。结合数据库和本地缓存的使用,能够实现高效存储与访问。 Caffeine Cache基于LRU算法实现,支持多种缓存过期策略。在Spring Boot 2.0中,Caffeine Cache将取代Guava成为默认缓存方案。使用Caffeine Cache
在Spring Boot 2.0项目中集成Caffeine Cache,可以使用以下步骤:准备工作
搭建Spring Boot 2.x项目,集成MyBatis与MySQL数据库。java工程
添加依赖
在项目的pom.xml文件中添加Caffeine Cache依赖。配置类
引入CaffeineCacheConfig配置类,设置缓存配置。配置文件
Caffeine配置文件中定义缓存参数,如缓存名称、大小、过期时间等。实体类
定义与数据库交互的实体类。mapper
编写Mapper接口,用于数据库操作。service
实现服务层逻辑,调用Mapper执行数据库操作。controller
编写Controller处理HTTP请求,集成缓存注解。启动类
定义主启动类,配置Spring Boot应用。运行
运行应用,使用Postman进行测试。在接口上添加@Cacheable注解启用缓存,@CachePut和@CacheEvict注解用于缓存更新与清除。 启动应用后,通过Postman发送请求,观察IDEA控制台输出。首次请求从数据库获取数据,随后在短时间内再次请求,观察缓存启用与失效的效果,如缓存时效为秒。学习使用本地缓存Caffeine
Caffeine是一个基于Java 8的高性能缓存库。其内部实现基于Java进程内存,提供多种构建策略生成Cache容器,包括Cache、LoadingCache、AsyncCache和AsyncLoadingCache实例的构造器(Builder)。默认情况下,Caffeine创建的缓存实例不执行任何类型回收。
Caffeine的Cache实例被实现为哈希表,具有与ConcurrentHashMap相似的性能特征。其asMap视图及其集合视图具有弱一致性迭代器,安全地在并发使用,但如果其他线程在迭代器创建之后修改缓存,这些修改在迭代器中是否反映出来是不确定的。
默认情况下,返回的缓存使用equals方法来确定键或值的相等。如果指定了weakKeys,则缓存对键使用identity比较。同样,如果指定了weakValues或softValues,缓存将对值进行标识比较。
当应用maximumSize、maximumWeight、expireAfter、expireAfterWrite、expireAfterAccess、weakKeys、weakValues或softvalue时,缓存项在符合条件时将自动从缓存中删除。使用maximumSize或maximumWeight时,缓存项可能在每次缓存修改时被清除。expireAfter、expireAfterWrite或expireAfterAccess应用时,缓存项可能在每次缓存修改、偶尔的缓存访问或调用Cache.cleanUp时被清除。Caffeine支持使用Scheduler及时删除过期缓存项,而不是等待定期维护。
如果使用弱键、弱值或软值,缓存中存在的键或值可能会被垃圾收集器回收。带有回收键或值的缓存项在每次缓存修改、偶尔的缓存访问或调用cache . cleanup时从缓存中删除。缓存的估计大小计算包括这些项,但对读写操作来说是不可见的。
某些缓存配置可能导致定期维护任务的积累,这些任务在写操作期间执行,或在没有写操作的情况下,偶尔的读操作也可能导致执行。Cache实例的Cache.cleanUp方法将执行维护。只有使用maximumSize、maximumWeight、expireAfter、expireAfterWrite、expireAfterAccess、weakKeys、weakvalue或softvalue构建的缓存才能进行定期维护。
Caffeine生成的缓存是可序列化的,反序列化的缓存保留原始缓存的所有配置属性。请注意,序列化表单不包括缓存内容,只包括配置。
开发者建议:不要依赖缓存过期时间来实现业务逻辑。就像JVM的垃圾回收机制触发具有不确定性一样,Caffeine的回收策略也是复杂且不确定的。可以假定设置了淘汰机制的缓存项将在未来的某段时间将过期,但不能确定究竟在什么时间点、什么操作发生前被回收,除非主动操作删除。
Caffeine的方法包括newBuilder、initialCapacity、maximumSize、expireAfterWrite、expireAfterAccess、refreshAfterWrite、build、removalListener和writer。newBuilder构造默认设置的Caffeine实例。initialCapacity设置内部数据结构的最小容量。maximumSize指定缓存可以包含的最大缓存项数量。expireAfterWrite和expireAfterAccess自动从缓存中删除缓存项。refreshAfterWrite在创建后一段时间内若没有被写入,重新构建(refresh)缓存项。build构建缓存容器。removalListener指定一个监听器在每次删除缓存项时接受通知。writer指定写入器在创建或修改缓存项时通知该写入器。
Caffeine的容器接口包括Cache、LoadingCache、AsyncCache和AsyncLoadingCache。Cache键到值的半持久化映射,手动添加缓存项,直到清除或手动使其失效为止。LoadingCache键到值的半持久化映射,值由缓存自动加载,直到删除或手动使其失效为止。AsyncCache键到值的半持久化映射,手动添加缓存项,直到清除或手动使其失效为止。AsyncLoadingCache键到值的半持久化映射,缓存自动异步加载值,直到删除或手动使其失效为止。
Cache容器方法包括get、getIfPresent、put和invalidate。get返回与键相关联的值,必要时从CacheLoader.load(Object)获取。getIfPresent返回与此缓存中的键关联的值,如果没有键的缓存值,则返回null。put将值与此缓存中的键关联,替换旧值。invalidate丢弃键的任何缓存值。cleanUp执行任何当前有必要执行的维护操作。
在Spring boot maven项目中,引入Caffeine依赖。编写测试案例,运行结果表明,Caffeine设置最大缓存数量后,读取时删除缓存项,命中数略大于预设值,因为清理是通过定期维护任务触发的。增大读写数量,测试并发达到每秒万次。
在CacheTest中演示了Caffeine的使用,设计为全局资源的单例模式,使用Spring框架的Bean注入,以在程序进程间共享。在并发环境下,Cache容器的使用显著降低了连续数据库请求的频率,穿透访问数降低。测试请求返回结果每分钟变化一次,验证了缓存效果。
进程级缓存是解决高并发问题的手段之一,在分布式环境中,还需结合Redis等分布式缓存技术。
本地缓存天花板— caffeine了解下?
在重构公司项目的过程中,遇到了高并发挑战,我们已采用Redis作为数据库,但为确保性能,决定引入本地缓存。众多组件中,我们选择了Caffeine,一款据称性能远超Guava的组件。Caffeine被描述为高性能、最优的缓存库,源自Guava并进行优化,使用ConcurrentLinkedHashMap等设计。
添加Caffeine到项目中,首先需要在Maven项目中添加依赖。Caffeine提供了四种缓存添加策略,官方文档提供中文版,方便理解和使用。不过,版本需与JDK对应,否则可能会出现版本不兼容的错误。
使用Caffeine,可以手动通过get、put、invalidate等接口进行操作,文档详细说明了这些接口的功能。例如,cache.get(key, k -> value)通过原子计算插入缓存,如果生成元素失败,可能会返回null。此外,Caffeine还提供了LoadingCache的自动加载,以及AsyncCache的异步加载功能,可根据需求定制线程池。
缓存的属性参数至关重要,如maximumSize控制缓存大小和缓存策略,expireAfterWrite、expireAfterAccess和expireAfter定义了缓存的过期时间,refreshAfterWrite则设置刷新缓存的策略。详细配置需参考官方文档。
尽管官方文档展示了Caffeine的强大性能,真正的效果还需在实际项目中检验。由于篇幅限制,我们仅分享了基础内容,深入理解和应用还需读者自行探索。实践是检验真理的唯一标准,Caffeine是否适合,还需大家亲自测试验证。
探索之路无止境,希望这篇文章为你们提供了关于Caffeine的基本理解和入门指导。- 结束 -