Java缓存资源优化案例详解
典型场景:高并发商品查询系统
问题描述
电商系统中,商品详情页面临高并发查询,每次查询都直接访问数据库导致性能瓶颈。

优化方案实现
本地缓存(Caffeine)
@Service
public class ProductService {
// 配置Caffeine缓存
private final Cache<String, Product> productCache = Caffeine.newBuilder()
.maximumSize(10000) // 最大缓存条目
.expireAfterWrite(10, TimeUnit.MINUTES) // 写入后10分钟过期
.recordStats() // 记录统计信息
.build();
@Autowired
private ProductRepository productRepository;
public Product getProduct(String productId) {
// 先从缓存获取
Product product = productCache.getIfPresent(productId);
if (product != null) {
return product;
}
// 缓存未命中,从数据库加载
product = productRepository.findById(productId)
.orElseThrow(() -> new ProductNotFoundException(productId));
// 放入缓存
productCache.put(productId, product);
return product;
}
// 缓存统计监控
public CacheStats getCacheStats() {
return productCache.stats();
}
}
Redis分布式缓存
@Service
public class ProductCacheService {
@Autowired
private StringRedisTemplate redisTemplate;
@Autowired
private ObjectMapper objectMapper;
// 缓存Key前缀
private static final String PRODUCT_CACHE_PREFIX = "product:";
private static final long CACHE_TTL = 30; // 分钟
public Product getProduct(String productId) {
String cacheKey = PRODUCT_CACHE_PREFIX + productId;
// 1. 查询Redis缓存
String cacheValue = redisTemplate.opsForValue().get(cacheKey);
if (cacheValue != null) {
// 缓存命中
return deserializeProduct(cacheValue);
}
// 2. 缓存未命中,查询数据库
Product product = queryFromDatabase(productId);
if (product == null) {
// 3. 防止缓存穿透:存储空值
redisTemplate.opsForValue().set(cacheKey, "NULL", 5, TimeUnit.MINUTES);
return null;
}
// 4. 更新缓存
redisTemplate.opsForValue().set(cacheKey,
serializeProduct(product),
CACHE_TTL,
TimeUnit.MINUTES);
return product;
}
// 缓存预热
@PostConstruct
public void preloadCache() {
List<Product> hotProducts = productRepository.findHotProducts();
hotProducts.forEach(product -> {
String cacheKey = PRODUCT_CACHE_PREFIX + product.getId();
redisTemplate.opsForValue().set(cacheKey,
serializeProduct(product),
CACHE_TTL,
TimeUnit.MINUTES);
});
}
}
多级缓存架构
@Service
public class MultiLevelCacheService {
// 一级缓存:本地堆缓存 (Caffeine)
private final Cache<String, Product> localCache = Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(1, TimeUnit.MINUTES)
.build();
// 二级缓存:Redis缓存
@Autowired
private RedisTemplate<String, Product> redisTemplate;
@Autowired
private ProductRepository productRepository;
public Product getProduct(String productId) {
String cacheKey = "product:" + productId;
// 第一步:查询本地缓存
Product product = localCache.getIfPresent(productId);
if (product != null) {
return product;
}
// 第二步:查询Redis缓存
product = redisTemplate.opsForValue().get(cacheKey);
if (product != null) {
// 回填本地缓存
localCache.put(productId, product);
return product;
}
// 第三步:查询数据库
product = productRepository.findById(productId)
.orElse(null);
if (product != null) {
// 回填Redis和本地缓存
redisTemplate.opsForValue().set(cacheKey, product, 30, TimeUnit.MINUTES);
localCache.put(productId, product);
}
return product;
}
}
缓存更新策略
主动更新策略
@Component
public class CacheUpdateStrategy {
@Autowired
private Cache<String, Product> localCache;
@Autowired
private RedisTemplate<String, String> redisTemplate;
@RabbitListener(queues = "product.update.queue")
public void handleProductUpdate(ProductUpdateEvent event) {
// 1. 更新数据库
productRepository.save(event.getProduct());
// 2. 删除缓存(下次查询自动加载)
String cacheKey = "product:" + event.getProductId();
localCache.invalidate(event.getProductId());
redisTemplate.delete(cacheKey);
// 3. 发送缓存失效消息到其他服务节点
sendCacheInvalidationMessage(event.getProductId());
}
}
缓存优化监控
@Component
public class CacheMonitor {
@Autowired
private MeterRegistry meterRegistry;
// 缓存命中率监控
public void recordCacheHit(String cacheName) {
meterRegistry.counter("cache.hits", "cache", cacheName).increment();
}
public void recordCacheMiss(String cacheName) {
meterRegistry.counter("cache.misses", "cache", cacheName).increment();
}
// 缓存大小监控
@Scheduled(fixedRate = 60000) // 每分钟
public void logCacheStats() {
CacheStats stats = productCache.stats();
log.info("Cache Stats - Hit Rate: {}, Eviction Count: {}, Load Time: {}",
stats.hitRate(),
stats.evictionCount(),
stats.averageLoadPenalty());
}
}
性能对比数据
| 指标 | 无缓存 | 本地缓存 | Redis缓存 | 多级缓存 |
|---|---|---|---|---|
| 平均响应时间 | 200ms | 5ms | 15ms | 3ms |
| QPS | 500 | 50000 | 20000 | 80000 |
| 数据库压力 | 高 | 低 | 中 | 极低 |
| 缓存成本 | 无 | 低 | 中 | 中高 |
最佳实践建议
- 选择合适的缓存粒度:针对不同场景选择合适的缓存对象大小
- 设置合理的过期时间:避免缓存雪崩,使用随机过期时间
- 实现缓存预热:系统启动时加载热点数据
- 监控缓存命中率:低于80%需要优化缓存策略
- 处理缓存穿透:缓存空值或布隆过滤器
- 防止缓存击穿:使用互斥锁控制并发访问
常见问题解决
// 缓存穿透防护:布隆过滤器
@Component
public class BloomFilterCache {
private BloomFilter<String> bloomFilter;
@PostConstruct
public void init() {
// 初始化布隆过滤器,预期数据量100万,误判率0.01
bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charset.defaultCharset()),
1000000, 0.01);
}
public boolean mightContain(String key) {
return bloomFilter.mightContain(key);
}
}
// 缓存击穿防护:互斥锁
public Product getProductWithLock(String productId) {
Product product = cache.get(productId);
if (product == null) {
synchronized (this) {
product = cache.get(productId);
if (product == null) {
product = db.query(productId);
cache.put(productId, product);
}
}
}
return product;
}
通过以上优化,可以将系统性能提升10-100倍,显著改善用户体验和系统稳定性。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播