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

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


一、Guava Cache 简介

1.1 什么是 Guava Cache?

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

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

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


二、核心特性详解

2.1 依赖引入

Maven
xml 复制代码
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.1-jre</version>
</dependency>
Gradle
groovy 复制代码
implementation 'com.google.guava:guava:31.1-jre'

2.2 缓存构建器 CacheBuilder

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

2.2.1 基本缓存创建
java 复制代码
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):元素在最后一次访问后指定时间过期。
java 复制代码
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) 算法管理缓存大小。

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

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

java 复制代码
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 实现异步加载。
java 复制代码
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 监听缓存项被驱逐或过期。

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

三、使用案例详解

3.1 单体应用缓存

场景:用户信息缓存
java 复制代码
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 作为分布式缓存。

java 复制代码
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
java 复制代码
@Configuration
public class CacheConfig {
@Bean
public Cache<String, String> myCache() {
return CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build();
}
}
2. 使用缓存
java 复制代码
@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 避免缓存雪崩

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

4.2 缓存命中率优化

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

4.3 内存管理

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

五、常见问题与解决方案

5.1 缓存穿透(Cache Penetration)

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

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

5.2 缓存击穿(Cache Breakdown)

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

  • 互斥锁(Mutex Lock):仅允许一个线程重建缓存。
  • 永不过期:热点数据设置永不过期,定时异步更新。
java 复制代码
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 Cache Caffeine
算法 LRU(较简单) Window TinyLFU(更高命中率)
异步加载 不支持(需手动实现) 支持 AsyncLoadingCache
统计功能 基本统计 详细统计(命中率、加载次数等)
性能 一般(适合中等规模应用) 更高吞吐量和更低延迟
维护状态 已停止更新(推荐使用 Caffeine) 活跃维护

七、总结

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


八、参考资料

相关推荐
lang2015092815 分钟前
Java JSR 250核心注解全解析
java·开发语言
czhc114007566326 分钟前
协议 25
java·开发语言·算法
逆光的July27 分钟前
如何解决超卖问题
java
落花流水 丶33 分钟前
Java 集合框架完全指南
java
lang201509281 小时前
Java WebSocket API:JSR-356详解
java·python·websocket
jiang_changsheng1 小时前
环境管理工具全景图与深度对比
java·c语言·开发语言·c++·python·r语言
计算机学姐1 小时前
基于SpringBoot的民宿预定管理系统【三角色+个性化推荐算法+数据可视化统计】
java·vue.js·spring boot·mysql·信息可视化·intellij-idea·推荐算法
yaoxin5211231 小时前
314. Java Stream API - 使用 Collectors.partitioningBy() 分区元素
java·windows
noBt1 小时前
Windows IDEA 卡顿严重
java·ide·intellij-idea
h7ml1 小时前
淘宝返利软件的跨端同步架构:Java RESTful API+GraphQL满足Web/APP/小程序的多端数据需求
java·架构·restful