分布式系统最终一致性的防护栏---幂等

来源:互联网 发布:数据预测方法 编辑:程序博客网 时间:2024/04/29 10:36

实践证明,在分布式系统,同时满足CAP定律(一致性、可用性、分区容错性)是不太可能的。虽然强一致性可以提高用户的体验,但是牺牲了系统的可用性,在经过综合的考虑和验证下,业界普遍的做法是在一致性和可用性进行了平衡,也就是提高系统的可用性,保证系统的最终一致性。而系统的幂等就是保证系统由强一致性转换为最终一致性的防护栏。

幂等是何许东西,举例说明。

假设应用系统是一个交易系统,此系统提供了取现的业务withdraw(account_id,amount)函数,如下图所示


正常流程应该是,客户端发起提现请求1,系统收到请求后把对应账户的余额减去提现额度,然后返回success给客户端2,客户端收到系统的响应后,提现完成。

但是,由于网络或者其他原因导致2断掉,即系统的响应没有到client。client没有收到响应,就会重复请求3(刷新等),系统收到client提现请求,又会做一次总额减少的操作,然后完成之后,响应success给客户端4,在这种情况下,本来用户提取100,结果账户余额减少了200,不是用户想看到的,用户体验差。为了消除这种问题,就要对提现这个功能做幂等。

什么是幂等,幂等就是对方法多次操作的结果和一次操作的结果是一致的。

对于上述提现系统的幂等的一种实现方法如下:

每次提现client都会带着一个id,server后端接到请求后会通过id来判断,是不是已经操作。如下图


如上图所示,client在每次提现之前都会去服务器拿一次ticket,拿到ticket之后,然后带着ticket去请求提现功能,server收到提现请求后,首先会check客户端传过来的ticket,判断是不是重复请求。这样就能解决重复提交的问题。

正常流程应该是1->2->5->6,中间环节出现任何问题,都不会发生重复请求,例如,假如2没有到达client,6没有到达client。假设2没有到达,用户会重复发送请求3,得到一个新的ticket不影响整个流程的业务。如果6没有到达client,client重复7发送到server,server拿到ticket,判断此请求已经处理,不在处理这次请求,响应client,达到用户正确的提现行为。

下面就说一下怎么达到最终一致性,还是举例子来说明

一个交易系统,用户购买产品,会产生两个操作,用户余额减少和增加交易记录,假设用户余额表和交易记录表是分库存储的,所以会产生两个事务,最终一致性就是保证这两个事务最终一致。

具体实践,如下:

一种常见的做法就是在第一个事务中通过本地事务的事务保证,保证"增加交易记录"和“增加一条异步消息队列记录”同时成功或者同时失败,增加一张updates_applied表,此表记录已经处理过的消息,第二个事务,读出消息队列的消息(不删除),通过判断updates_applied表,来判断此消息是不是已经执行,如果没有执行,则执行相关业务逻辑(保证幂等性),执行完此消息后,在updates_applied增加一条操作记录,事务结束。用事务保证异步消息的执行和增加updates_applied的记录的一致性操作,然后删除队列。


在实践中,可以灵活运用


0 0
原创粉丝点击