专栏名称: 架构师之路
架构师之路,坚持撰写接地气的架构文章
目录
相关文章推荐
架构师之路  ·  保证session一致性究的5种方法!(第40讲) ·  2 天前  
51好读  ›  专栏  ›  架构师之路

系统重试,导致库存扣多啦,怎么办(两行代码破解)?(第41讲)

架构师之路  · 公众号  · 架构  · 2025-03-05 11:50

正文

《架构师之路:架构设计中的100个知识点》

41.重复扣减

大家有没有遇到过,库存异常的情况:
1. 系统重试,导致库存扣了多次;
2. 系统并发,导致库存设置错误;
今天和大家聊一聊库存扣减里的方案设计。

库存微服务一般提供什么接口?
图片
提供库存的 查询、扣减、设置 等RPC接口:
1. 库存查询接口 ,微服务一般执行:
select num from stock where sid=$sid
2. 库存扣减 接口 微服务一般 执行:
update stock set num=num-$reduce where sid=$sid
3. 库存设置 接口 微服务一般 执行:
update stock set num=$num_new where sid=$sid

库存操作,一般是什么业务场景?
用户下单前,一般会对库存进行查询,有足够的存量才允许扣减:
图片
如上图所示,通过查询接口,得到库存是5。

用户下单时,接着会对库存进行扣减:
图片
如上图所示,购买3单位的商品,通过扣减接口,最终得到库存是2。

简言之,一般是“先查后减”。

库存“先查后减”会遇到什么问题?
系统往往有 重试机制 ,这个重试机制可能实现在系统底层,例如:服务连接池重试,数据库连接池重试,业务代码不可控。

如果通过扣减接口来修改库存,在 重试时会导致重复扣减
图片
如上图所示,try和retry,导致一次扣减执行两次,最终得到一个错误库存。

如何解决“重试导致库存异常”的问题?
这里的 根本原因 “reduce”操作是一个 非幂等 的操作 ,不能够重复执行, 可以升级为“set”操作
图片
如上图所示,同样是购买3单位的商品,通过set操作,即使有重试机制,也不会得到错误的库存,“ set 操作是一个 幂等 操作

因此,应该“先查后设”。

库存“先查后设”会遇到什么问题?
并发量很大时,还是可能导致库存异常:
图片
如上图所示,两个并发的操作,查询库存,都得到了库存是5。

接下来多个用户发生了 并发 的购买动作:
画外音:秒杀类业务特别容易出现。
图片
如上图所示:
1. 用户1购买了3个库存,库存要设置为2;
2. 用户2购买了2个库存,库存要设置为3;
3. 这两个设置库存的接口并发执行, 库存会先变成2,再变成3,导致数据不一致 (实际卖出了5件商品,但库存只扣减了2, 最后一次设置库存会覆盖和掩盖前一次并发操作 );

如何解决“并发导致库存异常”的问题?
这里的 根本原因 设置操作发生的时候,没有检查库存与查询出来的库存有没有变化 ,理论上:
1. 库存为5时,用户1的库存设置才能成功;
2. 库存为5时,用户2的库存设置才能成功;

实际执行的时候:
1. 库存为5,用户1的set stock 2确实应该成功;
2. 库存变为2了,用户2的set stock 3应该失败掉;
画外音:有条件的成功。

接口实现优化升级,将库存设置接口执行的:
update stock set num=$y where sid=$sid
升级为:
update stock set num=$num_new where sid=$sid
and num=$num_old
画外音:加了一个初始条件比对。

简言之, “先查后






请到「今天看啥」查看全文