幂等性实现方案
字面理解
幂
-
名词:盖东西的巾
大巾谓之幂。——《小尔雅·广诂》
-
动词:覆盖,遮盖
祭祀,以疏布巾幂八尊。——《周礼·天官》
数学中:指一个数自乘若干次形式:幂次(方次)
等
- 形容词:数量、程度相同;相等
幂等性
- 幂是将同样的动作覆盖在前面的结果上
- 等即相同、相等的意思
那么幂等性就可以这么理解:重复数次相等的动作和只做一次动作具有相同的性质
概念
幂等(Idempotence)一个数学领域上的概念,常见于抽象代数中,定义如下:
如果一个函数f(x)满足:f(f(x)) = f(x), 则函数f(x)满足幂等性。
幂等函数/方法:可以使用相同的参数重复执行,并能获取相同结果的函数。
这个概念已被扩展到计算机领域,如:HTTP1.1中幂等定义:
Methods can also have the property of "idempotence" in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single. 《rfc2616 - 9.1.2 Idempotent Methods》
除了网络错误以及请求超时的问题,请求同一个接口多次和单次,对资源所造成的影响是一致的。
所以计算机领域中幂等性:用来描述一个操作、方法或者服务,被多次执行所产生的影响与一次执行的影响相同。
幂等常见的场景:
- 前台重复提交
- 订单付款请求,多次发送,应只扣款用户一次
- 分布式中服务与服务之间的调用
- 生产者与消费者(如Kafka等),消息发送失败,重复发送产生的重复消息
幂等性实现方案
首先需要确定动作/接口是否具有幂等性;如:
- 具有幂等性的业务:
- 查询业务:获取配置文件/用户名等:getUserName(String userId)
- 设值业务:设置对象为初始状态等:setInitStatus()
- 不具有幂等性的业务:
- 递增/减业务:AtomicInteger.incrementAndGet()
判断业务具有幂等性后,那么常见个设计方案如下:
-
唯一约束实现幂等
思路:insert if not exist
如:利用数据库的唯一约束:当表中存在唯一索引,重复请求新增记录就会报错,这时返回已存在的记录并返回。
用户转账为例,假如用户A转账给用户B,用户A本意只转100元给用户B;但由于转账系统的某些情况,实际发生了3次转账给用户B的请求;那么没有幂等设计的情况下表中存在的是两个字段:账户ID、变更金额,用户A减少了100元;用户B增加了100*3元。
幂等设计:增加字段转账ID,那么三个字段:转账ID、账户ID、变更金额;那么这三个字段联合构成唯一约束,这样对象相同的转账请求,表中只能存在一条记录;以上三个转账请求,那么第二次和第三次请求将返回失败结果;
-
更新设置前置条件
思路:check and update
给变更设置一个前置条件,如果满足这个条件则执行变更,否则拒绝变更;重复执行相同请求,如果第一次执行了,则前置条件就会变化,那么后面重复的请求检查前置条件,自然不会满足,则变更不会执行。
-
记录并检查(token机制)
思路:update if token not exist
该思路与唯一约束有点类似;区别如下:记录并检查:发送端制定唯一约束,消费端只需要校验唯一的约束
-
唯一约束方案:消费端制定唯一约束
两者区别是唯一的约束制定方不同。
记录并检查是适用范围最广的实现幂等方案;记录并检查操作也称为token机制活着GUID(全局唯一ID)机制
在发送消息时,给每条消息指定一个全局唯一的ID,消费时,先检查这个ID是否被消费过,如果没有消费过,则执行变更操作,然后将该ID标记为已消费。
具体实现方案:
指正交流微信: snail_java