接口幂等性定义
我们实际系统中有很多操作,是不管做多少次,都应该产生一样的效果或返回一样的结果。满足这些条件的接口都应该实现幂等性。
例子
用户下订单后,由于网络波动,在前端没有接收到后端成功请求之前。用户多次提交相同请求参数的请求,可能会导致出现多次扣款和多次订单情况。
解决方案
- 通过唯一标识来区分,订单编号,流水编号(不与当前时间关联)增加数据库唯一索引
- 数据提交前要向服务的申请token,token放到redis设置token有效时间; 提交后后台校验token,同时删除token,生成新的token返回。token特点:要申请,一次有效性,可以限流。注意:redis要用删除操作来判断token,删除成功代表token校验通过,如果用select+delete来校验token,存在并发问题,不建议使用;
- 锁机制 悲观锁(获取数据时加锁 for update mysql中的myisam不支持行锁和事务)和乐观锁(更新的时候加锁 添加version列) 注意使用唯一索引或主键索引来查询防止产生锁表
- 分布式锁 分布式系统,构建全局唯一索引比较困难,例如唯一性的字段没法确定,这时候可以引入分布式锁,通过第三方的系统(redis或zookeeper),在业务系统插入数据或者更新数据,获取分布式锁,然后做操作,之后释放锁,这样其实是把多线程并发的锁的思路,引入多多个系统,也就是分布式系统中得解决思路
- 在并发不高的后台系统,或者一些任务JOB,为了支持幂等,支持重复执行,简单的处理方法是,先查询下一些关键数据,判断是否已经执行过,在进行业务处理,就可以了。注意:核心高并发流程不要用这种方法;
遇到过的问题
购买商品时,调用付款接口时,需要对账户扣款,并且生成对应账户的资金变动记录时,前端短时间内发送2次相同参数的请求,生成了相同两笔订单,生成了2笔资金变动记录,由于在查询账户余额时加入了悲观锁,由于未知原因导致用户账户余额只扣除了一次的钱。从而导致账户对账时出现错误。初步猜测跟代码顺序有关系,有待试验