让你设计一个购物车功能,怎么设计?
- 标签:后端、系统设计、场景题
🏛 业务架构师
购物车看着简单,但它是电商转化漏斗的心脏环节——加购到下单的转化率直接影响 GMV,我会从数据模型、存储选型、业务增值三面讲。
数据模型
核心是"用户 × 商品 × 数量 + 选中状态",但要预留业务字段:加购时间(凑单营销用)、来源活动 ID(归因分析用):
cart: {userId, skuId, quantity, checked, addTime, activityId}存储选型:Redis 为主,异步落库
- 购物车是高频读写、可容忍极小概率丢失的数据(用户重新加一次就是了,不值得为它上强一致)——Redis Hash(
key=cart:{userId}, field=skuId)读写毫秒级 - 异步持久化到 DB 做备份和数据分析;用户登录合并购物车(游客车 + 登录车合并,去重取大)
- 设置容量上限(如 99 件)和过期时间(如 90 天)——这是成本控制也是业务策略,无限增长的购物车是存储资损,过期提醒("您购物车的商品降价了")反而是转化工具
必答的业务增值点(架构师差异所在)
- 价格快照问题:购物车展示加购价还是现价?必须现价(价格随营销活动实时算),加购价用于"降价提醒"——这是业务正确性问题不是技术问题
- 失效商品处理:下架/售罄商品置灰不删除,保留用户心智,配合"找相似"推荐
- 营销联动:凑单(还差 X 元减 Y)、满减试算是购物车的核心职责,它本质是个实时优惠计算引擎的入口
- 加购数据是用户意图的最强信号, feeds 给推荐和广告,价值不亚于下单数据——设计时就要把数据规范留给分析用
收尾:购物车系统的复杂度不在 CRUD,在于它同时服务**用户(体验)、运营(营销)、算法(数据)**三方,架构上要为后两者预留好数据出口。
🏗 系统架构师
购物车看似简单,但它是高频写、多端同步、营销耦合的存储设计题,我按量级给方案。
存储选型(核心决策)
- 登录用户:Redis Hash,key 为
cart:{userId},field 为 SKU ID,value 为数量+勾选标记+加购时间。理由:读写 QPS 高(大促万级/用户级)、天然支持单 SKU 增删改、TTL 做闲置清理 - 未登录用户:客户端本地存储(localStorage),登录时合并到服务端。合并策略:相同 SKU 数量取大或相加(需与产品确认),合并操作幂等
- 持久化:Redis 主从 + 定期/异步落 DB(用户维度全量快照或 binlog 级同步),Redis 故障可恢复;同时 DB 是营销计算与账务的最终数据源
功能设计要点:
- 加购上限:单品数量上限、种类上限(如 99/200),防止恶意刷与 Hash 膨胀
- 价格实时算:购物车里只存 SKU 与数量,绝不存价格快照,结算时实时取价格中心价格并校验(价格、库存、上下架状态),这是防资损红线
- 营销耦合:勾选、凑单、满减试算走营销中心的实时试算接口,购物车本身保持 dumb
- 一致性:改车操作幂等(version 或操作序列号),多端并发改以"操作时间戳新者赢"+ 关键字段合并
量级分档:DAU 百万级用上面的单 Redis 集群够;DAU 亿级(淘宝量级)则要按 user 分片 + 本地缓存快照 + 写合并,加车 RT 控制在 50ms 内。回答重点是存储结构、登录合并、价格不落车三条。
💻 全栈开发专家
购物车看着简单,难点在高并发读写 + 登录/游客身份合并 + 结算一致性。我的设计:
存储:Redis Hash 为主,异步落库
key: cart:{userId}
field: skuId
value: JSON{quantity, checked, skuVersion, addTime}- Hash 结构天然支持单个 SKU 增删改查(
HSET/HDEL/HINCRBY),不用整存整取。 - Redis 是在线主存储,定时任务(XXL-JOB)+ 变更消息把数据刷回 MySQL 做持久化兜底,Redis 故障时可降级读库。
核心接口
- 加购/改数量:
HSET,数量上限(如 99);重复加购合并数量。 - 勾选/全选:value 里维护 checked 标记,结算时
HGETALL过滤。 - 删除:
HDEL;清空:DEL(用户主动)。 - 列表页:拿 cart 数据后批量查 SKU 服务(一次 RPC 带全 skuId),绝不能循环单查,然后过滤下架/无库存商品并在前端置灰。
游客购物车合并
未登录用设备 ID 当 key(cart:device:{uuid} + TTL 90 天),登录时把 device 购物车 HGETALL 后逐条 HSETNX 合并到用户车(已有的不覆盖,数量取大),再删除 device key。
结算快照(一致性关键)
下单时把价格、标题做快照写进订单明细,不能信任购物车里的价格;库存与最终价格在下单接口再校验一次。这避免了"购物车 100 元、下单变 120 元"的资损投诉。