
1. 项目背景与核心需求烘焙坊电商系统的购物车模块面临两个关键挑战高并发场景下的性能瓶颈和数据一致性要求。当促销活动带来瞬时流量激增时传统基于数据库直接读写的方式会导致响应延迟明显上升实测在500QPS压力下平均响应时间超过800ms。同时由于购物车数据具有高频更新特性用户可能连续添加/删除多个商品需要保证跨请求的状态同步。我们最终选择Redis作为解决方案主要基于三点考量单节点读写性能可达10万QPS完全覆盖业务峰值丰富的数据结构支持HashSortedSet组合使用原生支持过期时间和持久化策略关键决策采用异步双写策略先更新Redis再通过消息队列同步到MySQL牺牲部分实时一致性换取系统可用性。经压测验证该方案在2000QPS下仍能保持200ms内的稳定响应。2. 缓存架构设计详解2.1 多级缓存体系搭建采用L1L2两级缓存架构L1本地缓存使用Caffeine存储用户基础信息等变化频率低的数据// 配置示例 Caffeine.newBuilder() .maximumSize(10_000) .expireAfterWrite(5, TimeUnit.MINUTES) .build();L2分布式缓存Redis集群存储购物车等需要跨服务共享的数据缓存更新策略采用Cache-Aside模式具体流程读请求先查本地缓存未命中则查询Redis仍未命中最后查DB并回填缓存写操作先更新DB再删除缓存2.2 Redis数据结构选型购物车采用HashSortedSet组合结构# 用户购物车基础数据 HSET cart:user123 item:cupcake 2 HSET cart:user123 item:bread 1 # 商品价格排序索引 ZADD cart:index:user123 15.99 item:cupcake ZADD cart:index:user123 9.99 item:bread该设计实现O(1)复杂度的单品查询HashO(logN)范围查询SortedSet内存占用减少40%相比全量JSON存储3. 购物车核心功能实现3.1 并发操作控制采用Lua脚本保证原子性操作-- 添加商品脚本 local key KEYS[1] local item ARGV[1] local quantity tonumber(ARGV[2]) local current redis.call(HGET, key, item) if current then quantity quantity tonumber(current) end redis.call(HSET, key, item, quantity) return quantity3.2 过期与持久化策略配置方案# redis.conf关键配置 maxmemory 2gb maxmemory-policy volatile-lru save 900 1 save 300 10配合定时任务每天凌晨3点执行BGSAVE同时设置购物车数据30天自动过期。4. 性能优化实战4.1 热点key处理通过分片解决热门商品被频繁访问的问题// 商品ID取模分片 int shard itemId.hashCode() % 16; String cacheKey cart:user123:shard_ shard;4.2 缓存雪崩预防采用三级防护差异化过期时间基础过期时间随机浮动值熔断降级当Redis不可用时启用本地缓存模式提前预热活动前通过离线任务加载热点数据5. 异常处理实录5.1 典型问题排查表现象根因解决方案购物车物品重复网络重试导致重复提交接口增加幂等token价格显示不一致缓存未及时失效发布商品更新事件触发缓存刷新操作超时Redis连接池耗尽调整maxTotal到500并启用空闲检测5.2 踩坑经验管道化使用误区批量操作时应控制每次管道命令数量在50个以内避免单次操作阻塞过久。实测超过100条命令时平均延迟会从15ms飙升到120ms。内存碎片优化当Redis内存占用超过物理内存70%时建议设置activedefrag yes并调整hz值为20可使内存利用率提升15%。监控指标重点除了常规的命中率外需要特别关注evicted_keys和keyspace_misses指标当每分钟淘汰key数超过100时需要及时扩容。6. 扩展实践建议对于需要强一致性的场景如库存扣减可采用Redisson提供的分布式锁RLock lock redisson.getLock(item_lock:itemId); try { lock.lock(5, TimeUnit.SECONDS); // 业务操作 } finally { lock.unlock(); }在灰度发布场景下建议通过hash tag保证用户请求始终路由到同一节点# 使用{}定义hash tag SET {user123}.cart item1 SET {user123}.profile info1