这里的幂等是参考的数学上的一个概念,在服务中的定义为多次执行所产生的影响均与一次执行的影响相同。
幂等没有一种专门的规则或者方法来实现,都是针对业务具体来做的。
幂等有多个可以讨论的维度。可以从大方向上按照操作(增删改查)来讨论。
实现幂等有两个大方向:
除了天然幂等的操作外,实现重复操作效果一致非常困难,因此一般幂等的解决思路就是防重复。防重复一般分为两步:
唯一令牌可以由客户端也可以由服务端生成。
具体到服务端验证唯一令牌而言,一般有以下方式:
唯一令牌是一种比较通用的方式,如果对于特定的一些业务,它的事务本身有状态,也可以用状态机配合锁来进行幂等。即先用分布式锁或数据库锁来锁住状态,然后修改状态。这样后来的事务发现状态改变就直接返回。
幂等和并发导致的数据不一致是不一样的,并发下的数据不一致解决的是两个同一个时间区间内进行的事务,如何不相互影响。比如有些文章说到的分布式锁和 CAS,其实解决的是并发的情况下数据不一致的问题。
不过 CAS 如果配合版本号的话,也可以起到幂等的效果。比如操作前就给了客户端一个版本号 v1,接下来扣减操作就是 update t set amount = amount-10 where account=a and version=v1。这个本质还是令牌。但这种使用方式很变扭,相当于一个很长的锁了。
对那种 update t set amount = amount-10 where account=a and amount=old_amount 这种,并不能保证查出的 old_amount 就是正确的值,可能已经是前一次操作后的结果了,没有任何意义。这个只能解决并发下数据不一致的问题。
幂等还有一个问题在于一个系统中需要多层幂等。什么意思呢?A 发送请求给 B,B 处理的一部分是要发送请求给另一个系统 C,C 在处理的过程中还可能需要发请求给另一个系统 D…… D 处理完了返回给 C,C 返回给 B,B 返回给 A。在这个链条中,如果 A B C D 中任何一个系统并没有正确实现幂等,也就是出现了 “幂等漏洞”,那么一个请求还是有可能被多次执行,产生区别于一次执行的影响。
每个工程师都应该了解的:聊聊幂等