幂等性学习笔记

幂等性(Idempotence)
是一个数学概念,指N次变换与一次变换的结果相同。
接口的幂等性就是指接口调用时,可以使用相同的参数重复执行,重复执行结果对系统产生的影响是相同的。

Http 协议维度
一次请求和多次请求某一个资源应该具有同样的副作用。

get方法:用于获取资源,不应该有副作用,天然幂等性,get请求不会改变资源的状态,不论调用一次还是N次都没有副作用。强调的是相同的副作用,不是每次get请求的结果相同。
delete:用于删除资源,有副作用,但调用一次还是N次副作用都是相同的,具有幂等性
post:新增资源,多次相同的post会在服务器端创建多份资源,因此不具有幂等性
put:更新资源,有副作用,但调用一次还是N次副作用都是相同的,具有幂等性

应用维度
幂等性衍生到软件工程中,指函数(接口)可以使用相同的参数重复执行,不应该影响系统状态,也不会对系统造成额外改变。
既第一次请求时对资源产生了副作用,但是以后的多次请求都不会再对资源产生副作用。多次执行和一次执行产生的副作用相同。

产生幂等性场景

1:网络波动,可能引起重复请求
2:用户重复操作,用户在使用产品时可能无意的触发多次下单交易,甚至因为没有响应而有意触发多次交易。
3:应用使用了失败或超时重试机制(Nginx重试,Rpc重试或业务重试)
4:第三方平台接口,因异常导致多次回调
5:中间件/应用服务根据自身特性,也有可能进行重试
6:客户端重复提交,页面重复刷新:
7:定时任务重复执行

幂等性在哪一层实现
数据访问层

单库下的幂等问题
读请求,查询不会改变数据,天然幂等,不需要做幂等
写请求:增删改,会改变数据,一定要做幂等;

insert
当插入重复数据时
自增主键:一定会有幂等性问题
业务主键:可建立联合唯一索引,可满足幂等

delete:
绝对值删除:删除确定值,满足幂等
相对值删除:比如删除十条分数最低的,不满足幂等

update:
绝对值更新:更新确定值,满足幂等性
相对值更新:比如将价格在原价基础上加100,不满足幂等性

分布式系统中,我们的一次请求可能有多个步骤,跨服务跨事物请求,需要使用分布式事务锁来解决


保证幂等性的方案 
前端幂等性实现
1.用户提交后将按钮置灰,消除用户重复点击产生的副作用。
2.使用post/redirect/get模式,提交表单后进行重定向
3.session中存放特殊标识

后端幂等性实现
1.使用唯一索引
此方案可以限制重复插入数据,当数据重复时,插入数据库会抛异常,不会出现脏数据。

2.Token+Redis方案

幂等性学习笔记

3.状态幂等
针对更新操作,比如业务上需要修改订单状态,订单有待支付,支付中,支付成功,支付失败,订单超时等,设计的时候
最好支持状态单向改变(不可逆),在更新的时候where条件可以加上status=原来的状态值,多次调用实际上也只执行一次。

4.乐观锁实现幂等
如果更新已有数据,可以进行加锁更新,也可以设计表结构时使用乐观锁,通过version来做乐观锁,既能保证效率,又能保证幂等。
乐观锁的version版本在更新业务数据是需要自增。
查询数据,得到版本号。通过版本号去更新,版本号匹配就更新,版本号不匹配就不更新。
update tabe_xxx set money = money-99,version = version+1 where id = xx and version = 1;
采用更新带条件实现乐观锁。比如库存超卖问题
update table_xxx set quality = quality - #countQuality# where quality - #countQuality# >=0;

5.防重表(数据库实现分布式锁)
向防重表中插入唯一索引,插入成功后进行后续业务处理,操作完成后删除防重表数据

6.select + insert
操作之前先查询,符号要求再插入,该方案只有在无并发系统中可解决幂等问题。例如并发请求时,两次查询同时进行,都没有,然后都插入。单机环境中,可结合JVM加锁来保证。

7.分布式锁保证幂等性
在进入方法时,先获取锁,假如获取到锁,就继续后面的流程,假如没有获取到锁,就等待锁的释放知道获取到锁,当执行完方法时
释放锁,锁需要设置超时时间,防止因意外没有释放锁,它可用来解决分布式系统的幂等性。
常用的分布式锁实现方案有redis,zookeeper

8.缓冲队列
将请求都快速地接收下来,放入缓冲队列,后续使用异步任务处理队列中的数据,过滤掉重复的请求。
优点为同步改异步,高吞吐,不足之处就是不能及时返回请求结果,需要后续轮询处理结果。

9.全局唯一来实现幂等
通过source来源+seq***来判断请求是否重复,在并发时只能处理一个请求,其他相同并发请求要么返回请求重复要么等待前面请求执行完成再执行;

幂等性虽然增加了系统业务功能复杂度,降低了执行效率,但保证了系统数据的正确性,因此非常有必要。

备注:B站学习之笔记--2,有不足或错误之处,欢迎大家指出!