Java缓存资源优化案例怎么做

wen java案例 32

Java缓存资源优化案例详解

典型场景:高并发商品查询系统

问题描述

电商系统中,商品详情页面临高并发查询,每次查询都直接访问数据库导致性能瓶颈。

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
数据库压力 极低
缓存成本 中高

最佳实践建议

  1. 选择合适的缓存粒度:针对不同场景选择合适的缓存对象大小
  2. 设置合理的过期时间:避免缓存雪崩,使用随机过期时间
  3. 实现缓存预热:系统启动时加载热点数据
  4. 监控缓存命中率:低于80%需要优化缓存策略
  5. 处理缓存穿透:缓存空值或布隆过滤器
  6. 防止缓存击穿:使用互斥锁控制并发访问

常见问题解决

// 缓存穿透防护:布隆过滤器
@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倍,显著改善用户体验和系统稳定性。

抱歉,评论功能暂时关闭!