接口幂等性思路

摘要:
概念接口幂等性就是用户对于统一操作发起的一次请求或多次请求的结果是一致的,不会因为多次点击而产生了副作用。哪些场景需要保证接口的幂等性?幂等解决方案token机制1.服务端提供发送token接口,需要幂等的接口,就在执行业务前,获取token,服务器将token保存到redis中。当第一次执行后,version变成2后,再次执行上述sql,where条件不成立,也保证了幂等性。全局请求唯一id调用接口时,生成一个唯一id,redis将id存在set中,存在则处理过。

概念

接口幂等性就是用户对于统一操作发起的一次请求或多次请求的结果是一致的,不会因为多次点击而产生了副作用。

哪些场景需要保证接口的幂等性?

  • 用户多次点击按钮。
  • 用户页面回退再次提交
  • 微服务之间相互调用,由于网络波动卡顿,导致feign触发重试机制。
  • 其他情况...

天然幂等情况

以sql为例:

对于select * from table where id =?这种场景,无论执行多少次,都是幂等的。

update table set col =? where col2 = ?,也是幂等的

delete from table where id =? 也是幂等的

insert into table(id,name....) values (1,name,...),如果id是唯一主键,那么该操作也是幂等的。

幂等解决方案

token机制

1.服务端提供发送token接口,需要幂等的接口,就在执行业务前,获取token,服务器将token保存到redis中。

2.然后调用业务接口时,将token放在请求头中。

3.服务器判断token是否存在redis中,存在表示第一次请求,然后删除token,继续执行业务。

4.如果判断token不在redis中,就是重复操作,直接返回重复标记给client,就保证业务不被重复执行。

危险性

1.先删除token还是后删除token

  • 先删除,网络闪断等原因导致业务确实没有执行,然后触发重试机制,由于防重设计,请求不能被执行
  • 后删除,业务处理成功,但服务闪断,出现超时,没有删除token,别人继续重试,导致业务执行多次。
  • 最好的设计为先删除token,如果业务调用失败,重新获取token再次请求。

2.token获取、比较和删除必须为原子性

redis.get(token)、redis.equals、redis.del(token),如果这些操作不是原子性的,高并发情况下,可能get到同样数据,判断都成功,继续业务

可以使用lua脚本保证redis操作的原子性

if redis.call('get',KEYS[1]) == ARGV[1] 
then return redis.call('del',KEYS[1])
else return 0 end

锁机制

悲观锁

select * from table where id = ? for update;

悲观锁使用时一般伴随着事务一起使用,数据库锁定的时间可能会有点长。

注意:id必须时主键或者时唯一索引,不然会导致锁表的结果。

乐观锁

主要适用于读多写少的场景。

更新场景:

例如:update table set col = ? ,version= version+1 where id=? and version =1

可以根据version版本号,操作的时候需要带上version。

当第一次执行后,version变成2后,再次执行上述sql,where条件不成立,也保证了幂等性。

分布式锁

多个机器同时处理相同数据,我们可以加上分布式锁(redis或者zookeeper等),同一时间,只有一个机器能拿到分布式锁,执行业务,处理完成后,释放锁,获取到锁的时候必须判断该业务是否处理过,如果是,则不处理。

唯一约束

数据库唯一约束

插入数据,应该按照唯一索引进行插入,相同的唯一索引只能有一条,可以在数据库中防止重复。但是要保证在同一个业务下发多次请求都生成全局唯一的主键。

分库分表场景时,要保证相同请求落地到同一数据库同一张表。

redis set集合防重复

计算数据的MD5,放入set集合中,每次处理,先看MD5是否已经存在,存在则不处理。

防重表

专门新建一个数据表作为防重表。处理业务时,先将唯一索引(例如订单号)插入防重表,在进行业务操作,并且在同一事务中。

全局请求唯一id

调用接口时,生成一个唯一id,redis将id存在set中,存在则处理过。

可以使用nginx设置每一个请求的唯一id。

proxy_set_header X-Request-Id $request_id

此外,我们通过$request_id 实现客户端->网关服务器->微服务集群A->>微服务集群B.... 实现日志串联。通过trace_id回显,跟踪每次调用路由。

免责声明:文章转载自《接口幂等性思路》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇iOS 如何查看APP的jetsamEvent日志NUC970开发板烧录下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

C# 通过ServiceStack 操作Redis——Set类型的使用及示例

Set:用哈希表来保持字符串的唯一性,没有先后顺序,存储一些集合性的数据 /// <summary> /// Set:用哈希表来保持字符串的唯一性,没有先后顺序,存储一些集合性的数据 /// 1.共同好友、二度好友 /// 2.利用唯一性,可以统计访问网站的所有独立 IP /// </summar...

线上redis热key问题

一个安静的晚上突然被群里报警打断,然后果断不情愿的爬起来找问题,通过监控发现一个服务的QPS暴增,接口响应延迟也上来了,达到s级别了,所以赶紧找问题。 因为应用很依赖redis,第一时间先看是不是它,果然还真是它,看下图: 确定了问题的方向就该找具体原因了,进一步查看Zabbix发现其中一台redis的CPU使用率明显升高,如下图: 连到机器上top发...

Swoole跟thinkphp5结合开发WebSocket在线聊天通讯系统教程

https://cloud.tencent.com/developer/article/1408530 ThinkPHP使用Swoole需要安装 think-swoole Composer包,前提系统已经安装好了Swoole PECL 拓展 tp5的项目根目录下执行composer命令安装think-swoole: composer require top...

Redis内存满了的几种解决方法(内存淘汰策略与Redis集群)

1,增加内存; 2,使用内存淘汰策略。 3,Redis集群。 重点介绍下23; 第2点: 我们知道,redis设置配置文件的maxmemory参数,可以控制其最大可用内存大小(字节)。 那么当所需内存,超过maxmemory怎么办? 这个时候就该配置文件中的maxmemory-policy出场了。 其默认值是noeviction。 下面我将列出当可用内存...

redis 常用操作

/*1.Connection*/$redis = newRedis(); $redis->connect('127.0.0.1',6379,1);//短链接,本地host,端口为6379,超过1秒放弃链接 $redis->open('127.0.0.1',6379,1);//短链接(同上) $redis->pconnect('127.0....

接口测试笔记

1.2 一..接口测试:通过相应的工具或者人工对某一个接口的工作状态进行测试的过程 二..接口测试点: 1.测试接口正确性:保证接口地址与请求方法是正确的 2.测试接口的安全性:有一些接口不能直接暴露,我们需要对它进行炎症之后才可以去调用 3.测试接口的性能:例如:我们需要考虑某一个接口在N多个用户访问的时候工作的压力 4.测试接口的数据:保证接口返回的数...