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

1 引言

在实际开发中,经常遇到这样的场景:无论做多少次操作,都应该产生一样的效果或是返回同样的结果。如:

  • 用户发起一笔付款请求,应该只扣除用户一次余额,无论是因为网络重发或是系统bug,都应该只扣除一次
  • 发送通知消息,应该只发一次,要是用户重复收到通知会引起客户反感
  • 分销系统中给推广者计算佣金,每个周期内的佣金只能入库一次,要是重复入库难免会造成财务损失

2 幂等性的概念

幂等(idempotence)是一个数学与计算机概念,常见于抽象代数中。在计算机编程中,一个幂等操作的特点是其任意多次执行所产生的效果与一次执行相同。在比较复杂的场景中幂等操作常常是通过唯一交易号(流水号)实现的。

3 幂等操作的技术实现方案

3.1 查询操作

查询一次和查询多次结果相同,在数据不变的情况下,查询结果相同。SELECT是天然的幂等操作。

3.2 删除操作

DELETE操作也是幂等的,对若干条数据删除一次和删除多次效果相同(注意返回结果不同,删除成功则返回成功删除的条数,删除的数据不存在则返回0)。

3.3 唯一索引

防止新增脏数据。比如支付宝用户账户,当新用户注册手机号成为新用户之后需要创建一个支付宝账户,给手机号设置一个唯一索引,这样就防止同个手机号被重复注册了(当使用唯一索引时,为了防INSERT时报错影响用户体验,所以需要在插入时使用try{…}catch(){…}体,并捕获异常DuplicateKeyException

3.4 悲观锁

获取数据的时候加锁。SELECT * FROM table t WHERE t.id=#{} for update;注意,id字段一定是主键或者是唯一索引,不然会锁表,高并发的时候会出现服务宕机的。悲观锁一般是伴随着事务一起使用。

3.5 乐观锁

乐观锁只是在更新那一刻锁表,其它时候不锁表,所以相对于悲观锁效率更高。乐观锁可以通过版本号和其它字段状态实现:

1. UPDATE table SET username=#{newVal},version=2 WHERE username=#{originVal},version=1
2. UPDATE table SET username=#{newVal} WHERE username=#{originVal}

第2种实现适合不用版本号,更新时只做数据安全校验的场景,适合库存模型:如扣除份额和回滚份额,性能更高。
乐观锁的更新操作,最好是用主键或者唯一索引来更新,这样是行锁,否则更新时会锁表。上述语句改成以下效果更好:

1. UPDATE table SET id=#{newVal},version=2 WHERE id=#{originVal},version=1
2. UPDATE table SET id=#{newVal} WHERE id=#{originVal}

3.6 分布式锁

分布式锁只要是为了解决分布式条件下,某一流程只能由一个系统执行,此时由于构造全局的唯一索引比较困难,例如唯一性字段不好确定,此时就需要引入分布式锁。如果说3.3节的唯一索引是将请求拦截在下游,分布式锁就是将请求拦截在上层。实现机制是:通过Redis或者Zookeeper构造分布式锁(如Redis的setnx()指令),在业务系统插入或更新数据时需要先获取分布式锁,由于锁只能由一个系统获取,所以其它系统都将被拒绝,获取锁的进程执行完之后释放分布式锁

3.7 token机制

主要是为了防止页面重复提交

在这里插入图片描述

注意:token每次都需要申请,有效性只有一次,可以限流。也可以通过SELECT+DELETE的机制来校验token,但这种方式存在并发问题,效率较低。

3.8 SELECT+INSERT

并发不高的后台系统为了支持幂等性,支持重复执行,简单的逻辑是:先查询一下关键数据,判断是否已经执行过,再进行业务处理就可以了。但是该方法不支持高并发的场景。

3.9 对外提供的API接口

比如支付宝提供的付款接口:为了保证幂等性,需要在客户提交请求时附带两个参数:source(来源)和seq(序列号)。用source+seq在数据库里面做联合唯一索引,防止重复支持。

4 小结

幂等操作与是不是分布式和高并发没有关系。幂等性是一个合格的程序员的一个基因,在设计系统时是首要考虑的问题,尤其是在像支付宝、银行、互联网金融公司等涉及金钱的系统,既要高效,又要保证数据准确。

点点关注,不会迷路

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值