当前位置: 首页 > news >正文

Guava Cache 高性能本地缓存库详解与使用案例

Guava Cache 高性能本地缓存库详解与使用案例


一、Guava Cache 简介

1.1 什么是 Guava Cache?

Guava Cache 是 Google 提供的 Java 本地缓存库,是 Google Guava 工具库的一部分。它提供了灵活且高效的缓存管理功能,适用于需要高性能、低延迟的本地缓存场景。核心特性包括:

  • 基于大小和时间的缓存驱逐
  • 软引用/弱引用支持
  • 缓存统计(命中率、加载次数等)
  • 手动刷新与异步加载
  • 缓存监听器

Guava Cache 适用于单体应用、微服务中的本地缓存需求,尤其适合对缓存性能要求较高的场景。


二、核心特性详解

2.1 依赖引入

Maven
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.1-jre</version>
</dependency>
Gradle
implementation 'com.google.guava:guava:31.1-jre'

2.2 缓存构建器 CacheBuilder

Guava Cache 的核心是通过 CacheBuilder 构建缓存实例,支持链式配置。

2.2.1 基本缓存创建
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;Cache<String, String> cache = CacheBuilder.newBuilder()
.maximumSize(100)// 最大缓存大小
.build();
2.2.2 基于时间的过期策略
  • 写入后过期(expireAfterWrite):元素在写入后指定时间过期。
  • 访问后过期(expireAfterAccess):元素在最后一次访问后指定时间过期。
Cache<String, String> cache = CacheBuilder.newBuilder()
.maximumSize(100)
.expireAfterWrite(10, TimeUnit.MINUTES)// 写入后10分钟过期
.expireAfterAccess(5, TimeUnit.MINUTES)// 最后一次访问后5分钟过期
.build();
2.2.3 基于大小的驱逐策略

Guava 使用 LRU(Least Recently Used) 算法管理缓存大小。

Cache<String, String> cache = CacheBuilder.newBuilder()
.maximumSize(1000)// 缓存最多存储1000个元素
.build();
2.2.4 软引用/弱引用
  • 软引用(Soft References):在 JVM 内存不足时回收。
  • 弱引用(Weak References):在下一次 GC 时回收。
Cache<String, String> cache = CacheBuilder.newBuilder()
.maximumSize(100)
.softValues()// 值使用软引用
.weakKeys()// 键使用弱引用
.build();
2.2.5 缓存统计

启用统计功能可获取命中率、加载次数等信息。

Cache<String, String> cache = CacheBuilder.newBuilder()
.maximumSize(100)
.recordStats()// 启用统计
.build();// 获取统计信息
CacheStats stats = cache.stats();
System.out.println("命中率: " + stats.hitRate());
2.2.6 手动刷新与异步加载
  • 手动刷新refresh(key) 强制刷新指定缓存项。
  • 异步加载:结合 LoadingCache 实现异步加载。
LoadingCache<String, String> loadingCache = CacheBuilder.newBuilder()
.maximumSize(100)
.build(new CacheLoader<String, String>() {
@Override
public String load(String key) throws Exception {
return fetchFromDB(key);// 从数据库加载
}
});// 异步加载
String value = loadingCache.get("key");

2.3 缓存监听器

通过 RemovalListener 监听缓存项被驱逐或过期。

Cache<String, String> cache = CacheBuilder.newBuilder()
.maximumSize(100)
.removalListener((RemovalListener<String, String>) notification -> {
System.out.println("Key: " + notification.getKey() + " 被移除,原因: " + notification.getCause());
})
.build();

三、使用案例详解

3.1 单体应用缓存

场景:用户信息缓存
public class UserService {
private final LoadingCache<String, User> userCache = CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build(new CacheLoader<String, User>() {
@Override
public User load(String userId) throws Exception {
return fetchUserFromDB(userId);// 从数据库加载
}
});public User getUser(String userId) {
try {
return userCache.get(userId);// 自动加载或从缓存获取
} catch (ExecutionException e) {
throw new RuntimeException("缓存加载失败", e);
}
}private User fetchUserFromDB(String userId) {
// 模拟数据库查询
return new User(userId, "User_" + userId);
}
}
优势:
  • 减少数据库压力:高频查询直接命中缓存。
  • 自动刷新:Guava 自动管理缓存更新。

3.2 分布式系统中的本地缓存

场景:结合 Redis 的二级缓存

Guava Cache 作为本地缓存,Redis 作为分布式缓存。

public class DistributedCache {
private final Cache<String, String> localCache = CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterWrite(5, TimeUnit.MINUTES)
.build();public String get(String key) {
String value = localCache.getIfPresent(key);
if (value == null) {
value = fetchFromRedis(key);
if (value == null) {
value = fetchFromDB(key);
saveToRedis(key, value);
}
localCache.put(key, value);
}
return value;
}
}
优势:
  • 本地缓存加速:减少对 Redis 的直接访问。
  • 降级容错:Redis 不可用时可直接访问数据库。

3.3 Spring Boot 集成

1. 配置缓存 Bean
@Configuration
public class CacheConfig {
@Bean
public Cache<String, String> myCache() {
return CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build();
}
}
2. 使用缓存
@Service
public class MyService {
@Autowired
private Cache<String, String> myCache;public String getData(String key) {
String value = myCache.getIfPresent(key);
if (value == null) {
value = fetchFromExternalService(key);
myCache.put(key, value);
}
return value;
}
}

四、性能优化技巧

