Redis + Caffeine多级缓存电商场景深度解析

Redis + Caffeine多级缓存

  • [Redis + Caffeine多级缓存电商场景深度解析](#Redis + Caffeine多级缓存电商场景深度解析)
    • 一、实施目的
    • 二、具体实施
      • [2.1 架构设计](#2.1 架构设计)
      • [2.2 组件配置](#2.2 组件配置)
      • [2.3 核心代码实现](#2.3 核心代码实现)
    • 三、实施效果
      • [3.1 性能指标对比](#3.1 性能指标对比)
      • [3.2 业务指标改善](#3.2 业务指标改善)
      • [3.3 系统稳定性](#3.3 系统稳定性)
    • 四、关键策略
      • [4.1 缓存预热](#4.1 缓存预热)
      • [4.2 一致性保障](#4.2 一致性保障)
      • [4.3 监控配置](#4.3 监控配置)
    • 电商多级缓存完整实现方案
      • [1. 基础配置](#1. 基础配置)
        • [1.1 Maven依赖](#1.1 Maven依赖)
        • [1.2 配置文件](#1.2 配置文件)
      • [2. 核心实现类](#2. 核心实现类)
        • [2.1 缓存配置类](#2.1 缓存配置类)
        • [2.2 商品服务实现](#2.2 商品服务实现)
        • [2.3 库存服务实现](#2.3 库存服务实现)
      • [3. 辅助组件](#3. 辅助组件)
        • [3.1 缓存预热](#3.1 缓存预热)
        • [3.2 监控端点](#3.2 监控端点)
      • 关键点说明
        • [1. 多级缓存流程](#1. 多级缓存流程)
        • [2. 缓存策略](#2. 缓存策略)
        • [3. 一致性保障](#3. 一致性保障)
        • [4. 监控能力](#4. 监控能力)
        • [5. 性能优化](#5. 性能优化)

Redis + Caffeine多级缓存电商场景深度解析

一、实施目的

  1. 性能优化

    • 降低商品详情页访问延迟
    • 提升系统整体吞吐量
  2. 成本控制

    • 减少Redis集群规模
    • 降低数据库查询压力
  3. 稳定性保障

    • 应对秒杀等高并发场景
    • 实现故障自动降级

二、具体实施

2.1 架构设计

用户请求 → Nginx → 应用服务器(Caffeine) → Redis集群 → MySQL/分库分表

2.2 组件配置

Caffeine配置

java 复制代码
spring.cache.caffeine.spec=maximumSize=50000,expireAfterWrite=60s,refreshAfterWrite=30s,recordStats

Redis集群配置

java 复制代码
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 核心代码实现

商品查询服务

java 复制代码
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);
            // 异步写入Redis
            executor.execute(() -> {
                redisTemplate.opsForValue().set(
                    redisKey, 
                    value,
                    60 + ThreadLocalRandom.current().nextInt(30),
                    TimeUnit.MINUTES
                );
            });
        }
        return value;
    });
    return detail;
}

库存扣减服务

java 复制代码
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 业务指标改善

  1. 秒杀场景

    • 下单成功率从35%提升至89%
    • 超卖问题完全杜绝
  2. 常规场景

    • 商品详情页加载时间从1.2s→180ms
    • 服务器成本降低40%

3.3 系统稳定性

  1. Redis故障时:

    • 核心商品仍可提供服务
    • 系统存活时间从<1分钟延长至30分钟
  2. 大促期间:

    • 流量波动减少70%
    • CPU负载降低55%

四、关键策略

4.1 缓存预热

java 复制代码
@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 一致性保障

java 复制代码
@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监控指标
java 复制代码
 name: cache_hit_rate
 expr: rate(caffeine_cache_hits_total[5m]) / (rate(caffeine_cache_hits_total[5m]) +  rate(caffeine_cache_misses_total[5m]))

 name: redis_latency
 expr: histogram_quantile(0.99, rate(redis_command_duration_seconds_bucket[1m]))

电商多级缓存完整实现方案

1. 基础配置

1.1 Maven依赖
java 复制代码
<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 配置文件
java 复制代码
spring:
  redis:
    host: 127.0.0.1
    port: 6379
    password: yourpassword
    lettuce:
      pool:
        max-active: 16
        max-wait: 1000ms
        max-idle: 8

caffeine:
  specs:
    productCache: maximumSize=10000,expireAfterWrite=60s,recordStats
    stockCache: maximumSize=5000,expireAfterWrite=10s

2. 核心实现类

2.1 缓存配置类
java 复制代码
@Configuration
@EnableCaching
public class CacheConfig {

    @Bean
    public 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;
    }

    @Bean
    public 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 商品服务实现
java 复制代码
@Service
public class ProductServiceImpl implements ProductService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Cacheable(cacheNames = "products", key = "#productId")
    @Override
    public 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 库存服务实现
java 复制代码
@Service
public class StockServiceImpl implements StockService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Cacheable(cacheNames = "stocks", key = "#productId")
    @Override
    public 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")
    @Override
    public boolean deductStock(Long productId, int quantity) {
        // 库存扣减逻辑
        return stockRepository.deductStock(productId, quantity);
    }
}

3. 辅助组件

3.1 缓存预热
java 复制代码
@Component
public class CacheWarmUp implements CommandLineRunner {

    @Autowired
    private ProductService productService;
    
    @Override
    public void run(String... args) {
        List<Long> hotProducts = Arrays.asList(1001L, 1002L, 1003L);
        hotProducts.parallelStream().forEach(productService::getProductDetail);
    }
}
3.2 监控端点
java 复制代码
@RestController
@RequestMapping("/cache")
public class CacheMonitorController {

    @Autowired
    private 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. 多级缓存流程
  1. 先查Caffeine本地缓存
  2. 未命中则查Redis
  3. 仍未命中则查数据库
  4. 回填各级缓存
2. 缓存策略
数据类型 本地缓存TTL Redis TTL
商品数据 60秒 30-90分钟(随机)
库存数据 10秒 10秒
3. 一致性保障
  1. 使用@CacheEvict保证更新时缓存失效
  2. 库存采用短过期时间自动刷新
4. 监控能力
  1. 通过/cache/stats端点暴露缓存命中率
  2. 集成Spring Boot Actuator
5. 性能优化
  1. 并行预热热点数据
  2. Redis连接池配置
  3. 本地缓存大小控制
相关推荐
teacher伟大光荣且正确11 分钟前
关于Qt QReadWriteLock(读写锁) 以及 QSettings 使用的问题
java·数据库·qt
钱彬 (Qian Bin)22 分钟前
项目实践13—全球证件智能识别系统(内网离线部署大模型并调用)
数据库·postgresql·fastapi·ubuntu24.04·离线部署·qwen3大模型
hgz071023 分钟前
索引的原理
数据库
尋有緣40 分钟前
力扣614-二级关注者
大数据·数据库·sql·oracle
TG:@yunlaoda360 云老大1 小时前
华为云国际站代理商的DDM支持哪些拆分算法?
数据库·算法·华为云
@淡 定1 小时前
主流缓存中间件对比:Redis vs Memcached
redis·缓存·中间件
咕噜企业分发小米1 小时前
腾讯云向量数据库的HNSW索引具体是如何构建和优化的?
数据库·云计算·腾讯云
l1t1 小时前
在postgres和duckdb中比较两个数组并只挑选不匹配的元素
数据库·sql·postgresql·数组·duckdb
阿佳举世无双1 小时前
快速启动redis
数据库·redis·缓存
星辰_mya1 小时前
redis主从同步-概览
数据库·redis·缓存