高并发下接口幂等性解决方案

发布时间:2023年12月19日

高并发下接口幂等性解决方案

1. 幂等性概念:

①. 一个幂等操作指任意多次执行所产生的影响跟一次执行的影响相同.

②. 幂等函数(幂等方法):
   a. 可以使用相同参数重复执行,并能获得相同结果的函数.
   b. 这些函数不会影响数据状态,也不用担心重复执行会对数据造成改变.
   c. 如:"getUsername()"、"setTrue()"就是一个幂等函数.

③. 总结:
   幂等就是一个操作不论执行多少次,产生的效果和返回的结果都是一样的.

2. 业务场景:

①. 前端重复提交选中的数据,后台只能产生一个反应结果.
②. 发起一笔付款请求,只能扣用户账户一次钱,当遇到网络重发或系统bug重发,也只能扣一次钱.
③. 发送短信、极光推送等消息,也只能发一次.
④. 创建业务订单,一次业务请求只能创建一个.

3. 技术场景:

(1). mysql:

①. 查询操作:
   a. 在数据不变的情况下,查询一次和多次的结果是一样的.
   b. select是天然的幂等操作.

②. 删除操作:
   a. 删除一次和多次都是把数据删除,会体现在返回结果不一样.
   b. 删除的数据不存在,返回0.
   c. 删除的数据多条,返回多条值.

③. 唯一索引:
   a. 防止新增脏数据.
   b. 如:支付宝每个用户只能有一个资金账户,将资金账户表的用户ID加唯一索引,可以防止给用户创建资金账户多个.
   c. 唯一索引或唯一组合索引是用来防止新增数据存在脏数据.

④. 悲观锁:
   a. 加锁获取数据:
      select * from table_xxx where id='xxx' for update;
   b. 注:id字段一定是主键或唯一索引,否则会锁表.
   c. 悲观锁使用时,一般伴随事务一起使用,数据锁定时间可能会很长(根据实际情况选用).

⑤. 乐观锁:
   a. 只在更新数据那一刻锁表,其它时间不锁表.
   b. 相对于悲观锁,效率更高.
   c. 实现方式可以通过version或其他状态条件:
      1. 通过版本号实现:
         update table_name set name=xx, version=version+1 where id=#id# and version=xxx
      2. 通过条件限制实现:
         update table_name set avai_amount=avai_amount-#subAmount# where  id=#id#  and  avai_amount-#subAmount# >= 0
         要求:quality-#subQuality# >= ,这个情景适合不用版本号,只更新是做数据安全校验,适合库存模型,扣份额和回滚份额,性能更高;
   d. 注:乐观锁的更新操作,最好加主键或唯一索引来更新,这样是行锁,否则更新时会锁表.

(2). redis:

①. token机制:
a. 防止页面重复提交.
b. 当客户端请求页面时,服务器会生成一个随机数Token保存到redis或session中,再将Token发给客户端(hidden表单).
c. 下次客户端提交请求时,Token会随着表单一起提交到服务器端.
d. 服务器端第一次验证相同通过后,会将Token值更新,若是用户重复提交,第二次的验证判断将会失败.


(3). 分布式锁:

如果是分布是系统,构建全局唯一索引比较困难,例如唯一性的字段没法确定,这时候可以引入分布式锁,通过第三方的系统(redis或zookeeper),在业务系统插入数据或者更新数据,获取分布式锁,然后做操作,之后释放锁,这样其实是把多线程并发的锁的思路,引入多多个系统,也就是分布式系统中得解决思路。要点:某个长流程处理过程要求不能并发执行,可以在流程执行之前根据某个标志(用户ID+后缀等)获取分布式锁,其他流程执行时获取锁就会失败,也就是同一时间该流程只能有一个能执行成功,执行完成后,释放分布式锁(分布式锁要第三方系统提供);


文章来源:https://blog.csdn.net/m0_68635815/article/details/135094298
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。