求职者: 干燥苦涩、缺乏深度
"关于实时库存预警,我是这样想的:
首先,为了实现秒级更新,我们不能直接查数据库,因为 MySQL 并发高了会挂。我们会把库存数据放在 Redis 里,利用 Redis 很快的特性来支撑高并发。
其次,为了不'超卖',我们在扣减库存的时候需要加锁。比如使用分布式锁,或者直接用数据库的事务 update table set stock = stock - 1 where id = xxx and stock > 0。只要 SQL 语句写得对,就不会扣成负数。
最后,预警这一块,我们可以写一个定时任务,每秒钟查一下 Redis 里的库存,如果发现库存小于预警线,就发个短信或者邮件通知业务人员。
这就是我解决超卖和预警的基本思路,核心就是用 Redis 加锁和数据库事务。"
点评: "这个回答属于'初级开发水平'。方案单一,没考虑到大规模分布式系统的复杂性 , 虽然提到了 Redis 和事务,但思考太碎片化。他把'不超卖'寄希望于数据库事务,但在高并发下,大量请求堆积在数据库行锁上会导致系统瞬间雪崩。此外,定时任务做预警既不实时也不优雅,完全没有体现出对'流式数据处理'的理解。"
改造后:有业务、有逻辑、有实践(正面正确回答)
面试者语气:(沉稳、系统化思考,区分了"交易扣减"与"预警显示"的异构需求)
"实现秒级库存预警并杜绝'超卖'错误,本质上是要处理好高性能读、高可靠写、以及端到端的一致性。我的方案分为三个维度:
第一,核心扣减链路:采用'Redis + Lua'实现原子性防超卖。 在高并发下,传统的数据库行锁会产生严重的磁盘 I/O 竞争。
-
我们采用 Redis 预扣减 机制。通过 Lua 脚本 将'判断库存是否足够'与'执行扣减'合并为一个原子操作,利用 Redis 单线程模型彻底避免超卖。
-
同时,为了防止 Redis 宕机导致数据丢失,我们会开启 AOF 指纹校验,并配合 Canal 监听数据库 Binlog 进行最终的数据对齐。
第二,计算预警链路:基于 Flink 的实时流计算。 预警不能靠定时任务轮询(延迟高且压力大),我们要变'拉'为'推':
-
数据源: 将订单系统的库存变更日志推送到 Kafka。
-
计算引擎: 使用 Flink 实时消费 Kafka 。利用 Flink 的
KeyedStream(按商品 ID 分区)和ValueState维护当前内存中的实时库存状态。 -
动态预警逻辑: 我们可以将预警阈值存储在配置中心(如 Nacos/Apollo)中,Flink 通过
BroadcastState实时获取最新的阈值,在秒级内完成'库存计算 -> 阈值对比 -> 触发告警'的全流程。
第三,解决'显示错误'的一致性痛点: '超卖显示错误'通常是因为缓存与数据库不一致导致的。
-
双删策略: 在数据库更新后异步清理缓存,防止旧数据残留。
-
前端处理: 针对极高并发下的缓存延迟,我们在前端展示逻辑中引入'模糊库存'处理(如显示'仅剩少量'而非精确数字),但在点击购买的'决断点'(Check-out)强制走后端的 Lua 脚本校验,确保业务层面的绝对准确。
通过这套'Redis 强控制、Flink 实时算、异步链路补一致'的方案,我们能在支撑 10W+ TPS 的同时,保证预警延迟在 1 秒以内。"
评价: "这个回答非常老练。
抓住了本质: 知道防超卖要靠 Lua 原子操作,而不是简单的分布式锁(锁的开销太大)。
技术栈选型合理: 引入 Flink + BroadcastState 做预警,体现了处理'动态配置'和'实时计算'的工程经验,这是目前主流大厂的标准做法。
考虑到了边界: 提到了缓存一致性和'模糊库存'的处理,说明他不仅懂技术,还懂实际业务中的用户体验折中(Trade-off)。
进阶建议: 如果能再提一下'大促期间如何处理热点 Key(比如某个爆款商品产生的 Redis 单点压力)',比如采用'多级缓存'或'库存分桶'策略,那这个回答就是满分神作了。"