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

一 什么叫幂等?

通俗的讲解:

发一次接口调用与发多次相同的接口消息都能得到与预期相符的结果。

如下图:

![image](images/SzpOAWrJuPwK5KJA6A1RXIwWVbshmTUAGCWkM0wTKLk.png)

我们来看一条更新操作:

![image](images/oUPRtHlUFFD9W4YSFZcLwU6_sPdpZaWHFIMBwVxCFWM.png)

后台伪代码:

![image](images/fikdvi2OzvCntqVFjoXwB4hZc3VRNtj7dpVP0IcUT4o.png)

发现问题在哪儿了吗?

此接口每重复一次,该数据的值就会加500,此时幂等性就被破坏了。

二 怎么解决?

正常人的思路:

传统办法是代码增加前置判断,if(!员工已调薪){进行调薪}

有什么问题?

需要前置判断的地方太多了,一不留神就漏了

这种技术问题不应该成为干扰程序员写业务代码的因素。

真实的解决方案:

我们需要一种无侵入的幂等解决方案,构建幂等表是我们的通用解决方案,让兄弟们专心的写CRUD就好啦。

如何设计呢?请看下图:

![image](images/MRO4ei-P9Zx-CDAJtXPFjF1K0tnuWI9atLXm4J7qf2U.png)

  1. 我们在传统的应用请求中间加了一层应用网关,其主要作用是转发以及记录请求的一种特殊格式
  2. 应用系统请求头新增requestId,唯一即可,且针对同样的请求内容,requestId保持一致
  3. 请求到达网关,通过ngnix和lua脚本语言的控制将其存放到redis的幂等表,通常我们使用:系统名称+requestId组成,value就是该请求的处理过程,通常有两个,处理中和处理完成,可细分。存活时间靠expire设置
  4. 下次同请求会去redis中判段

遇到重复请求:

![image](images/cvKxQc4kBNgy_TtDkd98dNefxBwsZdWpFTfAiwMvSBs.png)

注意,如果是重试请求,请保持requestId不一致。

正常的后续处理逻辑:

![image](images/zY1AfTUYvb11nAVrb_yjHZKYBfstMSnWhP94epjfYK0.png)

业务系统处理完毕,会更新该key的value。

几个疑问:

  1. 为什么设置存活时间 - 节省redis空间,如果redis宕机,也能保证后续处理都能成功通过
  2. 还要更新redis的状态,是否增加业务代码难度 - 使用aop注解
  3. redis存状态的原因 - 告知当前操作者你这是属于重复请求正在处理不要再请求了,告知用户当前请求你已经成功了,不要重复请求

AOP设计如下:

![image](images/yBQt-g739qzjV1HU6ptBUTW0ZpS6avBQbhEJAI08reU.png)

总结:

优点:后台服务无代码侵入,无需修改业务逻辑

缺点:前台应用要针对幂等进行改造,架构复杂度增加,需要额外部署Nginx、Redis

Last modification:July 5, 2022
If you think my article is useful to you, please feel free to appreciate