Redis + Caffeine多级缓存
Redis + Caffeine多级缓存电商场景深度解析
一、实施目的
-
性能优化
- 降低商品详情页访问延迟
- 提升系统整体吞吐量
-
成本控制
- 减少Redis集群规模
- 降低数据库查询压力
-
稳定性保障
- 应对秒杀等高并发场景
- 实现故障自动降级
二、具体实施
2.1 架构设计
用户请求 → Nginx → 应用服务器(Caffeine) → Redis集群 → MySQL/分库分表
2.2 组件配置
Caffeine配置:
spring.cache.caffeine.spec=maximumSize=50000,expireAfterWrite=60s,refreshAfterWrite=30s,recordStats
Redis集群配置:
spring.redis.cluster.nodes=192.168.1.101:6379,192.168.1.102:6379
spring.redis.lettuce.pool.max-active=500
spring.redis.lettuce.pool.max-wait=2000
2.3 核心代码实现
商品查询服务:
public ProductDetail getProductDetail(Long productId) {// 本地缓存查询ProductDetail detail = caffeineCache.get(productId, k -> {// Redis查询String redisKey = "pd:" + productId;ProductDetail value = redisTemplate.opsForValue().get(redisKey);if (value == null) {// 数据库查询value = productDao.findById(productId);// 异步写入Redisexecutor.execute(() -> {redisTemplate.opsForValue().set(redisKey, value,60 + ThreadLocalRandom.current().nextInt(30),TimeUnit.MINUTES);});}return value;});return detail;
}
库存扣减服务:
public boolean deductStock(Long productId, int num) {// 本地库存标记if (!localStockMark.tryLock(productId)) {return false;}try {// Redis原子扣减Long remain = redisTemplate.execute(new DefaultRedisScript<>("local stock = tonumber(redis.call('GET', KEYS[1]))\n" +"if stock >= tonumber(ARGV[1]) then\n" +" return redis.call('DECRBY', KEYS[1], ARGV[1])\n" +"else\n" +" return -1\n" +"end",Long.class),Collections.singletonList("stock:" + productId),String.valueOf(num));if (remain >= 0) {// 异步记录库存变更mq.sendStockMessage(productId, num);return true;}return false;} finally {localStockMark.unlock(productId);}
}
三、实施效果
3.1 性能指标对比
指标 | 单Redis架构 | 多级缓存架构 | 提升幅度 |
---|---|---|---|
平均响应时间 | 68ms | 9ms | 655% |
峰值QPS | 12万 | 85万 | 608% |
数据库查询量 | 100% | 8% | 减少92% |
3.2 业务指标改善
-
秒杀场景:
- 下单成功率从35%提升至89%
- 超卖问题完全杜绝
-
常规场景:
- 商品详情页加载时间从1.2s→180ms
- 服务器成本降低40%
3.3 系统稳定性
-
Redis故障时:
- 核心商品仍可提供服务
- 系统存活时间从<1分钟延长至30分钟
-
大促期间:
- 流量波动减少70%
- CPU负载降低55%
四、关键策略
4.1 缓存预热
@Scheduled(cron = "0 0 3 * * ?")
public void dailyPreheat() {List<Long> hotItems = hotProductService.predictHotItems();hotItems.parallelStream().forEach(id -> {ProductDetail detail = productDao.getDetail(id);caffeineCache.put(id, detail);redisTemplate.opsForValue().set("pd:" + id,detail,6, TimeUnit.HOURS);});
}
4.2 一致性保障
@Transactional
public void updateProduct(Product product) {// 1.删除缓存caffeineCache.invalidate(product.getId());redisTemplate.delete("pd:" + product.getId());// 2.更新数据库productDao.update(product);// 3.延迟双删executor.schedule(() -> {redisTemplate.delete("pd:" + product.getId());}, 1, TimeUnit.SECONDS);
}
4.3 监控配置
Prometheus监控指标
name: cache_hit_rateexpr: rate(caffeine_cache_hits_total[5m]) / (rate(caffeine_cache_hits_total[5m]) + rate(caffeine_cache_misses_total[5m]))name: redis_latencyexpr: histogram_quantile(0.99, rate(redis_command_duration_seconds_bucket[1m]))
电商多级缓存完整实现方案
1. 基础配置
1.1 Maven依赖
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>com.github.ben-manes.caffeine</groupId><artifactId>caffeine</artifactId><version>3.1.8</version></dependency>
</dependencies>
1.2 配置文件
spring:redis:host: 127.0.0.1port: 6379password: yourpasswordlettuce:pool:max-active: 16max-wait: 1000msmax-idle: 8caffeine:specs:productCache: maximumSize=10000,expireAfterWrite=60s,recordStatsstockCache: maximumSize=5000,expireAfterWrite=10s
2. 核心实现类
2.1 缓存配置类
@Configuration
@EnableCaching
public class CacheConfig {@Beanpublic CacheManager cacheManager() {CaffeineCacheManager cacheManager = new CaffeineCacheManager();cacheManager.registerCustomCache("products", Caffeine.from(caffeineProperties().getSpec("productCache")).build());cacheManager.registerCustomCache("stocks",Caffeine.from(caffeineProperties().getSpec("stockCache")).build());return cacheManager;}@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(factory);template.setKeySerializer(new StringRedisSerializer());template.setValueSerializer(new GenericJackson2JsonRedisSerializer());return template;}
}
2.2 商品服务实现
@Service
public class ProductServiceImpl implements ProductService {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;@Cacheable(cacheNames = "products", key = "#productId")@Overridepublic ProductDetail getProductDetail(Long productId) {String redisKey = "product:" + productId;ProductDetail detail = (ProductDetail) redisTemplate.opsForValue().get(redisKey);if (detail == null) {detail = loadFromDB(productId);redisTemplate.opsForValue().set(redisKey, detail,60 + ThreadLocalRandom.current().nextInt(30),TimeUnit.MINUTES);}return detail;}private ProductDetail loadFromDB(Long productId) {// 数据库查询实现return productRepository.findById(productId);}
}
2.3 库存服务实现
@Service
public class StockServiceImpl implements StockService {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;@Cacheable(cacheNames = "stocks", key = "#productId")@Overridepublic Integer getStock(Long productId) {String redisKey = "stock:" + productId;Integer stock = (Integer) redisTemplate.opsForValue().get(redisKey);if (stock == null) {stock = loadStockFromDB(productId);redisTemplate.opsForValue().set(redisKey,stock,10, TimeUnit.SECONDS);}return stock;}@CacheEvict(cacheNames = "stocks", key = "#productId")@Overridepublic boolean deductStock(Long productId, int quantity) {// 库存扣减逻辑return stockRepository.deductStock(productId, quantity);}
}
3. 辅助组件
3.1 缓存预热
@Component
public class CacheWarmUp implements CommandLineRunner {@Autowiredprivate ProductService productService;@Overridepublic void run(String... args) {List<Long> hotProducts = Arrays.asList(1001L, 1002L, 1003L);hotProducts.parallelStream().forEach(productService::getProductDetail);}
}
3.2 监控端点
@RestController
@RequestMapping("/cache")
public class CacheMonitorController {@Autowiredprivate CacheManager cacheManager;@GetMapping("/stats")public Map<String, Object> getCacheStats() {Map<String, Object> stats = new HashMap<>();CaffeineCache productsCache = (CaffeineCache) cacheManager.getCache("products");if (productsCache != null) {stats.put("products", productsCache.getNativeCache().stats());}return stats;}
}
关键点说明
1. 多级缓存流程
2. 缓存策略
数据类型 | 本地缓存TTL | Redis TTL |
---|---|---|
商品数据 | 60秒 | 30-90分钟(随机) |
库存数据 | 10秒 | 10秒 |
3. 一致性保障
- 使用
@CacheEvict
保证更新时缓存失效 - 库存采用短过期时间自动刷新
4. 监控能力
- 通过
/cache/stats
端点暴露缓存命中率 - 集成Spring Boot Actuator
5. 性能优化
- 并行预热热点数据
- Redis连接池配置
- 本地缓存大小控制