事故流程
提现业务大体流程:
- 通过 user-service 调用 trade-service,即用户生成流水后向交易服务发起转账请求
- trade-service 调用三方支付平台,发起实际的出款请求
- 三方支付平台完成订单后,异步回调 trade-service,通知支付结果
- trade-service 回调 user-service,根据支付结果,生成流水,并进行相对应的扣除代扣金额,或归还代扣金额
发生事故时,trade-service 响应 user-service 超时,使得 user-service feign 调用超时,进行了数据回滚(修改提现流水的状态为已失败、归还用户的代扣余额、生成归还余额的明细流水)。但实际上,trade-service 完成了三方支付平台的调用,完成了出款,只是响应时间超过了 feign 的最大等待时间。最终导致:
- 用户的余额没扣,但是还是出款了
- 支付成功的回调达到后,又扣减了一次代扣金额,金额相关数据错乱了
问题分析
冷静分析下,这个问题的本质原因在于,对微服务内部节点发起了转账调用,无论这期间发生了什么样的异常,都进行了数据自动的回滚。可是发生了异常并不一定就代表调用三方支付平台异常,也可能 trade-service 自身的问题,但也可能就是三方支付平台返回了异常。比如:
- 用户的账户被冻结了
- 公司的出款帐号余额不够了
- 已经达到了用户每月的收款额度上限
所以,需要对数据回滚增加条件限制,不是所有的情况都可以进行自动回滚,一定要只判断可以回滚的情况,而不是判断不能回滚的情况。
解决方式
控制回滚数据的异常类型,只针对于那些已知的异常类型进行数据的回滚,如问题分析中提到的三点。其余的所有异常,数据现场留痕,后期进行人工补偿。数据可以弥补,但是钱绝对不能多出,555。