小白学分布式程序开发13-幂等性

来源:互联网 发布:js拼接字符串逗号隔开 编辑:程序博客网 时间:2024/06/06 05:47

幂等性(Idempotence):分布式架构的基石,即同一个操作无论请求多少次,其结果都相同。

在以前的单应用系统中,我们只需要把数据操作放入事务中即可,发生错误立即回滚,但是再响应客户端的时候也有可能出现网络中断或者异常等等。

举个最简单的例子:

*支付

用户购买商品时使用网上支付,支付扣款成功,但是返回结果的时候网络异常,此时钱已经扣了,用户再次点击按钮,此时会进行第二次扣款,返回结果成功,用户查询余额返发现多扣钱了,流水记录也变成了两条。

如何解决上述问题呢,此时就需要用到幂等设计?

幂等设计:单次支付请求,也就是直接支付了,不需要额外的数据库操作了,这个时候发起异步请求创建一个唯一的ticketId,就是门票,这张门票只能使用一次就作废,具体步骤如下:

1.异步请求获取门票

2.调用支付,传入门票

3.根据门票ID查询此次操作是否存在,如果存在则表示该操作已经执行过,直接返回结果;如果不存在,支付扣款,保存结果

4.返回结果到客户端

如果步骤4通信失败,用户再次发起请求,那么最终结果还是一样的


举例:

假设有一个从账户取钱的远程API(可以是HTTP的,也可以不是),我们暂时用类函数的方式记为:

       bool withdraw(account_id, amount)

       withdraw的语义是从account_id对应的账户中扣除amount数额的钱;如果扣除成功则返回true,账户余额减少amount;如果扣除失败则返回false,账户余额不变。

       我们可以通过一些技巧把withdraw变成幂等的,比如:

       int create_ticket()

       bool idempotent_withdraw(ticket_id, account_id, amount)

       create_ticket的语义是获取一个服务器端生成的唯一的处理号ticket_id,它将用于标识后续的操作。idempotent_withdraw和withdraw的区别在于关联了一个ticket_id,一个ticket_id表示的操作至多只会被处理一次,每次调用都将返回第一次调用时的处理结果。这样,idempotent_withdraw就符合幂等性了,客户端就可以放心地多次调用。

       基于幂等性的解决方案中一个完整的取钱流程被分解成了两个步骤:

       1、调用create_ticket()获取ticket_id;

       2、调用idempotent_withdraw(ticket_id, account_id, amount)。

       虽然create_ticket不是幂等的,但在这种设计下,它对系统状态的影响可以忽略,加上idempotent_withdraw是幂等的,所以任何一步由于网络等原因失败或超时,客户端都可以重试,直到获得结果。如图所示:



和分布式事务相比,幂等设计的优势在于它的轻量级,容易适应异构环境,以及性能和可用性方面。在某些性能要求比较高的应用,幂等设计往往是唯一的选择。
幂等性是高并发分布式架构、分布式系统数据一致性的底层基本原理。

最后别忘了关注我们的微信公众号,也可以加入我们的QQ群(635943139),谢谢*o*!

原创粉丝点击