分布式架构中的幂等性
程序猿小白
今天我们学习什么新知识?
攻城狮小明
我们来学一下分布式架构中的幂等性。
幂等性
幂等性(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是幂等的,所以任何一步由于网络等原因失败或超时,客户端都可以重试,直到获得结果。如图所示:
和分布式事务相比,幂等设计的优势在于它的轻量级,容易适应异构环境,以及性能和可用性方面。在某些性能要求比较高的应用,幂等设计往往是唯一的选择。
幂等性是高并发分布式架构、分布式系统数据一致性的底层基本原理。
程序猿小白
又学到了新的知识,我会继续努力学习的。
攻城狮小明
我们也会持之以恒为大家带来好的知识分享,下节课再见。
小白程序猿
你若有干货或程序开发中的趣事,欢迎前来爆料啊~