1.接口的幂等和防重对比
防重设计:主要为了避免产生重复数据,对接口返回没有太多要求。
幂等设计:除了避免产生重复数据之外,还要求每次请求都返回一样的结果。
2.幂等方案
1.redis setnx存放唯一键
该方案通过把请求的唯一键,例如:requestId,使用redis的setnx写入到redis中,如果写入成功,说明之前没写入过,正常处理业务逻辑即可;如果写入失败,那么说明之前处理过,
针对处理的情况,根据requestId,把结果查询出来,组装返回。
另外:redis需要留意过期时间,一般设置4,5分钟的过期即可,太长了重试情况也是比较少。
优势:
- 入口层就拦截,减少后续处理浪费资源
劣势:
- 99%的情况都不会重试,这一层redis耗时和存储占用就浪费了
- 依赖redis中间件,增加了风险点
2.mysql唯一索引
该方案通过把请求的唯一键当做唯一索引写入DB,例如:requestId,如果写入成功,说明之前没写入过,正常处理业务逻辑即可;如果写入失败,就会抛出Sql重复插入异常,那么说明之前处理过。
针对处理的情况,根据requestId,把结果查询出来,组装返回。
优势:
- 少查一次redis,性能有所提高
- 支持幂等的实效性长
劣势:
- 如果是重试的请求,本来可以不用走后续流程的也会走接口的流程,某些情况下会影响性能。
- 如果涉及的业务链路很长,保存在最后一步,中间涉及的上下游http没做幂等处理,会存在数据不一致的情况。
3.幂等方案选取
1.redis setnx存放唯一键
该方案数据库层面不做任何处理,适合:
- 后台管理系统请求,而且对幂等性要求不高,做个请求去重即可
- 库里面不存requestId这些唯一的信息
上面这两个场景都是对幂等性要求不高的时候,可以这样处理,如果是关键接口还是需要用2、3方案保险
2.mysql唯一索引
适合大部分不复杂的场景,或者请求链路清晰,整个业务的上下游、中间件等支持幂等操作的场景
3.redis setnx + mysql唯一索引
这种是结合redis和mysql唯一索引,目的是防止涉及的业务链路很长,保存在最后一步,中间涉及的上下游http没做幂等处理,存在数据不一致的情况
针对的场景:
- 该接口太复杂,不确定上下游调用的情况(上下游是否做了幂等、redis缓存是否会变化等)
注意:幂等要把之前第一次有效的请求的结果返回回去,注意请求有可能是成功也有可能失败(失败比如:请求的某些code不存在),如果是标准的幂等,应该是要不管成功、失败都要返回一致的。
但是大部分场景我们只针对返回成功的情况做幂等也是可以的
4.一些其他优化处理
1.对请求参数做了摘要, 参数一致的情况下才返回幂等结果。
怕他改了参数 类似一个订单他先是请求的100块, 后面同一个请求id,但是入参不一样,再请求的200块, 还是返回成功 那就有点说不过去了,调用方也懵逼