什么是幂等性?四种接口幂等性方案详解!

什么是幂等性?四种接口幂等性方案详解!_第1张图片

幂等性在我们的工作中无处不在,无论是支付场景还是下订单等核心场景都会涉及,也是分布式系统最常遇到的问题,除此之外,也是大厂面试的重灾区。

知道了幂等性的重要性,下面我就详细介绍幂等性以及具体的解决方案,希望对大家有所帮助@mikechen

什么是幂等性

幂等是一个数学与计算机学概念,在数学中某一元运算为幂等时,其作用在任一元素两次后会和其作用一次的结果相同。

所谓接口幂等性,就是一次和多次请求某一个资源对于资源本身应该具有同样的结果。

什么是幂等性?四种接口幂等性方案详解!_第2张图片

也就是说,在接口重复调用的情况下,对系统产生的影响是一样的,这就是幂等性。

 

为什么需要幂等性

业务开发中,经常会遇到重复提交的情况,无论是由于网络问题无法收到请求结果而重新发起请求,或是前端的操作抖动而造成重复提交情况。

在交易系统,支付系统这种重复提交造成的问题有尤其明显,比如:用户在APP上连续点击了多次提交订单,后台应该只产生一个订单。

什么是幂等性?四种接口幂等性方案详解!_第3张图片

再比如:向支付宝发起支付请求,由于网络问题或系统BUG重试,支付宝应该只扣一次钱,而不是多次重试,造成多次扣钱。

什么是幂等性?四种接口幂等性方案详解!_第4张图片

再比如:现在是微服务的时代,服务化接口在外部调用者会存在多次调用的情况(考虑网络中断重试等),为了防止外部多次调用对系统数据状态的发生多次改变,将服务设计成幂等,就是为了防止多次重试,造成系统不一致的问题。

通过以上典型的支付场景就知道幂等性的重要性了,那问题来了,如何实现幂等性,有哪些解决方案?下面我们接着聊。

 

幂等性的解决方案

数据库唯一主键

数据库唯一主键的实现主要是利用数据库中主键唯一约束的特性,一般来说唯一主键比较适用于“插入”时的幂等性,其能保证一张表中只能存在一条带该唯一主键的记录。

唯一索引 使用唯一索引可以避免脏数据的添加,当插入重复数据时数据库会抛异常,保证了数据的唯一性。

唯一索引表的创建示例如下:

CREATE TABLE `table_name` (
  `id` int NOT NULL AUTO_INCREMENT,
  `orderid` varchar(32) NOT NULL DEFAULT '' COMMENT '唯一id',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uq_orderid` (`orderid`) COMMENT '唯一约束'
) ENGINE=InnoDB;

使用数据库唯一主键完成幂等性时需要注意的是,该主键一般来说并不是使用数据库中自增主键,而是使用分布式 全局ID 充当主键,这样才能能保证在分布式环境下 ID 的全局唯一性。

适用操作:

  • 插入操作
  • 删除操作

 

数据库乐观锁

数据库乐观锁方案一般只能适用于执行“更新操作”的过程,我们可以提前在对应的数据表中多添加一个字段,充当当前数据的版本标识。

这样每次对该数据库该表的这条数据执行更新时,都会将该版本标识作为一个条件,值为上次待更新数据中的版本标识的值。

select version from tablename where xxx

更新数据时首先和版本号作对比,如果不相等说明已经有其他的请求去更新数据了,提示更新失败。

update tablename set count=count+1,version=version+1 where version=#{version}

适用操作:

  • 更新操作

 

PRG 模式

Post/Redirect/Get 是一种 web 开发设计模式,用于防止表单的重复提交。

默认情况,提交 Post 请求到服务器后,如果直接刷新浏览器,会重新在提交一次 Post 请求。

什么是幂等性?四种接口幂等性方案详解!_第5张图片

在访问电商网站时,提交订单采用的是 Post 请求,如果直接刷新浏览器就容易导致重复订单的提交,这个不是用户希望发生的行为。

PRG 方法就是用户防止这种现象的发生,下面例图描述了用 PRG 方法来避免 Post 请求的重复提交。当服务器处理完 Post 请求后,会发响应给用户浏览器,指示用户浏览器用 Get 方式立刻访问另一条 URL 。用户浏览器拿到 Get 请求的数据,整个流程才算结束。

什么是幂等性?四种接口幂等性方案详解!_第6张图片

此时用户刷新当前页面,也不会引起 Post 请求的重复提交了。

 

防重 Token 令牌

针对客户端连续点击或者调用方的超时重试等情况,例如提交订单,此种操作就可以用 Token 的机制实现防止重复提交。

简单的说就是调用方在调用接口的时候先向后端请求一个全局 ID(Token),请求的时候携带这个全局 ID 一起请求(Token 最好将其放到 Headers 中),后端需要对这个 Token 作为 Key,用户信息作为 Value 到 Redis 中进行键值内容校验,如果 Key 存在且 Value 匹配就执行删除命令,然后正常执行后面的业务逻辑。

什么是幂等性?四种接口幂等性方案详解!_第7张图片

如果不存在对应的 Key 或 Value 不匹配就返回重复执行的错误信息,这样来保证幂等操作。

上面我只是列举了解决幂等性的解决方案与思路,其实还有很多类似解决方案,比如订单流程还可以结合前段拦截,以及更多的后端方案来保障唯一性。

这些还需要结合你的实际业务场景,来最终来选择更适合你的解决方案,但是万变不离其中,都是为了保证一次操作,保证唯一约束,这才是幂等性的本质。

作者简介

mikechen,10年+大厂架构经验,《BAT架构技术500期》系列文章作者,曾就职于阿里、淘宝、百度等一线互联网大厂。

阅读mikechen的互联网架构更多技术文章合集

Java并发|JVM|MySQL|Spring|Redis|分布式|高并发|架构师

关注「mikechen 的互联网架构」公众号,回复【架构】领取我原创的《300 期 + BAT 架构技术系列与 1000 + 大厂面试题答案》

什么是幂等性?四种接口幂等性方案详解!_第8张图片

你可能感兴趣的:(java架构师架构架构设计)