Redis最佳实践——购物车优化详解

article/2025/8/13 1:59:51

在这里插入图片描述

Redis在电商购物车高并发读写场景下的优化实践


一、购物车业务场景分析
  1. 典型操作特征

    • 读/写比例 ≈ 8:2
    • 高峰QPS可达10万+
    • 单用户最大商品数500+
    • 操作类型:增删改查、全选/反选、数量修改
  2. 技术挑战

    • 高并发下的数据一致性
    • 海量数据存储与快速访问
    • 实时价格计算与库存校验
    • 分布式环境下的会话管理

二、核心数据结构设计优化

1. 存储结构方案对比

方案优点缺点
String+JSON简单直观修改需反序列化整个数据
Hash结构支持字段级操作嵌套结构处理略复杂
Sorted Set天然支持排序存储成本较高
混合结构平衡性能与灵活性实现复杂度略高

2. 最终数据结构设计

// Key设计:cart:{userType}:{userId}
String cartKey = "cart:user:10001"; // Value结构:
// Hash结构存储商品基础信息
Map<String, String> itemData = new HashMap<>();
itemData.put("sku:1001", "{\"quantity\":2,\"selected\":1,\"price\":5999,\"timestamp\":1717025661}");// Sorted Set维护操作顺序
jedis.zadd(cartKey + ":zset", System.currentTimeMillis(), "sku:1001");

三、读写分离架构设计

1. 多级缓存架构

首次访问
缓存穿透
缓存未命中
缓存命中
缓存命中
回写
回写
客户端
读请求
本地缓存
Redis集群
数据库
返回数据

2. 各层缓存配置

缓存层级技术选型容量过期策略
本地缓存Caffeine10万用户基于大小+访问时间(1分钟)
Redis缓存Hash+Zset1TB内存动态TTL+LRU淘汰
持久化存储MySQL+TiDB无限扩展事务保障

四、高并发写入优化

1. 批量操作管道化