4.1 避免缓存雪崩

  • 随机过期时间:为缓存设置随机过期时间,避免大量缓存同时失效。
  • 热点数据预加载:对高频访问的数据主动加载到缓存。
// 随机过期时间(需结合自定义逻辑)
Cache<String, String> cache = CacheBuilder.newBuilder()
.maximumSize(1000)
.build();

4.2 缓存命中率优化

  • 合理设置大小:根据业务访问模式调整 maximumSize
  • 监控统计:定期分析 hitRate()evictionCount(),调整策略。
CacheStats stats = cache.stats();
System.out.println("命中率: " + stats.hitRate());

4.3 内存管理

  • 软引用值(softValues):在 JVM 内存不足时自动回收缓存。
  • 定期清理:使用 cleanUp() 手动触发清理。
cache.cleanUp(); // 手动清理过期缓存

五、常见问题与解决方案

5.1 缓存穿透(Cache Penetration)

问题:查询不存在的数据导致频繁访问数据库。
解决方案

  • 布隆过滤器(Bloom Filter):拦截不存在的键。
  • 空值缓存:对查询结果为空的键设置短暂缓存。
String value = cache.get(key, () -> {
String result = fetchFromDB(key);
if (result == null) {
cache.put(key, "");// 缓存空值
}
return result;
});

5.2 缓存击穿(Cache Breakdown)

问题:热点数据过期后大量请求直接访问数据库。
解决方案

  • 互斥锁(Mutex Lock):仅允许一个线程重建缓存。
  • 永不过期:热点数据设置永不过期,定时异步更新。
String value = cache.get(key, () -> {
synchronized (key.intern()) {
if (cache.getIfPresent(key) == null) {
String result = fetchFromDB(key);
cache.put(key, result);
return result;
}
}
return cache.getIfPresent(key);
});

5.3 缓存雪崩(Cache Avalanche)

问题:大量缓存同时失效,导致数据库压力激增。
解决方案

  • 随机过期时间:为缓存设置随机过期时间。
  • 分层缓存:本地缓存 + Redis 分布式缓存。

六、Guava Cache 与 Caffeine 对比

特性Guava CacheCaffeine
算法LRU(较简单)Window TinyLFU(更高命中率)
异步加载不支持(需手动实现)支持 AsyncLoadingCache
统计功能基本统计详细统计(命中率、加载次数等)
性能一般(适合中等规模应用)更高吞吐量和更低延迟
维护状态已停止更新(推荐使用 Caffeine)活跃维护

七、总结

Guava Cache 是 Java 生态中经典的本地缓存库,其 灵活配置、稳定性和易用性 使其成为许多项目的首选。通过合理配置缓存策略,开发者可以显著提升系统性能,减少对数据库的依赖。尽管 Caffeine 在性能上更优,但 Guava Cache 仍然是许多遗留项目和中等规模应用的可靠选择。


八、参考资料

  • Guava 官方文档:https://github.com/google/guava
  • Guava Cache 最佳实践:https://www.baeldung.com/java-guava-cache
  • Guava 与 Caffeine 对比:https://github.com/ben-manes/caffeine/wiki/Guava
http://www.dtcms.com/a/452858.html

相关文章:

  • 开源安全管理平台wazuh-阻止恶意IP访问
  • 蒲城做网站网站定制开发成本
  • 嵌入式开发入门:从 FreeRTOS 任务到通信协议(详细教程)
  • 数据结构(长期更新)第2讲:顺序表(一)
  • 《Flask 的“微”哲学:从轻量内核到请求上下文的深度剖析》
  • 在 Elasticsearch 中改进 Agentic AI 工具的实验
  • Solid Explorer(双窗格文件管理器) 解锁完整版
  • 做外贸自己的公司网站wordpress头像设置方法
  • Java学习之旅第二季-9:包
  • 大数据毕业设计选题推荐-基于大数据的人类健康生活方式数据分析与可视化系统-大数据-Spark-Hadoop-Bigdata
  • 图像处理实践:自定义直方图变换函数的优化与问题解决
  • 人力资源管理的思维方式学习笔记7-final
  • JavaEE初阶——线程安全(多线程)
  • [工作流节点16] 更新他表记录的自动化方案:跨表数据联动的关键实现
  • 南京金融网站建设wordpress热门文章调用
  • 针对 OpenMMLab 视频理解(分类)的 MMAction2 的环境配置
  • 中国电信用户行为实时分析系统运维实战
  • HTTP、WebSocket、XMPP、CoAP、MQTT、DDS 六大协议在机器人通讯场景应用
  • 长春网站制作招聘信息上海网站被查
  • 做自媒体视频搬运网站网站建设与管理淘宝
  • IP 协议的相关特性
  • 《投资-88》价值投资者的认知升级与交易规则重构 - 第三层:估值安全边际,“再好的公司,如果买贵了,也会变成一笔糟糕的投资。”
  • 工程师 - Raspberry Pi Pico程序:读取SPI数据后从串口输出
  • 虚幻引擎5 GAS开发俯视角RPG游戏 P04-12 可缩放浮点数的曲线表
  • 接口请求工具对比 apifox apipost swagger postman等
  • C++联合体(Union)详解:与结构体的区别、联系与深度解析
  • LangChain部署RAG part2.搭建多模态RAG引擎(赋范大模型社区公开课听课笔记)
  • SSM--day4--SpringMVC(补充)
  • Flink Checkpoint与反压问题排查手册:从日志分析到根因定位
  • 元宇宙的教育应用:重构学习体验与知识传递