一键三连,让算法推荐更多类似干货 ~
你最近面试被问到的最难的题是什么? 评论区交流,我来解答
突然发现自己欠了一屁股 技术债 ? 别薅头发了 —— 关注本专栏,带你清债~
一、口诀:
库存防超卖,锁和版本带;
Redis 先扣减,异步同步快;
限流加队列,拆分监控在。
二、答案:
锁、缓存、流量削峰、监控:
1. 数据库层:保证库存操作的原子性
- 悲观锁:使用
SELECT ... FOR UPDATE锁定库存记录,确保同一时间只有一个请求能修改库存,避免并发冲突。 - 例如:
SELECT inventory FROM goods WHERE id = 1 FOR UPDATE; UPDATE goods SET inventory = inventory - 1 WHERE id = 1 AND inventory > 0; - 乐观锁:通过版本号或库存条件控制,例如在更新时校验库存是否足够,避免超卖:
UPDATE goods SET inventory = inventory - 1, version = version + 1 WHERE id = 1 AND inventory > 0 AND version = 1;
锁的选择核心是匹配冲突频率:
冲突多(秒杀)→ 悲观锁(避免重试浪费资源)。
冲突少(优惠券)→ 乐观锁(提升吞吐量)。
- 字段约束:将库存字段设为无符号整数,当库存为 0 时再减 1 会直接报错,从数据库层面阻止超卖。
2. 缓存层:减少数据库压力,快速响应
- Redis 预存库存:将库存提前加载到 Redis,抢购时先在 Redis 中扣减库存(如使用
DECR命令),成功后再异步同步到数据库。通过 Lua 脚本保证扣减的原子性,避免并发问题:lua
-- 若库存>0则扣减,返回1;否则返回0 if redis.call('get', KEYS[1]) > 0 then return redis.call('decr', KEYS[1]) else return 0 end - 库存拆分:将热点商品的库存拆分为多个子库存(如 10 万库存拆成 20 份),随机轮询扣减子库存,分散 Redis 单分片压力,避免单点瓶颈。
3. 流量控制:避免超预期请求冲击
- 限流:通过令牌桶算法限制每秒请求数(如 10 万 QPS),超出阈值的请求直接返回 “活动拥挤”,避免系统过载。
- 异步处理:使用消息队列(如 RocketMQ)接收抢购请求,消费者异步处理库存扣减和订单创建,削峰填谷,避免瞬间压力压垮数据库。
4. 兜底措施:应对极端情况
- 库存预热与监控:活动前预热库存到 Redis,实时监控库存余量和接口响应时间,异常时触发报警。
- 库存校验:订单创建后定期核对 Redis 与数据库的库存一致性,发现偏差时通过补偿机制修正(如回滚异常订单释放库存)。
三、STAR 法则回答
- 情境(S):电商秒杀活动中,某商品库存 1000 件,预计峰值 QPS 达 10 万,需避免超卖或少买,确保数据准确。
- 任务(T):设计方案解决高并发下的库存一致性问题,保证抢购过程中库存不超发、不遗漏。
- 行动(A):
- 数据库层:使用乐观锁(版本号)控制库存更新,确保只有库存 > 0 时才能扣减;
- 缓存层:将库存预存到 Redis,用 Lua 脚本原子性扣减,热点库存拆分为 10 个子库存分散压力;
- 流量控制:通过令牌桶限流每秒 10 万请求,用 RocketMQ 异步处理订单,避免直接冲击数据库;
- 兜底措施:实时监控库存数据,定时核对 Redis 与数据库一致性,异常时自动补偿。
- 结果(R):活动期间成功处理 12 万 QPS,库存准确扣减至 0,无超卖少买,响应时间 < 200ms,活动顺利完成。
四、生活例子
类比 “热门餐厅抢座位”:
- 数据库锁就像 “服务员一次只接待一位顾客登记座位”,避免多人同时抢同一座位;
- Redis 缓存好比 “门口电子屏实时显示余位”,顾客先看屏再进店,减少对服务员的询问;
- 库存拆分类似 “将 10 个座位分成多个区域,每个区域单独叫号”,避免拥挤;
- 限流如同 “餐厅规定每分钟最多放 5 人进店”,防止内部混乱。
(点个赞,算法会给你推荐更多类似干货 ~ 持续更新中,点关注,看下篇文章)
鉴于面试官喜欢逮住一个方向连环问,那我们再阐述一下周边问题:
(二)、悲观锁、乐观锁的适用场景是什么?
口诀:
高冲突,悲观锁,锁定资源防出错;
低冲突,乐观锁,无锁重试效率多。
1. 悲观锁:秒杀场景的 “铁将军”
- 适用场景:秒杀、热门商品抢购等高冲突场景(如 10 万 QPS 争抢 100 件库存)。
- 核心逻辑:通过
SELECT ... FOR UPDATE直接锁定库存记录,同一时间只允许一个请求操作,从根源避免并发冲突。 - 为何适配:秒杀中冲突极频繁,悲观锁 “先锁后操作” 能杜绝超卖,牺牲部分吞吐量换数据安全。
2. 乐观锁:优惠券场景的 “轻骑兵”
- 适用场景:优惠券发放、普通商品库存扣减等中低冲突场景(如 10 万张券分散领取)。
- 核心逻辑:通过版本号(
WHERE version = x)或库存条件(WHERE inventory > 0)实现无锁化更新,冲突时重试。 - 为何适配:冲突少,乐观锁 “先操作后校验” 能提升吞吐量,重试成本低。
3. 反向使用的坑
- 秒杀用乐观锁:高频冲突导致大量重试失败,数据库压力飙升,可能引发超卖。
- 优惠券用悲观锁:低频冲突下锁等待拖慢响应,吞吐量骤降,影响用户体验。
一键三连,让算法推荐更多类似干货 ~ 持续更新中~
你最近面试被问到的最难的题是什么? 评论区交流,我来解答)
突然发现自己欠了一屁股 技术债 ? 别薅头发了 —— 关注本专栏,带你清债~
2028

被折叠的 条评论
为什么被折叠?



