幂等性:多次调用方法或者接口不会改变业务状态,可以保证重复调用的结果和单次调用的结果一致。 selectdelete操作具有天然幂等性:select多次结果总是一致,delete第一次执行后继续再执行也不会对数据有影响; 一般没有幂等性而出现异常的操作:insert操作,update操作,混合类型操作(同时包含增删改等)。


幂等性的场景:



  1. 前端重复提交:前端瞬时点击多次造成表单重复提交;
  2. 接口超时重试:接口可能会因为某些原因而调用失败,出于容错性考虑会加上失败重试的机制。如果接口调用一半,再次调用就会因为脏数据的存在而出现异常。
  3. 消息重复消费:在使用消息中间件来处理消息队列,且手动ack确认消息被正常消费时。如果消费者突然断开连接,那么已经执行了一半的消息会重新放回队列。被其他消费者重新消费时就会导致结果异常,如数据库重复数据,数据库数据冲突,资源重复等。
  4. 请求重发:网络抖动引发的nginx重发请求,造成重复调用;

幂等性的实现方式:



  • 对于客户端交互的接口,可以在前端拦截一部分,例如防止表单重复提交,按钮置灰,隐藏,不可点击等方式。但是前端进行拦截器显然是针对普通用户,懂点技术的都可以模拟请求调用接口,所以后端幂等性很重要。
  • 后端的幂等性如何实现?将会从以下几个方面介绍。
    1.数据库去重表
    在往数据库中插入数据的时候,利用数据库唯一索引特性,保证数据唯一。比如订单的流水号,也可以是多个字段的组合。
    2.状态机制
    很多业务中多有多个状态,比如订单的状态有提交、待支付、已支付、取消、退款等等状态。后端可以根据不同的状态去保证幂等性,比如在退款的时候,一定要保证这笔订单是已支付的状态。
    3.TOKEN机制
    简单的说就是调用方在调用接口的时候先向后端请求一个全局ID(TOKEN),请求的时候携带这个全局ID一起请求,后端需要对这个全局ID校验来保证幂等操作,流程如下图:
    主要的流程步骤如下:
    (1)客户端先发送获取token的请求,服务端会生成一个全局唯一的ID保存在redis中,同时把这个ID返回给客户端。
    (2)客户端调用业务请求的时候必须携带这个token,一般放在请求头上。
    服务端会校验这个Token,如果校验成功,则执行业务。
    (3)如果校验失败,则表示重复操作,直接返回指定的结果给客户端。
    通过以上的流程分析,唯一的重点就是这个全局唯一ID如何生成,在分布式服务中往往都会有一个生成全局ID的服务来保证ID的唯一性,但是工程量和实现难度比较大.
    4.基于Redis实现
    通过Redis的SETNX命令实现接口的幂等性。
    SETNX key value:当且仅当key不存在时将key的值设为value;若给定的key已经存在,则SETNX不做任何动作。设置成功时返回1,否则返回0。
    具体流程步骤:
    (1)客户端先请求服务端,会拿到一个能代表这次请求业务的唯一字段;
    (2)将该字段以SETNX的方式存入Redis中,并根据业务设置相应的超时时间;
    (3)如果设置成功,证明这是第一次请求,则执行后续的业务逻辑;如果设置失败,则代表已经执行过当前请求,直接返回。
    分布式锁
    这里使用的防重表可以使用分布式锁代替,比如Redis。订单发起支付请求,支付系统会去Redis缓存中查询是否存在该订单号的Key,如果不存在,则向Redis增加Key为订单号。查询订单支付已经支付,如果没有则进行支付,支付完成后删除该订单号的Key。通过Redis做到了分布式锁,只有这次订单订单支付请求完成,下次请求才能进来。相比去重表,将放并发做到了缓存中,较为高效。思路相同,同一时间只能完成一次支付请求。
    5.乐观锁
    如果只是更新已有的数据,没有必要对业务进行加锁,设计表结构时使用乐观锁,一般通过version来做乐观锁,这样既能保证执行效率,又能保证幂等。例如: UPDATE tab1 SET col1=1,version=version+1 WHERE version=#version# 不过,乐观锁存在失效的情况,就是常说的ABA问题,不过如果version版本一直是自增的就不会出现ABA的情况。(从网上找了一张图片很能说明乐观锁,引用过来,出自Mybatis对乐观锁的支持)
    6.支付缓冲区
    把订单的支付请求都快速地接下来,一个快速接单的缓冲管道。后续使用异步任务处理管道中的数据,过滤掉重复的待支付订单。优点是同步转异步,高吞吐。不足是不能及时地返回支付结果,需要后续监听支付结果的异步返回。

学习产出:

提示:这里统计学习计划的总量
例如:
1、 技术笔记 2 遍
2、CSDN 技术博客 3 篇
3、 学习的 vlog 视频 1 个