电商系统核心诉求是高并发、高可用、数据一致性,面对商品详情海量查询、秒杀瞬时下单、库存超卖等场景,传统数据库架构极易出现性能瓶颈、数据错乱。Redis作为内存型中间件,凭借超快读写速度、原子操作和分布式能力,成为电商架构的核心支撑。

本篇聚焦电商最关键的三大场景:商品热点缓存、库存精准扣减、分布式锁防冲突,从业务分析、方案设计、核心代码到异常兜底,全流程讲解Redis实战落地,解决电商高并发下的性能与数据一致性难题。

核心定位:Redis承接电商前端高并发流量,做查询层提速、交易层护航,既保证接口响应毫秒级,又杜绝超卖、重复下单等业务故障。

一、场景一:商品热点缓存 —— 扛住海量查询,减轻DB压力

商品详情、分类列表、活动商品等读多写少场景,日均请求量可达百万级,直接查询数据库会导致IO阻塞、接口超时。通过Redis缓存热点商品数据,能将接口响应时间从数百毫秒降至10ms以内,数据库压力降低90%以上。

1. 缓存设计核心原则

  • 数据分层缓存:基础信息(标题、价格、主图)用String/Hash,规格、库存等高频变更数据单独缓存
  • 设置过期时间:避免脏数据,采用随机过期防止缓存雪崩
  • 缓存穿透防护:空值缓存、布隆过滤器拦截无效商品ID
  • 缓存更新策略:先更新数据库,再删除缓存,保证数据最终一致

2. 商品详情缓存实战(Hash结构)

选用Hash结构存储商品详情,可灵活更新单个字段(如价格、库存),无需全量替换,节省内存与带宽。

/**
 * 商品详情缓存Key规范
 */
private static final String GOODS_DETAIL_KEY = "goods:detail:%s";
// 缓存过期时间(2小时)
private static final long GOODS_EXPIRE = 7200;
// 缓存空值过期时间(1分钟),防止穿透
private static final long NULL_EXPIRE = 60;

/**
 * 查询商品详情:先查缓存,缓存未命中查数据库
 */
public Map<String, Object> getGoodsDetail(Long goodsId) {
    String key = String.format(GOODS_DETAIL_KEY, goodsId);
    // 1. 查询Redis缓存
    Map<Object, Object> cacheMap = redisTemplate.opsForHash().entries(key);
    if (CollUtil.isNotEmpty(cacheMap)) {
        // 缓存空值判断,避免穿透
        if (cacheMap.containsKey("isEmpty")) {
            return null;
        }
        return new HashMap<>(cacheMap);
    }

    // 2. 缓存未命中,查询数据库
    Map<String, Object> goodsDetail = goodsMapper.getGoodsDetail(goodsId);
    if (CollUtil.isEmpty(goodsDetail)) {
        // 空值写入缓存,防止穿透
        redisTemplate.opsForHash().put(key, "isEmpty", "true");
        redisTemplate.expire(key, NULL_EXPIRE, TimeUnit.SECONDS);
        return null;
    }

    // 3. 写入Redis缓存,设置随机过期时间(防止雪崩)
    redisTemplate.opsForHash().putAll(key, goodsDetail);
    redisTemplate.expire(key, GOODS_EXPIRE + new Random().nextInt(600), TimeUnit.SECONDS);
    return goodsDetail;
}

/**
 * 更新商品信息:先更DB,再删缓存
 */
@Transactional(rollbackFor = Exception.class)
public boolean updateGoodsInfo(Map<String, Object> params, Long goodsId) {
    // 1. 更新数据库
    boolean updateSuccess = goodsMapper.updateGoods(params, goodsId) > 0;
    if (updateSuccess) {
        // 2. 删除缓存,下次查询加载新数据
        String key = String.format(GOODS_DETAIL_KEY, goodsId);
        redisTemplate.delete(key);
    }
    return updateSuccess;
}

3. 缓存避坑要点

  • 禁止缓存全量商品,仅缓存热点、活动商品,节省内存
  • 大字段(商品详情富文本)尽量剥离,避免BigKey导致性能下降
  • 配合缓存监控,命中率低于90%时优化缓存策略

二、场景二:库存扣减 —— 原子操作,杜绝超卖

库存是电商核心数据,超卖会导致商家亏损、客诉纠纷,普通数据库扣减存在行锁竞争、并发冲突问题。Redis基于单线程原子命令,能实现高并发下库存精准扣减,从根源杜绝超卖。

1. 库存缓存设计方案

  • 库存预热:商品上架/活动开始前,将库存从DB同步至Redis(String结构)
  • 原子扣减:使用DECRBY命令原子扣减,无锁竞争
  • 库存回补:订单取消/超时未支付,通过INCR命令回补库存
  • 最终一致性:Redis扣减成功后,异步同步至数据库,保证数据一致

2. 库存扣减实战代码

/**
 * 库存缓存Key规范
 */
private static final String GOODS_STOCK_KEY = "goods:stock:%s";

/**
 * 活动前:库存预热到Redis
 */
public void initGoodsStock(Long goodsId, Integer stockNum) {
    String key = String.format(GOODS_STOCK_KEY, goodsId);
    redisTemplate.opsForValue().set(key, stockNum);
}

/**
 * 库存扣减核心逻辑
 * @param goodsId 商品ID
 * @param buyNum 购买数量
 * @return true-扣减成功 false-库存不足/扣减失败
 */
public boolean deductStock(Long goodsId, Integer buyNum) {
    String key = String.format(GOODS_STOCK_KEY, goodsId);
    // 1. 原子扣减库存(核心:DECRBY保证原子性,无并发冲突)
    Long remainStock = redisTemplate.opsForValue().decrement(key, buyNum);

    // 2. 库存不足判断,立即回滚
    if (remainStock < 0) {
        redisTemplate.opsForValue().increment(key, buyNum);
        return false;
    }

    // 3. 异步同步库存至数据库,保证最终一致
    asyncUpdateDbStock(goodsId, remainStock.intValue());
    return true;
}

/**
 * 订单取消/超时:库存回补
 */
public void revertStock(Long goodsId, Integer buyNum) {
    String key = String.format(GOODS_STOCK_KEY, goodsId);
    redisTemplate.opsForValue().increment(key, buyNum);
    // 异步同步数据库
    asyncUpdateDbStock(goodsId, null);
}

三、场景三:分布式锁 —— 解决并发冲突,保障业务安全

分布式架构下,多服务、多节点同时操作库存/订单,会出现重复下单、超卖、库存错乱问题。单机锁(synchronized)失效,需借助Redis分布式锁实现跨服务互斥,保证业务原子性。

1. 分布式锁核心要求

  • 互斥性:同一时间只有一个线程持有锁
  • 防死锁:设置锁过期时间,线程宕机自动释放锁
  • 防误删:仅锁持有者可解锁,避免误删他人锁
  • 可重入:同一线程可重复加锁,避免死锁

2. 生产级分布式锁实战(Redisson)

手写分布式锁存在超时、误删等坑,生产环境直接使用Redisson框架,封装完善的可重入锁、看门狗自动续期机制,稳定可靠。

/**
 * 注入Redisson客户端
 */
@Autowired
private RedissonClient redissonClient;

/**
 * 分布式锁扣减库存(秒杀/下单核心)
 */
public boolean createOrder(Long userId, Long goodsId, Integer buyNum) {
    String lockKey = String.format("lock:goods:%s", goodsId);
    // 获取可重入锁
    RLock lock = redissonClient.getLock(lockKey);

    try {
        // 尝试加锁:等待时间10s,锁自动过期时间30s
        boolean tryLock = lock.tryLock(10, 30, TimeUnit.SECONDS);
        if (!tryLock) {
            // 加锁失败,并发冲突
            return false;
        }

        // 加锁成功,执行业务逻辑
        // 1. 校验库存
        Integer stock = redisTemplate.opsForValue().get(String.format(GOODS_STOCK_KEY, goodsId));
        if (stock == null || stock < buyNum) {
            return false;
        }
        // 2. 扣减库存
        boolean deductSuccess = deductStock(goodsId, buyNum);
        if (!deductSuccess) {
            return false;
        }
        // 3. 创建订单
        return orderMapper.createOrder(userId, goodsId, buyNum) > 0;

    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        return false;
    } finally {
        // 解锁:仅当前线程持有锁时解锁
        if (lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }
}

3. 分布式锁避坑要点

  • 禁止使用SETNX+EXPIRE分开执行,必须用原子命令(Redisson底层已实现)
  • 锁粒度尽量细,仅锁定单个商品,而非全局锁,提升并发效率
  • 开启Redisson看门狗机制,避免业务未执行完锁过期
  • 集群环境使用RedLock红锁,防止主从切换丢锁导致超卖

四、三大场景整合方案与生产优化

1. 电商核心流程闭环

  1. 用户查询商品 → Redis缓存命中,快速返回详情
  2. 用户下单 → 分布式锁加锁 → Redis原子扣减库存
  3. 创建订单 → 释放锁 → 异步同步库存至数据库
  4. 订单取消 → 库存回补 → 更新数据库

2. 生产环境优化建议

  • Redis集群部署(主从+哨兵/Cluster),保证高可用
  • 库存缓存设置过期时间,定期与数据库校准
  • 加入库存预警,低于阈值触发告警
  • 缓存预热、降级、熔断联动,应对流量突刺
场景Redis数据类型核心技术核心价值
商品缓存Hash/String缓存穿透/雪崩防护、延时双删海量查询提速、减轻DB压力
库存扣减String原子DECRBY/INCR、异步同步高并发精准扣减、杜绝超卖
分布式锁StringRedisson可重入锁、看门狗跨服务互斥、解决并发冲突

核心总结:Redis是电商高并发架构的核心,商品缓存负责“提速”,库存扣减负责“精准”,分布式锁负责“安全”,三者配合实现高性能、高一致、高可用的电商系统。

结语

电商场景复杂多变,Redis的应用远不止缓存、库存、锁三大模块,还可延伸至购物车、订单限流、排行榜等业务。实际落地时,需结合业务体量调整缓存策略、锁粒度和过期时间,做好监控与兜底,才能让Redis稳定支撑业务增长。

发表回复