1. 简介
接口幂等性指的是无论调用多少次一个接口,都能得到相同的结果。
为什么接口幂等性
接口幂等性在系统中是常见的问题,一般单机系统也会出现这样的问题,例如表单提交时,多点击几次提交按钮,若没有做限制,就会出现多条数据生成。能发送类似情况的场景有:
- 前端表单重复提交
- 恶意提交,刷单
- 接口超时重试
- 消息重复消费
2. 解决方案
方案一:数据库乐观锁
思路:在数据库上加上版本号之类的字段,来实现乐观锁,达到接口幂等性效果。
方案:当同时操作同一条数据时,由于版本号初始值一致,仅有一个请求是可以正确执行,剩余的都会以失败结束。这样每次对该数据库该表的这条数据执行更新时,都会将该版本标识作为一个条件,值为上次待更新数据中的版本标识的值。
方案二:分布式锁
思路:在分布式环境下保证同一个请求只会被处理一次
方案:当一个请求到达后,检查对应的分布式锁(例如 Redis 中的 Key)是否存在,如果锁存在,则表示该请求已经被处理过,直接返回处理结果;如果锁不存在,则先加锁,然后进行业务操作,最后释放锁。
ps:由于分布式系统中网络延迟、宕机等因素的存在,可能会导致原子性及锁过期时间等问题。针对这些问题可以通过优化锁算法、增加过期时间、续约机制等措施来提高分布式锁的可靠性。
方案三:Token机制(标识)
思路:在请求中添加一个唯一标识符,以标识该请求是否已被处理
方案:在每个表单提交或接口请求中添加一个token,一般是随机生成一个字符串或使用UUID等方式生成。当请求服务器时,服务器会根据该token判断是否已经处理该请求,已处理则直接返回响应结果,未处理则更新token状态并进行后续业务操作。当客户端收到响应后,将token删除或标记为已处理,以避免后续重复提交。
3. 使用场景
乐观锁
常在消费消息中间件时,消息消费时使用。来保证消息只会消费一次,在消息中添加版本号,或者更新原始数据信息,保证消息只消费一次。
分布式锁
适用于分布式系统中数据一致性问题比较严重的场景,例如在电商网站上用户下单时使用。由于下单过程中库存可能会发生变化,如果多个用户同时提交订单,就可能导致超卖或出现异常下单的情况。此时可以通过分布式锁来控制同一请求只能被处理一次,以保证不会出现重复购买或库存异常等问题。
ps:下单操作不仅仅使用分布式锁来保证此次操作。
Token机制
适用于客户端向服务器发送网络请求的场景,如API接口、订单支付等。在客户端发起请求时,可以将请求参数中添加一个唯一Token标识符,并在服务端做校验,只有当Token唯一且在有效期内才能继续执行请求,否则将被视为重复操作或者过期操作,返回相应的提示信息。
4. 总结
几种的接口幂等性的方案大同小异,用悲观锁、乐观锁的方式来实现,都是比较简单的。