高并发下如何保证接口的幂等性?

2022-10-09 10:23:08 浏览数 (1)

点击上方“芋道源码”,选择“设为星标”

管她前浪,还是后浪?

能浪的浪,才是好浪!

每天 10:33 更新文章,每天掉亿点点头发...

源码精品专栏

  • 原创 | Java 2021 超神之路,很肝~
  • 中文详细注释的开源项目
  • RPC 框架 Dubbo 源码解析
  • 网络应用框架 Netty 源码解析
  • 消息中间件 RocketMQ 源码解析
  • 数据库中间件 Sharding-JDBC 和 MyCAT 源码解析
  • 作业调度中间件 Elastic-Job 源码解析
  • 分布式事务中间件 TCC-Transaction 源码解析
  • Eureka 和 Hystrix 源码解析
  • Java 并发源码

来源:blog.csdn.net/weixin_43281498/

article/details/123701060

  • 一、什么是幂等性
  • 二、幂等性的解决方案

一、什么是幂等性

所谓幂等,简单地说,就是对接口的多次调用所产生的结果和调用一次是一致的。

那么我们为什么需要接口具有幂等性呢?设想一下以下情形:

  • 支付接口,重复支付会导致多次扣钱 订单接口,同一个订单可能会多次创建。
  • 在接收消息的时候,消息推送重复。如果处理消息的接口无法保证幂等,那么重复消费消息产生的影响可能会非常大。

基于 Spring Boot MyBatis Plus Vue & Element 实现的后台管理系统 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://gitee.com/zhijiantianya/ruoyi-vue-pro
  • 视频教程:https://doc.iocoder.cn/video/

二、幂等性的解决方案

1)唯一索引

使用唯一索引可以避免脏数据的添加,当插入重复数据时数据库会抛异常,保证了数据的唯一性。

2)乐观锁

这里的乐观锁指的是用乐观锁的原理去实现,为数据字段增加一个version字段,当数据需要更新时,先去数据库里获取此时的version版本号

代码语言:javascript复制
select version from tablename where xxx

更新数据时首先和版本号作对比,如果不相等说明已经有其他的请求去更新数据了,提示更新失败。

代码语言:javascript复制
update tablename set count=count 1,version=version 1 where version=#{version}
3)悲观锁

乐观锁可以实现的往往用悲观锁也能实现,在获取数据时进行加锁,当同时有多个重复请求时其他请求都无法进行操作

4)分布式锁

幂等的本质是分布式锁的问题,分布式锁正常可以通过redis或zookeeper实现;在分布式环境下,锁定全局唯一资源,使请求串行化,实际表现为互斥锁,防止重复,解决幂等。

目前主要有三种方式实现redis的分布式锁:

  • setNx 命令
  • set 命令
  • Redission 框架

具体流程图如下:

具体步骤:

  • 用户通过浏览器发起请求,服务端会收集数据,并且生成订单号 code 作为唯一业务字段。
  • 使用 redis 的 set 命令,将该订单 code 设置到 redis 中,同时设置超时时间。
  • 判断是否设置成功,如果设置成功,说明是第一次请求,则进行数据操作。
  • 如果设置失败,说明是重复请求,则直接返回成功。

需要特别注意的是:分布式锁一定要设置一个合理的过期时间,如果设置过短,无法有效的防止重复请求。如果设置过长,可能会浪费redis的存储空间,需要根据实际业务情况而定。

5)token机制

token 机制的核心思想是为每一次操作生成一个唯一性的凭证,也就是 token。一个 token 在操作的每一个阶段只有一次执行权,一旦执行成功则保存执行结果。对重复的请求,返回同一个结果。token 机制的应用十分广泛。

该方案跟之前的所有方案都有点不一样,需要两次请求才能完成一次业务操作。

  • 第一次请求获取token
  • 第二次请求带着这个token,完成业务操作。

具体流程图如下:

第一步,先获取token。

第二步,做具体业务操作。

具体步骤:

  • 用户访问页面时,浏览器自动发起获取token请求。
  • 服务端生成token,保存到redis中,然后返回给浏览器。
  • 用户通过浏览器发起请求时,携带该token。
  • 在redis中查询该token是否存在,如果不存在,说明是第一次请求,做则后续的数据操作。
  • 如果存在,说明是重复请求,则直接返回成功。
  • 在redis中token会在过期时间之后,被自动删除。

以上方案是针对幂等设计的。

如果是防重设计,流程图要改改:

需要特别注意的是:token必须是全局唯一的。



欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢

已在知识星球更新源码解析如下:

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

代码语言:javascript复制
文章有帮助的话,在看,转发吧。谢谢支持哟 (*^__^*)

0 人点赞