public void batchAddItems(String userId, List<CartItem> items) {try (Jedis jedis = jedisPool.getResource()) {Pipeline pipeline = jedis.pipelined();String cartKey = buildCartKey(userId);items.forEach(item -> {String field = "sku:" + item.getSkuId();// 更新Hashpipeline.hset(cartKey, field, serialize(item));// 更新ZSETpipeline.zadd(cartKey + ":zset", System.currentTimeMillis(), field);});pipeline.sync();}
}

2. 异步队列削峰

@KafkaListener(topics = "cart_updates")
public void processCartUpdate(CartUpdateEvent event) {redisTemplate.executePipelined((RedisCallback<Object>) connection -> {event.getUpdates().forEach(update -> {connection.hSet(update.getCartKey().getBytes(),update.getField().getBytes(),serialize(update.getValue()));});return null;});
}

五、高并发读取优化

1. 热点数据预加载

@Scheduled(fixedRate = 600000) // 每10分钟执行
public void preloadActiveCarts() {List<String> activeUsers = userService.getRecentActiveUsers(10000);activeUsers.parallelStream().forEach(userId -> {String cartKey = buildCartKey(userId);Map<String, String> cartData = jedis.hgetAll(cartKey);localCache.put(userId, cartData);});
}

2. 分片读取优化

public Map<String, CartItem> getCartSharded(String userId) {String cartKey = buildCartKey(userId);List<String> fields = new ArrayList<>();// 分片读取HashMap<String, CartItem> result = new ConcurrentHashMap<>();IntStream.range(0, 4).parallel().forEach(shard -> {ScanParams params = new ScanParams().count(100).match("sku*");String cursor = "0";do {ScanResult<Map.Entry<String, String>> scanResult = jedis.hscan(cartKey, cursor, params);scanResult.getResult().forEach(entry -> {if (entry.getKey().hashCode() % 4 == shard) {result.put(entry.getKey(), deserialize(entry.getValue()));}});cursor = scanResult.getCursor();} while (!"0".equals(cursor));});return result;
}

六、实时库存校验方案

1. 库存缓存设计

// 库存Key结构
String stockKey = "stock:" + skuId + ":" + warehouseId;// 原子扣减库存
Long remain = jedis.eval("local current = redis.call('get', KEYS[1])\n" +"if not current then return -1 end\n" +"if tonumber(current) < tonumber(ARGV[1]) then return -1 end\n" +"return redis.call('decrby', KEYS[1], ARGV[1])", Collections.singletonList(stockKey), Collections.singletonList("1")
);

2. 库存预占机制

public boolean reserveStock(String userId, String skuId, int quantity) {String lockKey = "stock_lock:" + skuId;RLock lock = redissonClient.getLock(lockKey);try {if (lock.tryLock(100, 1000, TimeUnit.MILLISECONDS)) {// 检查实际库存int realStock = getRealStock(skuId);if (realStock < quantity) return false;// 写入预占记录String reserveKey = "reserve:" + userId + ":" + skuId;jedis.setex(reserveKey, 300, String.valueOf(quantity));// 更新显示库存jedis.decrBy("display_stock:" + skuId, quantity);return true;}} finally {if (lock.isHeldByCurrentThread()) {lock.unlock();}}return false;
}

七、数据一致性保障

1. 双写一致性方案

App Redis MQ DB 1. 写入购物车数据 2. 发送变更事件 3. 异步持久化 4. 定时全量同步 5. 返回操作结果 App Redis MQ DB

2. 补偿对账机制

@Scheduled(cron = "0 0 2 * * ?")
public void cartReconciliation() {// 扫描所有购物车KeyScanParams params = new ScanParams().match("cart:*").count(100);String cursor = "0";do {ScanResult<String> scanResult = jedis.scan(cursor, params);scanResult.getResult().parallelStream().forEach(cartKey -> {// 对比Redis与数据库Map<String, String> redisData = jedis.hgetAll(cartKey);Map<String, CartItem> dbData = cartDAO.getFromDB(extractUserId(cartKey));if (!dataEquals(redisData, dbData)) {log.warn("数据不一致:{}", cartKey);repairData(cartKey, redisData, dbData);}});cursor = scanResult.getCursor();} while (!"0".equals(cursor));
}

八、性能压测数据

测试环境

  • Redis Cluster(6节点,32核/128GB)
  • 1000并发线程
  • 单用户购物车50件商品

性能指标

操作类型优化前性能优化后性能提升倍数
添加商品1200 TPS8500 TPS7.1x
批量删除800 TPS6800 TPS8.5x
全量获取300 QPS4500 QPS15x
库存校验1500 TPS12000 TPS8x

九、生产环境最佳实践
  1. 容量规划

    • 按每个用户购物车平均50个商品计算
    • 单个Hash存储约需5KB内存
    • 百万用户需预留:1,000,000 * 5KB = 5GB
  2. 故障应急方案

    • 熔断降级:启用本地缓存应急模式
    • 快速扩容:Redis Cluster在线扩容
    • 数据恢复:AOF+RDB双重保障
  3. 监控关键指标

    # 实时监控命令
    redis-cli info stats | grep -E "instantaneous_ops_per_sec|keyspace_hits"
    redis-cli info memory | grep used_memory_human
    redis-cli latency doctor
    

十、总结与扩展

通过本方案可实现:

  • 毫秒级响应:核心操作<10ms
  • 99.99%可用性:双机房容灾保障
  • 线性扩展:支持千万级用户购物车
  • 精准库存:实时库存校验误差<0.1%

扩展优化方向

  1. 结合CDN缓存静态化购物车页面
  2. 使用Redis Stream实现实时价格推送
  3. 引入机器学习预测用户购物行为

更多资源:

https://www.kdocs.cn/l/cvk0eoGYucWA

本文发表于【纪元A梦】


http://www.hkcw.cn/article/IdcgCvvvEb.shtml

相关文章

[网页五子棋][对战模块]处理连接成功,通知玩家就绪,逻辑问题(线程安全,先手判定错误)

文章目录 处理连接成功通知玩家就绪逻辑图问题 1&#xff1a;线程安全问题 2&#xff1a;先手判定错误两边都是提示&#xff1a;轮到对方落子![image.png](https://i-blog.csdnimg.cn/img_convert/c570cd26eadbe87ed467bc4edaa7945e.png) 处理连接成功 实现 GameAPI 的 afterC…

Python训练打卡Day39

图像数据与显存 知识点回顾 图像数据的格式&#xff1a;灰度和彩色数据模型的定义显存占用的4种地方 模型参数梯度参数优化器参数数据批量所占显存神经元输出中间状态 batchisize和训练的关系 一、图像数据的格式 1.1灰度图像 作为图像数据&#xff0c;相较于结构化数据&#x…

pycharm打印时不换行,方便对比观察

原来&#xff1a; 优化&#xff1a; import torch torch.set_printoptions(linewidth200) 优化结果&#xff1a;

Practice 2025.6.1—— 二叉树进阶面试题(2)

文章目录 二叉树进阶面试题(2)Leetcode_144 二叉树的前序遍历(使用非递归)Leetcode_94 二叉树的中序遍历(使用非递归)Leetcode_145 二叉树的后序遍历(使用非递归) 二叉树进阶面试题(2) 本篇文章将继续进行二叉树的进阶面试题的讲解&#xff0c;其中&#xff0c;本部分将重点针…

DOCKER使用记录

1、拉取镜像 直接使用docker pull <image>&#xff0c;大概率会出现下面的报错信息&#xff1a; (base) jetsonyahboom:~$ docker pull ubuntu:18.04 Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while …

Vert.x学习笔记-EventLoop与Context的关系

Vert.x学习笔记 1. EventLoop 的核心作用2. Context 的核心作用3. EventLoop 与 Context 的关系1. 事件循环&#xff08;EventLoop&#xff09;的核心职责2. 上下文&#xff08;Context&#xff09;的核心职责3. 事件循环与上下文的关系&#xff08;1&#xff09;一对一绑定&am…

LTSPICE仿真电路:(三十一)HOWLAND电流源

1.HOWLAND电流源 推导过程&#xff1a;这个运放是正负反馈都存在&#xff0c;但负反馈是大于正反馈的&#xff0c;因正反馈多出一个Rload&#xff0c;所以可以使用虚短续断&#xff0c;运放的U等于U-&#xff0c;负反馈处得出Uout与U-的关系&#xff0c;再利用正相端节点电流算…

LLaMA-Factory - 批量推理(inference)的脚本

scripts/vllm_infer.py 是 LLaMA-Factory 团队用于批量推理&#xff08;inference&#xff09;的脚本&#xff0c;基于 vLLM 引擎&#xff0c;支持高效的并行推理。它可以对一个数据集批量生成模型输出&#xff0c;并保存为 JSONL 文件&#xff0c;适合大规模评测和自动化测试。…

引擎下线缺陷检测系统ENAgent

引擎下线缺陷检测系统ENAgent采用信号处理技术以及人工智能技术对引擎生产线下线的各种引擎在生产线上进行缺陷实时检测&#xff0c;通过振动信号、声纹信号等信号融合集成&#xff0c;在线实时判断其是否存在缺陷以及进行故障诊断。ENAgent系统采用全Python语言&#xff0c;以…

【量化交易学习】布林线(BOLL)指标

目录 1. 布林线&#xff08;BOLL&#xff09;指标定义与构成1.1 定义1.2 布林线的构成 2. BOLL&#xff08;布林线&#xff09;的应用场景3. BOLL指标的研判标准3.1 BOLL指标中的上、中、下轨线的意义3.2 BOLL指标中的上、中、下轨线之间的关系3.3 K线和布林线上、中、下轨之间…

ArcGIS Pro 创建渔网格网过大,只有几个格网的解决方案

之前用ArcGIS Pro创建渔网的时候&#xff0c;发现创建出来格网过大&#xff0c;只有几个格网。 后来查阅资料&#xff0c;发现是坐标不对&#xff0c;导致设置格网大小时单位为度&#xff0c;而不是米&#xff0c;因此需要进行坐标系转换&#xff0c;网上有很多资料讲了ArcGIS …

java27

1.IO流 FileOutPutStream字节输出流基本用法&#xff1a; 一次性写入一个字符串的内容&#xff1a; 注意&#xff1a;\r或者\n表示把普通的r或者n的字符转义成回车的意思&#xff0c;所以不需要\\ FileInputStream字节输入流基本用法 -1在ASCII码里面对应的符号&#xff1a; 不…

Windows设置之RDP文件用户密码

1、远程桌面另存为rdp文件 2、编辑rdp文件&#xff0c;添加用户名密码信息 username:s:<用户名> password 51:b:<加密后的密码> 3、<加密后的密码>通过PowerShell命令或者 ("<密码>" | ConvertTo-SecureString -AsPlainText -Force) | Conve…

day025-网络基础-DNS与ARP协议

文章目录 1. DNS服务1.1 DNS解析流程1.2 查看本地DNS缓存&#xff08;Windows&#xff09;1.3 查看详细DNS解析流程1.4 排查DNS故障 2. 面试题&#xff1a;用户访问网站过程2.1 抓包 3. ARP协议3.1 命令查看3.2 抓包 4. ICMP协议4.1 禁用ping 5. 踩坑记录1. **为什么解析域名时…

SEO长尾关键词优化实战

内容概要 在长尾关键词优化实践中&#xff0c;系统化的策略设计与执行路径直接影响流量获取效率与转化质量。本文从行业竞争度评估切入&#xff0c;通过多维指标拆解目标关键词的流量价值与操作成本&#xff0c;帮助从业者建立科学的资源分配模型&#xff1b;同时聚焦用户搜索…

复杂业务场景下 JSON 规范设计:Map<String,Object>快速开发 与 ResponseEntity精细化控制HTTP 的本质区别与应用场景解析

Moudle 1 Json使用示例 在企业开发中&#xff0c;构造 JSON 格式数据的方式需兼顾 可读性、兼容性、安全性和开发效率&#xff0c;以下是几种常用方式及适用场景&#xff1a; 一、直接使用 Map / 对象转换&#xff08;简单场景&#xff09; 通过 键值对集合&#xff08;如 M…

Oracle正则表达式学习

目录 一、正则表达简介 二、REGEXP_LIKE(x,匹配项) 三、REGEXP_INSTR 四、REGEXP_SUBSTR 五、REGEXP_REPLACE 一、正则表达简介 相关网址&#xff1a; https://cloud.tencent.com/developer/article/1456428 https://www.cnblogs.com/lxl57610/p/8227599.html https://…

【HW系列】—溯源与定位—Windows入侵排查

文章目录 实在不会手动&#xff0c;打开一个杀毒软件&#xff0c;全盘扫描一、入侵排查思路与流程1. 常见应急响应事件分类2. 入侵排查流程图 二、Windows账户安全排查&#xff08;D盾&#xff0c;微步沙箱&#xff09;1. 正常账户 vs 黑客账户区别2. 自动账户排查3. 隐藏账户与…

【机器学习基础】机器学习入门核心:Jaccard相似度 (Jaccard Index) 和 Pearson相似度 (Pearson Correlation)

机器学习入门核心&#xff1a;Jaccard相似度 &#xff08;Jaccard Index&#xff09; 和 Pearson相似度 &#xff08;Pearson Correlation&#xff09; 一、算法逻辑Jaccard相似度 (Jaccard Index)**Pearson相似度 (Pearson Correlation)** 二、算法原理与数学推导1. Jaccard相…

CVE-2021-28164源码分析与漏洞复现

漏洞概述 漏洞名称&#xff1a;Jetty 路径解析逻辑漏洞导致 WEB-INF 敏感信息泄露 漏洞编号&#xff1a;CVE-2021-28164 CVSS 评分&#xff1a;7.5 影响版本&#xff1a;Jetty 9.4.37 - 9.4.38 修复版本&#xff1a;Jetty ≥ 9.4.39 漏洞类型&#xff1a;路径遍历/信息泄露 C…