现代应用开发中,性能和可扩展性是决定系统成败的关键因素。缓存通过减少数据库负载、降低延迟和确保无缝用户体验,在提升这些方面发挥着关键作用。然而,没有一种单一的缓存解决方案能够完美适应所有场景。
本地缓存(例如 Caffeine)由于在内存中运行并靠近应用程序,因此能够提供极快的速度。它们非常适合减少频繁访问数据的响应时间。另一方面,分布式缓存(例如使用 Redis 的 Redisson)在应用程序的多个实例之间提供可扩展性和一致性。分布式缓存确保分布式系统中的所有节点访问相同最新的数据,这在多节点环境中至关重要。
然而,仅仅依赖本地或分布式缓存都会带来挑战:
这就是 混合缓存成为有效解决方案的地方。通过结合使用 Caffeine 和 Redisson 的本地和分布式缓存的优势,您可以获得本地缓存速度带来的高性能,同时利用分布式缓存保持一致性和可扩展性。
本文探讨如何在 Spring Boot 应用程序中实现混合缓存,以确保最佳性能和数据一致性。
首先,将必要的依赖项添加到您的 pom.xml
文件中:
<code class="language-xml"><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> <version>3.2.0</version> </dependency> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.43.0</version> </dependency></code>
以下是缓存配置:
<code class="language-java">@Configuration @EnableCaching public class CacheConfig implements CachingConfigurer { @Value("${cache.server.address}") private String cacheAddress; @Value("${cache.server.password}") private String cachePassword; @Value("${cache.server.expirationTime:60}") private Long cacheExpirationTime; @Bean(destroyMethod = "shutdown") RedissonClient redisson() { Config config = new Config(); config.useSingleServer().setAddress(cacheAddress).setPassword(cachePassword.trim()); config.setLazyInitialization(true); return Redisson.create(config); } @Bean @Override public CacheManager cacheManager() { CaffeineCacheManager cacheManager = new CaffeineCacheManager(); cacheManager.setCaffeine(Caffeine.newBuilder().expireAfterWrite(cacheExpirationTime, TimeUnit.MINUTES)); return cacheManager; } @Bean public CacheEntryRemovedListener cacheEntryRemovedListener() { return new CacheEntryRemovedListener(cacheManager()); } @Bean @Override public CacheResolver cacheResolver() { return new LocalCacheResolver(cacheManager(), redisson(), cacheEntryRemovedListener()); } }</code>
CacheManager
负责管理缓存的生命周期,并提供对适当缓存实现(例如本地或分布式)的访问。在本例中,我们使用 CaffeineCacheManager
来启用内存缓存,并通过 Caffeine
配置过期策略。
CacheResolver
动态地确定要对特定操作使用哪个缓存。在这里,LocalCacheResolver
连接本地(Caffeine)和分布式(Redisson)缓存,确保有效应用混合策略。
<code class="language-java">@Component public class LocalCacheResolver implements CacheResolver { // ... (代码与原文相同) ... }</code>
<code class="language-java">public class LocalCache implements Cache { // ... (代码与原文相同) ... }</code>
CacheEntryRemovedListener
监听从分布式缓存(Redis)中移除的条目,并确保它们也从各个节点的本地缓存中移除,从而保持一致性。
<code class="language-xml"><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> <version>3.2.0</version> </dependency> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.43.0</version> </dependency></code>
当执行用 @Cacheable
注解的方法时,将调用 put
方法。这会将数据存储在本地缓存 (Caffeine) 和分布式缓存 (Redis) 中:
<code class="language-java">@Configuration @EnableCaching public class CacheConfig implements CachingConfigurer { @Value("${cache.server.address}") private String cacheAddress; @Value("${cache.server.password}") private String cachePassword; @Value("${cache.server.expirationTime:60}") private Long cacheExpirationTime; @Bean(destroyMethod = "shutdown") RedissonClient redisson() { Config config = new Config(); config.useSingleServer().setAddress(cacheAddress).setPassword(cachePassword.trim()); config.setLazyInitialization(true); return Redisson.create(config); } @Bean @Override public CacheManager cacheManager() { CaffeineCacheManager cacheManager = new CaffeineCacheManager(); cacheManager.setCaffeine(Caffeine.newBuilder().expireAfterWrite(cacheExpirationTime, TimeUnit.MINUTES)); return cacheManager; } @Bean public CacheEntryRemovedListener cacheEntryRemovedListener() { return new CacheEntryRemovedListener(cacheManager()); } @Bean @Override public CacheResolver cacheResolver() { return new LocalCacheResolver(cacheManager(), redisson(), cacheEntryRemovedListener()); } }</code>
要检索数据,系统首先检查本地缓存中是否存在该键。如果找不到该键,则查询分布式缓存。如果分布式缓存中存在该值,则将其添加到本地缓存中,以便更快地进行后续访问:
<code class="language-java">@Component public class LocalCacheResolver implements CacheResolver { // ... (代码与原文相同) ... }</code>
当发生缓存驱逐时(例如,通过 @CacheEvict
注解),该键将从分布式缓存中移除。其他节点的本地缓存将通过 CacheEntryRemovedListener
收到通知,以移除相同的键:
<code class="language-java">public class LocalCache implements Cache { // ... (代码与原文相同) ... }</code>
混合缓存结合了本地内存缓存的速度和分布式缓存的可扩展性和一致性。这种方法解决了仅使用本地或分布式缓存的局限性。通过在 Spring Boot 应用程序中集成 Caffeine 和 Redisson,您可以实现显著的性能改进,同时确保应用程序节点之间的数据一致性。
使用 CacheEntryRemovedListener
和 CacheResolver
可以确保缓存条目在所有缓存层之间保持同步,为现代可扩展应用程序提供高效且可靠的缓存策略。这种混合方法在分布式系统中尤其宝贵,因为在这些系统中,性能和一致性都至关重要。
以上是春季启动中的混合缓存策略:Redisson和咖啡因整合的指南的详细内容。更多信息请关注PHP中文网其他相关文章!