跳至主要內容

保证接口幂等性

gqzclGolang后端后端分布式幂等大约 3 分钟

保证接口幂等性

什么是幂等

一个简单的例子,客户端发送一条消息到IM服务器,由于超时没有收到响应又重发了一条,但是服务器那边没有做验证,两个重复消息都执行成功了,结果对面收到了两条重复的消息,如果这种情况频繁出现,肯定会极大的影响用户体验,而幂等就是为了防止接口对于重复请求进行重复处理。

如何保证幂等

要保证幂等,就是要保证对于一个接口而言,多次处理同一请求,最后得到的结果都是一样的。

常见的解决方案有以下几种:

前端方面可以在用户点击按钮提交之后,将按钮置为不可用状态,防止用户多次提交。但是这只是简单的防护,主要还是要在服务器端做好幂等。

后端实现接口幂等主要就是上锁或者使用唯一索引或全局唯一ID。

首先对于需要使用幂等的场景主要有以下几种:

  • 前端重复提交

    • 这主要就是用户多次点击提交按钮,后端收到了重复的提交,可能会在数据库中产生多份数据变更,导致一些问题。
  • 接口超时重试

    • 第三方进行接口调用,可能会因为超时再次发起调用,这时候如果上一个请求已经处理了一半了,再次调用就会产生一些意想不到的问题。
  • 消息重复消费

    • 在使用消息中间件时可能一条消息已经被处理但是由于断开连接又被放回队列中被其他消费者重新处理,就会导致异常。

使用token实现(全局唯一ID)

主要步骤:

  1. 客户端先请求获取一个token,服务端生成并将token放入reids中,将token返回给客户端
  2. 客户端进行业务调用时携带token,服务端校验token,校验通过后将redis中的token删除并执行业务
  3. 如果redis中token已经删除,则校验失败,不进行处理并返回结果。

乐观锁

乐观锁就是很乐观,认为拿数据时别人不会修改数据,所以不会上锁,但在提交的时候会确认一下这个数据有没有被更新,适合读多写少的场景使用。

一般使用版本号version,在数据库表中添加一个version字段,当前端发送请求时会带上version,然后后端会将version与数据库中的version进行比对,相等时进行处理,处理后会将version加一,当遇到重复请求时,由于版本号以及变更导致与请求中的version不一致,所有不会对该重复请求进行处理。

基于MySQL唯一索引

主要步骤:

  1. 建立一张去重表,其中某个字段需要建立唯一索引
  2. 客户端去请求服务端,服务端会将这次请求的一些信息插入这张去重表中
  3. 因为表中某个字段带有唯一索引,如果插入成功,证明表中没有这次请求的信息,则执行后续的业务逻辑
  4. 如果插入失败,则代表已经执行过当前请求,直接返回

基于Redis的SETNX

  1. 客户端先请求服务端,会拿到一个能代表这次请求业务的唯一字段
  2. 将该字段以 SETNX 的方式存入 redis 中,并根据业务设置相应的超时时间
  3. 如果设置成功,证明这是第一次请求,则执行后续的业务逻辑
  4. 如果设置失败,则代表已经执行过当前请求,直接返回