幂等是一个数学与计算机学概念,即f(n) = 1^n,无论n为多少,f(n)的值永远为1,在数学中某一元运算为幂等时,其作用在任一元素两次后会和其作用一次的结果相同。在编程开发中,对于幂等的定义为:无论对某一个资源操作了多少次,其影响都应是相同的。 换句话说就是:在接口重复调用的情况下,对系统产生的影响是一样的,但是返回值允许不同,如查询。
幂等性设计主要从两个维度进行考虑:空间、时间。
在HTTP/1.1中,对幂等性进行了定义。它描述了一次和多次请求某一个资源对于资源本身应该具有同样的结果(网络超时等问题除外),即第一次请求的时候对资源产生了副作用,但是以后的多次请求都不会再对资源产生副作用。
使用幂等性最大的优势在于使接口保证任何幂等性操作,免去因重试等造成系统产生的未知的问题。前端重复提交表单
在接口调用时一般情况下都能正常返回信息不会重复提交,不过在遇见以下情况时可以就会出现问题:
幂等性是为了简化客户端逻辑处理,能放置重复提交等操作,但却增加了服务端的逻辑复杂性和成本,其主要是:
现在流行的 Restful 推荐的几种 HTTP 接口方法中,分别存在幂等行与不能保证幂等的方法,如下:HTTP协议语义幂等性
HTTP协议有两种方式:RESTFUL、SOA。现在对于WEB API,更多的会使用RESTFUL风格定义。为了更好的完成接口语义定义,HTTP对于常用的四种请求方式也定义了幂等性的语义。
在业务开发与分布式系统设计中,幂等性是一个非常重要的概念,有非常多的场景需要考虑幂等性的问题,尤其对于现在的分布式系统,经常性的考虑重试、重发等操作,一旦产生这些操作,则必须要考虑幂等性问题。以交易系统、支付系统等尤其明显,如:
对于幂等的考虑,主要解决两点前后端交互与服务间交互。这两点有时都要考虑幂等性的实现。从前端的思路解决的话,主要有三种:前端防重、PRG模式、Token机制。前端防重
针对客户端连续点击或者调用方的超时重试等情况,例如提交订单,此种操作就可以用 Token 的机制实现防止重复提交。简单的说就是调用方在调用接口的时候先向后端请求一个全局 ID(Token),请求的时候携带这个全局 ID 一起请求(Token 最好将其放到 Headers 中),后端需要对这个 Token 作为 Key,用户信息作为 Value 到 Redis 中进行键值内容校验,如果 Key 存在且 Value 匹配就执行删除命令,然后正常执行后面的业务逻辑。如果不存在对应的 Key 或 Value 不匹配就返回重复执行的错误信息,这样来保证幂等操作。
注意,在并发情况下,执行 Redis 查找数据与删除需要保证原子性,否则很可能在并发下无法保证幂等性。其实现方法可以使用分布式锁或者使用 Lua 表达式来注销查询与删除操作。实现流程
通过token机制来保证幂等是一种非常常见的解决方案,同时也适合绝大部分场景。该方案需要前后端进行一定程度的交互来完成。
但是现在有一个问题,当前是先执行业务再删除token。在高并发下,很有可能出现第一次访问时token存在,完成具体业务操作。但在还没有删除token时,客户端又携带token发起请求,此时,因为token还存在,第二次请求也会验证通过,执行具体业务操作。
对于这个问题的解决方案的思想就是并行变串行。会造成一定性能损耗与吞吐量降低。
那如果先删除token再执行业务呢?其实也会存在问题,假设具体业务代码执行超时或失败,没有向客户端返回明确结果,那客户端就很有可能会进行重试,但此时之前的token已经被删除了,则会被认为是重复请求,不再进行业务处理。
修改token_service_order工程中OrderController,新增生成令牌方法genToken
修改token_service_api工程,新增OrderFeign接口。
修改token_web_order工程中WebOrderController,新增获取token方法
修改token_common,新增feign拦截器
修改token_web_order启动类
修改token_service_order中OrderController,新增添加订单方法
修改token_service_order_api中OrderFeign。
修改token_web_order中WebOrderController,新增添加订单方法
通过postman获取令牌,将令牌放入请求头中。开启两个postman tab页面。同时添加订单,可以发现一个执行成功,另一个重复请求。
直接把token实现嵌入到方法中会造成大量重复代码的出现。因此可以通过自定义注解将上述代码进行改造。在需要保证幂等的方法上,添加自定义注解即可。自定义注解
在token_common中新建自定义注解Idemptent
在token_common中新建拦截器
修改token_service_order启动类,让其继承WebMvcConfigurerAdapter
更新token_service_order与token_service_order_api,新增添加订单方法,并且方法添加自定义幂等注解
获取令牌后,在jemeter中模拟高并发访问,设置50个并发访问
新增一个http request,并设置相关信息
添加HTTP Header Manager
测试执行,可以发现,只有一个请求是成功的,其他全部被判定为重复请求。
本文由传智教育博学谷狂野架构师教研团队发布。
如果本文对您有帮助,欢迎关注和点赞;如果您有任何建议也可留言评论或私信,您的支持是我坚持创作的动力。
转载请注明出处!
欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/) | Powered by Discuz! X3.4 |