什么是接口的幂等性?
幂等作为一个数学概念,是指在某个一元运算过程中,任意次数的运算结果会与一次运算结束后的结果是相同的。在计算机操作中,一个幂等操作的特点是任意执行一次或者多次其操作所产生的影响与执行一次操作产生的影响结果是一样的。
而所谓的幂等函数或者是幂等方法,则是指如果使用相同的参数进行重复执行,执行一次与执行多次所产生的结果是一样的。也就是说函数或者是方法的不会对整个系统的状态产生影响,也不用担心多次执行函数会对系统产生改变。
接口幂等性则是指对于某个接口来讲,请求一次的效果与请求多次对系统本身的影响是一样的,也就是说第一次请求对系统产生了一定的影响,但是在后续请求过程中对系统产生的影响与第一次请求所产生的影响是一样的,不会对系统带来副作用。
为什么需要幂等性操作?
一般我们向外提供的接口都是可以正常返回信息的,也就不会出现重复调用接口的情况,但是如果遇到了网络卡顿、页面卡顿等情况有可能会出现页面表单重复提交,网络卡顿有可能会出现接口超时,造成的接口重复调用,或者是会出现恶意攻击接口等情况。
而如何接口采用了幂等性操作其最大的优势就是可以保证接口调用一次的效果与多次调用的效果是样的,可以有效的避免因为重复调用而带来的诸多系统未知错误。
引入幂等性之后可以简化客户端的处理逻辑,也能有效的防止表单的重复提交。但是引入幂等性所付出的代价就是后端处理逻辑会相对较复杂。所以,在引入幂等性操作的时候首先需要考虑的就是是否有必要引入,要根据实际的情况,结合具体的业务来完成对幂等性的引入。
如何所实现幂等性操作?
第一种、数据库唯一键约束
数据库的主键唯一性约束,一般比较适合对于插入操作的幂等性约束,因为我们知道,一张数据库表中的一条记录只能有一个唯一的主键来进行标识记录。
使用数据库主键唯一性约束作为幂等条件的时候需要注意的是,在实际开发中我们所使用的主键并不是数据库中自增的主键,而是采用一些分布式的ID来充当组件,这样才能有效的保证在分布式环境下的ID全局唯一性。这样就可以保证幂等性的操作了。如下图所示。
主要流程包括
- 客户端执行创建请求,调用服务端接口
- 服务端执行业务逻辑采用分布式ID生成算法生成一个ID,将对应的ID插入对应记录的主键,然后执行数据插入操作。
- 服务端将对应的数据插入到数据库中,如果这个时候继续有同样的请求进入,则数据库就会报出主键冲突的异常,这个时候就可以提示客户度数据库中已存在该条信息。请勿重复提交。
第二种、数据乐观锁操作
数据库乐观锁操作是一种适用于更新操作的的幂等性解决方案。其实现需要我们在数据库表中多加入一个字段来充当当前数据版本号的标识。这样如果对这个数据进行更新的时候,就可以将该版本号作为标识来判断数据是否被更新了。
update table set number1 = 123 where id= 1 and version = 5;
例如如果执行了上面这个操作之后,我们可以将id = 1 并且 version=5 的数据进行了更新,在更新成功之后,version就会变成 6,那么如果这个时候还有请求进入其带入到更新操作依然会是version为5的操作,实际上,这个时候version已经变成了6,那么显然version为5的操作就是找不到的,就可以保证了更新操作的幂等性。并且多次执行也不会对数据产生多余的影响。
第三种、利用Token防止重复提交
针对前后端分离项目,在客户端连续进行点击按钮或者是调用超时的时候,利用Token就可以有效的防止重复提交。
简单的说就是在调用方调用接口的时候先向后端请求了一个全局的TokenID,在请求的时候携带这个Token进行调用。后端需要根据这个Token作为key,用户信息作为value到缓存中去验证,如果存在对应的数据则执行删除操作,然后后续的逻辑正常执行,如果没有找到或者是找到的数据不匹配那么就无法执行后续的操作。有点像是令牌,这个令牌的获取也可以进行流控操作。通过令牌的多少来控制发到后端请求的数量,这样也可以有效的减轻后端系统的压力。如下图所示
- 服务端提供获取Token的接口,这个Token可以是一个序列号也可以是一个分布式ID也可以其他唯一标识的字符串
- 客户端调用获取Token接口,这个时候服务端会生成一个Token串。
- 然后将该字符串存储到Redis缓存中,并且对这个Token串设置一个过期时间
- 将Token返回到客户端,客户端将Token携带到请求头部
- 客户端执行表单提交操作,并且将头部的Token一起发到服务端
- 服务端获取到头部的Token之后,根据Token从Redis缓存中查找对应的信息。判断是否存在。
- 如果服务端判断到对应Key存在并且信息匹配,那么就删除对应的key之后执行后续的业务,如果不存在则抛出异常提示重复提交异常。
注意,在并发场景中,执行Redis操作需要保证操作的原子性,这个时候有可能因为多个线程的进入而无法保证幂等性操作,这个是时候就需要采用分布式锁机制来保证原子性操作。
第四种、唯一标识匹配
通过上面的分析,要想保证幂等性操作,其实主要就是要让后续的操作逻辑能够正常执行,那么这个时候,我们只需要保证每次请求都可以被唯一标识就可以保证是否重复提交。这个时候我们可以为每一个请求分配一个唯一的标识,这个标识是一个短期标识。并且一般由下游的服务来生成,这个时候就保证了当上游服务请求发到下游服务的时候两者都知道对应的请求是否发生了变化。如下图所示。
上面这个操作有点类似于Token获取操作的思路。可以参照Token方式来对其进行理解。
总结
上面我们介绍了接口幂等性操作,并且介绍了保证幂等性的几种方式。当然上述的这些内容在单体应用的情况下基本上不会出现问题,但是如果在并发场景下一定要结合锁机制来使用才能有效的保证数据的安全性。