SHEIN 二面:Redis 库存扣减与缓存一致性
- 轮次
- 二面
- 时间
- 2026-09
- 来源
- 牛客网
《面试题目》
- 能挑之前的一个项目来展开介绍一下吗?你觉得当时最大的挑战是什么?或者说解决的印象比较深刻、比较难的一个事是什么?
- 项目中用 Redis 设计一个类似于具有事务性的原子化操作,有考虑过数据库和缓存的数据怎么一致吗?
- 如果下单超时失败了,这时候可能只扣了 Redis 里面的库存,实际上最终数据库里的库存没有扣减,这种情况怎么解决?
- Lua 脚本里面有什么样的逻辑?
- 真正购买成功时用户要经过订单系统、促销系统做扣减,这些流程不能在 Redis Lua 脚本里面去写,那么实际的流程是怎么样的?
- Redis 有稳定性的一些隐患吗?怎么解决?
- 介绍下 RAG 项目。
- 有考虑过自己想找一份什么样的工作、做哪一方面吗?有规划过吗?
- 除了刚才讲到的 RAG 系统,日常会用 AI 做些什么样的事?
《参考解析》
Redis 原子扣减与缓存一致性:先说清职责——Redis 只做”预占/预扣”,数据库才是权威库存。写路径是:Redis 用 Lua 原子地判断并扣减预占库存 → 下单成功记录订单 → 通过事务消息或本地消息表把扣减事件可靠投递到 MQ → 消费端在数据库里 UPDATE stock = stock - n WHERE stock >= n(靠行锁和条件保证不超卖),幂等键用订单号去重。缓存一致性上,纯 cache-aside 的”先更新 DB 再删缓存”已经够用,需要更稳就加延迟双删或在 binlog 订阅(Canal)驱动的删除;还有一种是把缓存当作唯一读源、写只写 DB 并失效缓存。无论哪种,最后都要有对账任务:定期比对 Redis 预占总量、DB 扣减总量和订单量,差异单人工或自动补偿,这才是能扛住事故的答案。
下单超时只扣了 Redis 没扣 DB 怎么办:核心是”预占要有租约、要有补偿”。做法:预占时记录一条流水(订单号、sku、数量、状态=预占中)并给 Redis 预占键设 TTL;支付成功后把状态置为已确认,再触发 DB 扣减;超时未支付/流程异常时,靠 Redis 键过期事件或延迟消息(RocketMQ 延迟消息、时间轮)触发回滚,把预占数量加回去,并把流水置为已释放。所有动作都带订单号做幂等(回滚只能执行一次),消费端失败就重试到成功或进死信,最后用定时对账兜底修复”钱货不一致”的单据。
Lua 脚本里写什么:脚本承担的是”读—判断—写”必须原子完成的那一小段:取库存 key、判断是否 >= 购买数量、DECRBY 扣减、记录预占(写一个带订单号的占位 key 或 Sorted Set)、返回结果码(成功/库存不足/重复提交)。要强调边界:Lua 里不能做网络调用和耗时操作(会阻塞 Redis 单线程),入参只用 KEYS/ARGV 传;Redis Cluster 下所有操作的 key 必须在同一个 slot,通常用 hash tag 把 {sku:123}:stock 和 {sku:123}:hold 绑到同一分片;脚本要控制在几十行内并用 EVALSHA 缓存减少传输。
完整下单链路为什么不能全塞进 Lua:订单、促销、优惠、风控、积分是不同服务,各自有自己的库和事务语义,塞进 Redis 单线程脚本既写不了跨系统事务,也会把 Redis 拖死。真实流程是”预占 + 异步编排”:接入层调订单服务下单 → 在 Redis Lua 里做库存预占(秒杀场景的第一道闸)→ 发消息,库存服务落库扣减、促销服务核销、订单服务更新状态,各自幂等 → 任一步失败就把整单标记失败并发补偿消息回滚预占 → 全部成功才让订单进入待支付/已支付。中间需要状态机(预占中/已确认/已释放)和超时兜底,讲清这些比讲”用了 Redis”重要得多。
Redis 的稳定性隐患与解法:可以按维度答:① 持久化——AOF 默认 everysec 最多丢 1 秒数据,RDB 丢得更多,核心数据不能只信 Redis;② 复制与故障切换——主从异步复制,主挂时未同步的写会丢,锁也可能丢,重要场景上哨兵/Cluster 并用数据库唯一约束兜底;③ 集群——slot 迁移期间的 MOVED/ASK、大 key 迁移阻塞、跨 slot 事务不可用;④ 容量与淘汰——设 maxmemory 与 noeviction/allkeys-lru 策略,避免内存打满后被 OOM 杀掉;⑤ 缓存三兄弟——穿透(布隆过滤器 + 空值缓存)、击穿(互斥重建或逻辑过期)、雪崩(过期时间加随机、多级缓存、集群);⑥ 慢查询与大 key——禁用 KEYS,用 SCAN,大 key 拆分,删除走 UNLINK 或分批;⑦ 监控——命中率、连接数、阻塞命令、主从延迟、慢日志。
RAG 项目与个人规划怎么答:15 分钟的二面时间有限,RAG 只要一支线讲清”解决什么业务问题—链路怎么搭(切分、向量召回、rerank、拼上下文、引用)—线上指标与 badcase 怎么迭代”,把细节留给面试官追问。规划类问题要贴着岗位答:想做后端/交易或基础架构方向,理由是可迁移的技术深度与业务复杂度,而不是空泛的”想成长”。被问日常怎么用 AI,讲真实场景(写脚本、读陌生代码、辅助排查、生成测试)加一句边界(关键逻辑自己 review)。