如图所示,bool withdraw(account_id, amount)函数表示:从account_id对应的账户中扣除amount数额的钱;如果扣除成功则返回true,账户余额减少amount;如果扣除失败则返回false,账户余额不变。
如果withdraw请求已经被服务器端正确处理,但服务器端的返回结果由于网络等原因被掉丢了,导致客户端无法得知处理结果。如果是在网页上,一些不恰当的设计可能会使用户认为上一次操作失败了,然后刷新页面,这就导致了withdraw被调用两次,账户也被多扣了一次钱。因此我们要做幂等控制。
问题:
如果采用采用分布式事务,通过引入支持分布式事务的中间件来保证withdraw功能的事务性,有哪些中间件可以提供这些功能?具体怎么实现的啊?
首先,RocketMQ 阿里开源的消息中间件,原来叫做MetaQ,文档里写的是支持分布式事务的,因为RocketMQ的各个环节,包括生产者,消费者,broker都是分布式的,所以基本可以保障由于网络原因丢掉,不过我们在项目中并没有使用这个特性.而且RocketMQ存在重复消费的问题,所以文档明确表明了应该业务方自己实现幂等性.
其次,分布式事务我觉得大多数情况下,应该很少会有真的实现这个东西的.大多数情况下只要保证最终一致性就可以了,分布式事务性能较低.
另外,幂等性和你说的分布式事务其实没多大关系,同样的场景,就算你的系统都在一起,如果接收到两个相同的请求应该如何做?如果没做到幂等性,不是分布式场景下同样会扣多.
而幂等性可以通过颁token等(介绍的文章其实很多)实现
首先,这个场景和分布式的事务其实是没有关系的!
其次,关于服务的幂等性问题,有多种保障方式,具体到你这个场景,可以在协议中定义一个请求表示requestID,在服务端,针对此requestID做验证,比如采用简单的redis分布式锁或者其他分布式锁做幂等性验证即可
涉及到失败重试,所以提供方的接口必须是幂等的,但是诸如扣减库存这种接口很难做到幂等,所以建议把失败接口失败重试关闭。
对于题主的这个场景,主要的原因是调用方因为超时失败了,没有对
amount
进行回滚,因为我猜的没错的话这应该是一个RPC调用吧,所以题主确实需要分布式事务来执行事务回滚,具体可以参考ByteTCC用TCC的方式也是一种解决方案