假设现在有商城和会员两个服务,用户在商城使用积分购买商品,但是用户的积分是存储在会员服务的。
现在的流程如下:
扣减积分发生在会员服务中,创建订单及修改订单状态为已支付发生在商城服务中,所以会出现“扣减了积分,但是没有成功创建订单”这种情况。
应该怎么解决这个问题呢?
1
nonoyang 2022-01-15 21:55:57 +08:00 via iPad
这应该是很典型的分布式事务吧,补偿机制?
|
2
qza1212 2022-01-15 21:59:03 +08:00
感觉顺序就错了,应该先创建订单,然后再扣积分
|
4
qza1212 2022-01-15 22:21:14 +08:00
@JasonLaw #3 了解了,两个方案吧,要么把积分扣减和将订单改为已支付这两个操作写到一个事务里,这里必然要用分布式事务。
或者也可以在扣减积分记录里记下订单 ID ,这样查询订单是未支付的时候需要再查一下积分记录,查看是否真的扣减成功。 |
5
dzdh 2022-01-15 22:24:42 +08:00
经典事物补偿
|
6
LinSP 2022-01-15 22:25:49 +08:00
用分布式事务感觉重了,扣减积分和订单对应一下就行,订单失败了就补偿下
|
7
dzdh 2022-01-15 22:26:02 +08:00
不会出现"扣减了积分,但是没有成功创建订单"的情况。
只会出现事物超时下单失败,积分重新+回去。 |
8
gancl 2022-01-15 23:28:49 +08:00
可以积分先锁住,创建订单失败则解锁积分;创建订单成功则用掉锁住的积分吗?
|
9
akira 2022-01-15 23:55:47 +08:00
扣减 改为冻结,订单成功后才真的扣
|
10
clf 2022-01-16 01:37:26 +08:00
创建订单-订单中就包含了需要消耗的积分和会员 ID
扣减积分-扣减记录中包含了订单的 ID 当订单和积分均存在时,这两条数据才是订单创建成功+积分扣除成功;如果不存在对应数据,用户端两条数据均不会显示,并触发回滚机制(触发回滚后提醒用户失败原因) |
11
Rocketer 2022-01-16 02:14:34 +08:00 via iPhone
我记得在某银行的积分商城里见过这个场景,积分记录里有创建订单扣减和取消订单(其实是订单失败)增加两条记录
|
12
levelworm 2022-01-16 03:06:53 +08:00 via Android
@LinSP 请教一下,这有似乎个问题,如果补偿的时候商品卖完了怎么办?感觉还是强制要求确认订单成功之后再扣减积分用户体验比较好?不过如果扣减不成功,补偿也会出现万一用户下单多次导致补偿的时候无分可扣,还得取消多余的订单。。。是不是我想的太多了。。。
|
14
winglight2016 2022-01-16 09:27:15 +08:00
@JasonLaw 不一定非要用分布式事务来解决。一是可以用工作流来处理,二是可以用 MQ 半事务,分布式事务个人觉得不可靠,是最后的选择。
|
15
751327 2022-01-16 17:38:21 +08:00 1
本地消息表、事务消息、tcc 方案、Seata AT
|
16
beitayongguo 2022-01-17 11:50:47 +08:00
业务上创建订单强依赖扣减积分 TCC 可能好点。 如果不强依赖,那搞成异步 MQ 吧~ 本地消息表事务消息都可以
|
17
julyclyde 2022-01-17 12:28:43 +08:00
其实积分场景用事后对账机制挺好的
|
18
TUNGH 2022-01-17 12:38:11 +08:00
我说一个解决方案吧,先创建订单,订单状态是中间态,比如支付中或者处理中,然后去扣积分,扣除成功就改订单支付成功状态,扣除失败就改订单状态为创建失败,失败原因是积分不足.当然,如果是积分和现金一起支付,那必然先锁住积分再创建订单.
|
19
eijnix 2022-01-17 16:36:09 +08:00
巧了 我就是某电商公司做会员的。。
我们是这样做的,积分表有个预扣字段,首先进行预扣,并记录需要下订单的商品的唯一 id ,再进行下订单,下订单失败则进行积分回滚,否则就进行积分正式扣除(核对下订单的商品的唯一 id ) 当然这里会发一些 kafka 给重试服务,是为了防止服务 down 掉的情况 |
20
eijnix 2022-01-17 16:41:49 +08:00
你现在的流程的话已经跟商城服务有太多的耦合了,而且用户的入口似乎是商城那边,做法可能跟我这个就不太一样了,有点像我们会员中的 offer 服务,我们用的是 tcc 方案
|
21
x66 2022-01-17 17:54:54 +08:00
@TUNGH 事实上你的方案没有解决扣减积分和修改订单状态不在同一个事务里的问题。
如果扣减积分成功,修改订单状态失败,还是需要一个补偿机制。 |
23
vibbow 2022-01-19 02:26:15 +08:00
先扣积分,然后创建订单。
之后检查订单是否创建成功,失败的话退回积分。 |