电商系统核心诉求是高并发、高可用、数据一致性,面对商品详情海量查询、秒杀瞬时下单、库存超卖等场景,传统数据库架构极易出现性能瓶颈、数据错乱。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. 电商核心流程闭环
- 用户查询商品 → Redis缓存命中,快速返回详情
- 用户下单 → 分布式锁加锁 → Redis原子扣减库存
- 创建订单 → 释放锁 → 异步同步库存至数据库
- 订单取消 → 库存回补 → 更新数据库
2. 生产环境优化建议
- Redis集群部署(主从+哨兵/Cluster),保证高可用
- 库存缓存设置过期时间,定期与数据库校准
- 加入库存预警,低于阈值触发告警
- 缓存预热、降级、熔断联动,应对流量突刺
| 场景 | Redis数据类型 | 核心技术 | 核心价值 |
|---|---|---|---|
| 商品缓存 | Hash/String | 缓存穿透/雪崩防护、延时双删 | 海量查询提速、减轻DB压力 |
| 库存扣减 | String | 原子DECRBY/INCR、异步同步 | 高并发精准扣减、杜绝超卖 |
| 分布式锁 | String | Redisson可重入锁、看门狗 | 跨服务互斥、解决并发冲突 |
核心总结:Redis是电商高并发架构的核心,商品缓存负责“提速”,库存扣减负责“精准”,分布式锁负责“安全”,三者配合实现高性能、高一致、高可用的电商系统。
结语
电商场景复杂多变,Redis的应用远不止缓存、库存、锁三大模块,还可延伸至购物车、订单限流、排行榜等业务。实际落地时,需结合业务体量调整缓存策略、锁粒度和过期时间,做好监控与兜底,才能让Redis稳定支撑业务增长。