2026/2/10 17:49:13
网站建设
项目流程
平面设计自学网站有哪些,厦门做网站多,招生网站建设方案,怎么去建一个网站#x1f6d2; 前言#xff1a;小小的购物车#xff0c;大大的坑
在面试中#xff0c;我最喜欢问候选人一个问题#xff1a;“设计一个京东/淘宝级别的购物车#xff0c;数据应该存在哪里#xff1f;”
回答 A#xff1a;“存在 Cookie 里#xff0c;省服务器资源。” … 前言小小的购物车大大的坑在面试中我最喜欢问候选人一个问题“设计一个京东/淘宝级别的购物车数据应该存在哪里”回答 A“存在 Cookie 里省服务器资源。” ——错。用户换个手机登录购物车空了体验极差。回答 B“存在 MySQL 里安全。” ——错。双 11 千万级并发每次加购都写库数据库直接火葬场。回答 C“存在 Redis 里快。” ——对了一半。Redis 挂了怎么办数据丢失会导致严重的客诉。真正的购物车系统是一个**“浏览器 Redis MySQL 消息队列”**的混合架构。今天我们就来拆解这个架构是如何一步步搭建出来的。 方案一纯数据库架构 (早期/低流量)在创业初期流量不大直接用 MySQL 也是没问题的。表结构设计CREATETABLEcart_item(idbigintNOTNULLAUTO_INCREMENT,user_idbigintNOTNULLCOMMENT用户ID,sku_idbigintNOTNULLCOMMENT商品ID,countintNOTNULLCOMMENT数量,checkedtinyintDEFAULT1COMMENT是否勾选,update_timedatetime,PRIMARYKEY(id),UNIQUEKEYidx_user_sku(user_id,sku_id));致命缺陷购物车是**“读写极高频”**的业务。用户反复加减数量、勾选商品如果每一次操作都去 Update 数据库数据库的TPS (Transcation Per Second)撑不住。而且这属于“临时数据”占用大量宝贵的数据库存储空间。 方案二纯 Redis 架构 (中等流量)为了快我们将数据全部迁移到 Redis。数据结构选型HashKey:cart:{userId}Field:skuIdValue: JSON 字符串 (包含数量、勾选状态、加入时间)Redis 命令演示# 添加商品 1001数量 2HSET cart:88881001{count:2, checked:1}# 增加商品数量HINCRBY cart:888810011# 获取购物车所有商品HGETALL cart:8888# 删除商品HDEL cart:88881001优点性能极其彪悍支持 10 万 QPS。缺点Redis 内存贵。且 RDB/AOF 持久化有滞后极端宕机情况下会丢数据虽然购物车数据丢失通常可接受但对于大厂这是 P0 级事故。 方案三终极混合架构 (Cookie Redis MySQL MQ)这是目前主流电商淘宝、京东的通用架构。1. 核心策略未登录状态数据保存在客户端Cookie/LocalStorage中。登录状态数据保存在Redis中热数据。持久化通过MQ 异步将 Redis 的变更写入MySQL冷数据备份防丢失做数据分析。2. 关键流程登录合并 (Merge)这是最复杂的逻辑。当用户在“未登录”时往 Cookie 加了 3 个商品然后点击“登录”。系统必须将 Cookie 里的数据 Redis 里原有的数据进行合并。架构流程图异步持久化登录合并流程登录态判断未登录已登录读取临时购物车读取原有购物车1. 合并逻辑2. 清空 Cookie发送变更消息削峰填谷批量写入RocketMQ / KafkaDB 同步服务MySQL 备份库购物车合并服务用户登录动作用户操作写入 Cookie / LocalStorageAPI 网关操作 Redis Hash️ 核心代码实战Redis 封装我们使用 Spring Boot RedisTemplate 来实现核心操作。ServicepublicclassCartService{AutowiredprivateStringRedisTemplateredisTemplate;privatestaticfinalStringCART_PREFIXcart:;/** * 添加购物车 */publicvoidaddCart(LonguserId,LongskuId,Integercount){StringkeyCART_PREFIXuserId;BoundHashOperationsString,Object,ObjectcartOpsredisTemplate.boundHashOps(key);StringskuIdStrskuId.toString();// 1. 判断商品是否存在if(cartOps.hasKey(skuIdStr)){// 2. 存在则累加数量Stringjson(String)cartOps.get(skuIdStr);CartItemitemJSON.parseObject(json,CartItem.class);item.setCount(item.getCount()count);cartOps.put(skuIdStr,JSON.toJSONString(item));}else{// 3. 不存在则新增CartItemnewItemnewCartItem(skuId,count);cartOps.put(skuIdStr,JSON.toJSONString(newItem));}// 4. 发送 MQ 消息做异步持久化 (伪代码)// producer.send(cart_update_topic, new CartUpdateEvent(userId, skuId));}/** * 登录合并逻辑 */publicvoidmergeCart(LonguserId,ListCartItemcookieItems){if(CollectionUtils.isEmpty(cookieItems))return;for(CartItemcookieItem:cookieItems){addCart(userId,cookieItem.getSkuId(),cookieItem.getCount());}// 合并完成后通知前端清除 Cookie}} 进阶思考Redis 存满了怎么办购物车数据有一个特点僵尸数据多。很多用户几年前加的商品还在购物车里。如果所有数据都堆在 Redis内存会爆炸。优化策略LRU 自动过期设置 TTL给cart:{userId}设置过期时间例如 30 天。自动续期每次用户查看购物车或加购时重置 TTL 为 30 天。兜底如果 Redis Key 过期了用户 30 天没来了再次访问时从MySQL把数据加载回 Redis缓存预热。这样既保证了活跃用户的极速体验又节省了昂贵的 Redis 内存。 总结设计购物车系统的 4 个金科玉律读写分离Redis 抗并发MySQL 兜底。异步写入使用 MQ 解耦不要让 DB 拖慢加购速度。端云协同未登录存前端登录后做合并。冷热分离利用 TTL 清理僵尸购物车。架构没有最好的只有最合适的。理解了这套逻辑你就能轻松应对大多数电商面试题。