脑补了一个微服务场景, 请问解决方案是什么?

345 天前
 chaleaochexist

还是说没有解决方案

卖苹果, 库存 3 个. 有人买了, 先减库存(苹果-1)因为支付失败,需要逆操作补库存(苹果+1).

但是苹果+1 在先 -1 在后. 理论上某个时刻苹果的库存变成 4 了.

请问如何解决?

3866 次点击
所在节点    程序员
54 条回复
seth19960929
344 天前
@realpg 很多银行就是转账直接跳到某个等待页面, 快的话马上显示成功, 慢的等 10s.
所以转账提交成功, 和转账成功分两步
sadfQED2
344 天前
槽点太多,不知道从哪开始说。
realpg
344 天前
@seth19960929 #21
对啊 这就是我说的这个状态
你不能消息丢给 mq 就给用户订单生成了
optional
344 天前
你把状态流程图画清楚就不会提这个问题了。
xuanbg
344 天前
第一,为什么要先减库存,不是付款成功才减?
第二,你不是先减掉了吗,怎么会加回时多出一个?这个逻辑我看不懂。

说来说去,为什么库存不够就不能下单?你们采购都死光了么?就算一时半会补不了货,不还能工厂直发吗?我要是老板,非把你们这些一根筋的程序员打个半死不可。
nothingistrue
344 天前
经典的异步乱序难题。你这个还好解决一些。

我这里假定「苹果+1 」、「苹果-1 」是两个事件,如果你用得不是事件驱动而是常规 REST 接口,那么可以把事件看作接口的入参对象,把事件消费过程看作接口的方法体。

首先,开了异步,并且还有严重级别的一致性问题,那么相关操作都要当作业务数据去存储。对于你的案例,就是「苹果+1 」、「苹果-1 」这些事件的消费记录,要当作业务数据存到数据库中。

「苹果-1 」事件无依赖,它的消费过程不用动。

「苹果+1 」事件必须晚于「苹果-1 」事件被消费,故它在消费时,要先去查找一下对应的「苹果-1 」事件是否有消费记录。如果没有,则停止当前消费过程,并追加延迟消费逻辑。延迟消费逻辑,可以简单的记消费失败并让发布事件那一方短暂延迟后重新发布事件(对于 REST 接口来说,就是接口抛异常,调用方捕获到异常之后,sleep ,然后重新调接口),也可以记消费成功但同时发布新的「苹果+1 延迟」事件(这个如果是 REST 接口,就有点难弄了,你需要额外加延迟调度框架,绝对不能在 REST 接口中 sleep )。

如果条件允许的话,还是用 Kafka 做事件驱动的基础设施,它能保证顺序消费。
nothingistrue
344 天前
@lsk569937453 #4
@realpg #17 #22
@tabris17 #18

不管是分布式事务,还是等消息处理成功才正式生成订单,这是 CP without A 的分布式原则选择,强一致但是低可用。下订单的场景明显不能采用这种原则。
hhjswf
344 天前
@xuanbg 先减库存保证库存不超扣。至于超扣这个事情重不重要,没干过电商运营不知道
MoYi123
344 天前
讨论技术问题就只讨论技术, 为什么总有懂哥来个什么程序员思维, 产品设计.
电商允许不一致, 那要是哪天你去做银行的项目, 遇到相似的场景, 也允许不一致吗?
peyppicp
344 天前
我司库存扣减业务,现在一般就几种扣减模式:
1. 下单减库存,订单取消回补库存,订单取消接口编排库存回补逻辑
2. 下单预占库存,支付成功减库存,订单超时释放
3. 支付减库存,业务场景并不多

前提:当前使用的数据库是魔改过的,并针对高并发场景下执行 UPDATE value=value-1 做过定制优化,20C 机器提供单行 5w+ TPS 容量

所以 op 需要根据不同场景来看:
场景 1:下单时交易同步调用库存服务完成扣减,库存内部落单并更新库存-1 ;订单取消时,交易负责触发库存的回补动作,对账兜底
场景 2:下单交易同步调用库存预占接口类似 TCC 模式预占库存并发送订单超时队列延迟消息,支付回调触发同步减库存;消费到订单已取消消息后,check 订单支付状态未成功则返还库存信息
场景 3:比较简单不提

实际上业务中基本上都是同步调用,用 MQ 做异步处理会导致系统设计复杂,用户体验并不好,且存在先后顺序问题,不过一般情况下加个时间戳也就解决了
dotw2x
344 天前
想表达异步消费无序的场景?Actor 模型很适合.
xuanbg
344 天前
@MoYi123 不懂业务的技术,做起事来往往事倍而功半。还在那自我感动攻克了什么什么技术难题,实际上根本不需要。真真是可笑。

如果你要和我讨论数据一致性问题,请先把业务场景摆出来。电商有电商的一致性需求,银行又有银行的一致性需求。不确定场景,这事太过复杂,就没什么可讨论的价值。
chaleaochexist
344 天前
@sadfQED2 我就是不会才问的.
请随意喷.
chaleaochexist
344 天前
@xuanbg
1. 付款成功才减 可能超卖.
2. 网络延迟

3. 这是一个脑补的问题, 我没做过电商业务. 实际上我没做过互联网项目. 你也不用着一直反问.
pierswu
344 天前
可用库存=库存-待出库存
创建购买订单,待出库存+1
支付成功 待出库-1 库存-1
支付失败 待出库-1

待出库存可以在数据库也可以在 redis 中
MoYi123
344 天前
@xuanbg 那就来讲讲业务, 库存是电商的一个非常核心的功能, 和仓储, 物流, 财务, 运营, 采购这些都有密切相关, 库存不可靠的话, 你要全公司一起来兼容你的 bug 吗?
xuanbg
344 天前
@MoYi123 库存负数就不能正确充正了吗?
HyperionX
344 天前
@xuanbg 有些业务场景就是要求不允许有超售,异步顺序问题也很常见。不懂可以理性探讨,不必一边见识有限还要 diss 别人 low
MoYi123
344 天前
@xuanbg 比方说我有个地方要算库存预计什么时候销售完, 你给我个负数, 这是不是就有 bug 了?
xuanbg
344 天前
@HyperionX 不能超卖的情况肯定是有的,譬如清库存商品。但正常商品就没有不能允许超卖的。做了 6 年电商,还能不懂这些?真的要锁库存,就不是这么一加一减这么简单了。没个分布式锁那能行?

我的意思是程序员要理解业务,设计最适合最简单最稳定的解决方案,而不是对业务不屑一顾,自顾自在那里炫技。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/946443

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX