赞
踩
缓存是一种将数据临时存储在更快的存储层以提高应用程序的性能和响应能力的技术。
第一级缓存通常是特定于应用程序单个实例的内存缓存。此缓存将数据存储在应用程序实例本地,从而最大限度地减少了重复访问较慢存储层(例如数据库)的需要。常见的内存缓存库包括 Caffeine、Guava 和 Ehcache。第一级缓存的特点:
单个应用程序实例的本地
通过内存存储实现快速访问
非持久性,通常受应用程序内存的限制
不跨多个实例共享数据
第二级缓存是分布式缓存,它允许应用程序的多个实例共享缓存数据。这种类型的缓存通常使用外部缓存系统(如 Redis、Memcached 或 Hazelcast)实现。分布式缓存有助于在不同应用程序实例之间维护缓存数据的一致性和可用性。第一级缓存的特点:
• 跨多个应用程序实例共享
• 可以持久化,确保重启后数据可用
• 与内存缓存相比,支持更大的数据量
需要网络访问,与内存缓存相比可能会带来延迟
第一级缓存通常是内存中的缓存,它将数据存储在单个应用程序实例中。我们可以使用 Caffeine,这是一个基于 Java 的高性能缓存库。Caffeine 提供内存缓存,其功能受到 Google Guava 的启发。它旨在高效、灵活且友好,提供各种缓存驱逐策略、加载机制和其他高级功能。以下是一些强大的功能,使 Caffeine 成为 Java 应用程序中缓存的热门选择:
高性能:Caffeine 旨在提供快速高效的缓存,具有低延迟和高吞吐量。
灵活的驱逐策略:Caffeine 支持各种驱逐策略,例如基于大小的驱逐,基于时间的驱逐和基于引用的驱逐。
自动加载:Caffeine 可以自动将条目加载到缓存中,减少了手动缓存管理的复杂性。
异步操作:Caffeine 支持异步缓存加载和驱逐,提高应用程序的性能和响应能力。
统计和监控:Caffeine 提供内置的收集缓存统计信息支持,帮助开发人员监控和优化缓存性能。
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-cache</artifactId>
- </dependency>
-
- <dependency>
- <groupId>com.github.ben-manes.caffeine</groupId>
- <artifactId>caffeine</artifactId>
- </dependency>
使用注释在主应用程序类中启用缓存 @EnableCaching
- @SpringBootApplication
- @EnableCaching
- public class Application {
- public static void main(String[] args) {
- SpringApplication.run(Application.class, args);
- }
- }
CacheManager 在你的配置类中使用 Caffeine 定义一个 Bean
@Configuration
注释,表明该类在 Spring 应用程序中作为配置类。
缓存管理器:
定义一个名为 cacheManager()
并返回 CacheManager 实例的 Bean
创建一个 CaffeineCacheManager
名为 items
的实例
使用特定属性设置 Caffeine 缓存:初始容量为 100、最大为 500、访问时间(10分钟)后到期
返回已配置的缓存管理器实例
- @Configuration
- public class CacheConfig {
-
- @Bean
- public CacheManager cacheManager() {
- CaffeineCacheManager cacheManager = new CaffeineCacheManager("items");
- cacheManager.setCaffeine(Caffeine.newBuilder()
- .initialCapacity(100)
- .maximumSize(500)
- .expireAfterAccess(10, TimeUnit.MINUTES));
- return cacheManager;
- }
- }
@Cacheable注解
添加 @Cacheable
注解到需要缓存的方法上
- @Service
- public class ItemService {
-
- @Cacheable("items")
- public Item getItemById(Long id) {
- try {
- Thread.sleep(3000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- return new Item(id, "ItemName");
- }
- }
第二级缓存是分布式缓存,它允许应用程序的多个实例共享缓存数据。Redis 是此目的的合适选择。
Redis 是一个开源的内存数据结构存储,可用作数据库、缓存和消息代理。它支持各种数据结构,包括字符串、哈希、列表、集合、有序集、位图和具有半径查询的地理空间索引。Redis 以其高性能、灵活性和广泛的功能集而闻名,在各种应用程序中都受到青睐。
Redis 拥有多项强大的功能,使其在各种用例中广受欢迎:
内存存储:Redis 将数据存储在内存中,确保快速的读写操作。
持久性:Redis 支持各种持久性机制,将数据存储在磁盘上,提供持久性。
数据结构:Redis 支持丰富的数据结构,允许进行多种数据操作。
复制:Redis支持主从复制,增强数据可用性和可扩展性。
高可用性:Redis Sentinel 提供高可用性和监控,确保自动故障转移。
集群支持:Redis 集群支持跨多个节点对数据进行水平分区。
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-redis</artifactId>
- </dependency>
配置
- spring.redis.host=localhost
- spring.redis.port=6379
定义 Redis 缓存管理器
创建一个配置类来设置 Redis 缓存管理器:
• 配置:定义一个 RedisConfig
配置类。
• Redis 连接工厂 Bean:定义一个 redisConnectionFactory()
的 Bean 方法。此方法返回一个 RedisConnectionFactory
对象,该对象是可以创建 Redis 连接的工厂 Bean 的接口。它指定应该 LettuceConnectionFactory
使用来创建 Redis 连接。
• Redis 模板 Bean:定义一个 redisTemplate()
的 Bean 方法。此方法返回一个对象,该对象提供 Redis 数据访问方法。它使用先前定义的方法 RedisTemplate<String, Object>
为 Redis 模板设置连接工厂redisConnectionFactory()
。
• 缓存管理器 Bean:定义一个 cacheManager()
的 Bean 方法。此方法配置并返回一个对象,用于管理应用程序中的缓存。它使用指定默认缓存配置设置,例如条目生存时间 (TTL) 持续时间。它使用配置的缓存默认值构建并返回一个对象。
- @Configuration
- public class RedisConfig extends CachingConfigurerSupport {
-
- @Bean
- public RedisConnectionFactory redisConnectionFactory() {
- return new LettuceConnectionFactory();
- }
-
- @Bean
- public RedisTemplate redisTemplate() {
- RedisTemplate template = new RedisTemplate();
- template.setConnectionFactory(redisConnectionFactory());
- return template;
- }
-
- @Bean
- @Override
- public CacheManager cacheManager() {
- RedisCacheConfiguration cacheConfig = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(10));
- return RedisCacheManager.builder(redisConnectionFactory())
- .cacheDefaults(cacheConfig)
- .build();
- }
- }
我们可以使用 Caffeine 和 Redis 的组合来实现一个简单的两级缓存。
配置:该类带有注解 @Configuration
,表明它是一个 Spring 配置类。
该类扩展了 CachingConfigurerSupport
,意味着它为 Spring 应用程序中的缓存提供了自定义配置。
Redis 连接工厂:定义一个名为 redisConnectionFactory()
的 Bean,返回一个 LettuceConnectionFactory
,它是 Lettuce 提供的 Redis 连接工厂实现。
Redis 模板:定义一个名为 redisTemplate()
的 Bean,返回一个 RedisTemplate<String, Object>
。
缓存管理器:设置复合缓存管理器来管理 Caffeine 和 Redis 缓存管理器。
- @Configuration
- public class TwoLevelCacheConfig extends CachingConfigurerSupport {
-
- @Bean
- public RedisConnectionFactory redisConnectionFactory() {
- return new LettuceConnectionFactory();
- }
-
- @Bean
- public RedisTemplate redisTemplate() {
- RedisTemplate template = new RedisTemplate();
- template.setConnectionFactory(redisConnectionFactory());
- return template;
- }
-
- @Bean
- public CacheManager cacheManager() {
- CompositeCacheManager cacheManager = new CompositeCacheManager();
- CaffeineCacheManager caffeineCacheManager = new CaffeineCacheManager("items");
- caffeineCacheManager.setCaffeine(Caffeine.newBuilder()
- .initialCapacity(100)
- .maximumSize(500)
- .expireAfterAccess(10, TimeUnit.MINUTES));
-
- RedisCacheConfiguration redisCacheConfig = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(10));
- RedisCacheManager redisCacheManager = RedisCacheManager.builder(redisConnectionFactory()).cacheDefaults(redisCacheConfig).build();
-
- cacheManager.setCacheManagers(Arrays.asList(caffeineCacheManager, redisCacheManager));
- return cacheManager;
- }
-
- }
集成测试验证缓存机制是否按预期工作:
测试 whenCacheMiss_thenDataIsFetchedFromService()
方法被定义为评估缓存功能。
启动一个计时器来测量执行时间,然后从中获取 ID 为 1 的项目 ItemService,预计缓存未命中,因为这是该项目的初始请求。然后,该方法计算此操作所花费的时间,并断言它超过了 3000 毫秒,表明缓存未命中。
随后,再次获取同一项,预计这次缓存命中。该方法断言第二个请求所花费的时间少于 100 毫秒,确认缓存命中。
通过此测试,验证的缓存行为 ItemService,确保缓存命中和未命中的缓存功能正确。
- @SpringBootTest
- @AutoConfigureMockMvc
- @ActiveProfiles("test")
- public class CacheIntegrationTest {
-
- @Autowired
- private ItemService itemService;
-
- @Test
- public void whenCacheMiss_thenDataIsFetchedFromService() {
- long start = System.currentTimeMillis();
- Item item1 = itemService.getItemById(1L);
- long timeTaken = System.currentTimeMillis() - start;
- assertTrue(timeTaken > 3000); // 缓存未命中
-
- start = System.currentTimeMillis();
- Item item2 = itemService.getItemById(1L);
- timeTaken = System.currentTimeMillis() - start;
- assertTrue(timeTaken < 100); // 缓存命中
- }
- }
了解一级和二级缓存的概念对于优化应用程序的性能至关重要。一级缓存提供对单个实例中频繁访问的数据的快速内存访问,而二级缓存提供跨多个实例的共享分布式解决方案。通过结合这些缓存策略,可以实现速度和可扩展性之间的平衡。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。