Redis + Caffeine多級緩存
- Redis + Caffeine多級緩存電商場景深度解析
- 一、實施目的
- 二、具體實施
- 2.1 架構設計
- 2.2 組件配置
- 2.3 核心代碼實現
- 三、實施效果
- 3.1 性能指標對比
- 3.2 業務指標改善
- 3.3 系統穩定性
- 四、關鍵策略
- 4.1 緩存預熱
- 4.2 一致性保障
- 4.3 監控配置
- Prometheus監控指標
- 電商多級緩存完整實現方案
- 1. 基礎配置
- 1.1 Maven依賴
- 1.2 配置文件
- 2. 核心實現類
- 2.1 緩存配置類
- 2.2 商品服務實現
- 2.3 庫存服務實現
- 3. 輔助組件
- 3.1 緩存預熱
- 3.2 監控端點
- 關鍵點說明
- 1. 多級緩存流程
- 2. 緩存策略
- 3. 一致性保障
- 4. 監控能力
- 5. 性能優化
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. 多級緩存流程
- 先查Caffeine本地緩存
- 未命中則查Redis
- 仍未命中則查數據庫
- 回填各級緩存
2. 緩存策略
數據類型 | 本地緩存TTL | Redis TTL |
---|---|---|
商品數據 | 60秒 | 30-90分鐘(隨機) |
庫存數據 | 10秒 | 10秒 |
3. 一致性保障
- 使用
@CacheEvict
保證更新時緩存失效 - 庫存采用短過期時間自動刷新
4. 監控能力
- 通過
/cache/stats
端點暴露緩存命中率 - 集成Spring Boot Actuator
5. 性能優化
- 并行預熱熱點數據
- Redis連接池配置
- 本地緩存大小控制