• 分布式环境下的接口幂等性


    一、问题的由来

    在高并发环境中或者金融支付领域保证结果的一致性是最重要的,也是必须的,网络不好我们支付一个订单点了两次,能扣我两笔钱吗?显然是不能,那么怎么保证支付一笔呢。咱们看下面的章节。

    二、问题的解决办法

    2.1 唯一id

    2.1.1 基本原理

    每次接口或者业务的操作,都根据业务和操作生成唯一id,在执行之前先判断id是否存在,如果不存在(不存在代表第一次执行)则执行后续操作,将数据保存到数据库或者内存数据库中,等再来一次相同请求时就肯定会执行不成功。

    2.1.2 伪代码

    插入相同id的数据时

    insert into test (id,name,pwd) value ('1','test','test');
    
    • 1

    就会主键冲突的错误:

    Duplicate entry '1' for key 'PRIMARY'
    
    • 1

    2.2 token机制

    2.2.1 基本原理

    服务端提供获取token的能力,每次请求前都需要去获取token,服务端把token放入到redis,然后在请求的时候把token带上,服务端在执行业务操作前先验证token,如果token存在就执行业务,执行成功就删除token,下次请求过来的时候发现没有token验证失败,执行业务失败。

    2.2.2 伪代码

    TokenController

    public class TokenController{
    	
    	public ExecuteResult generateToken(){
    		return service.generateToken();
    	}
    
    	public ExecuteResult checkToken(){
    		return service.generateToken();
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    TokenService

    public class TokenServiceController{
    	
    	public ExecuteResult generateToken(){
    		//一、token生成逻辑,需要有业务标识,
    		//就加上业务标识,不需要标识用uuid也可以
    
    		//二、将tokne保存到redis等内存数据库
    		
    		//三、返回生成的token
    	}
    
    	public ExecuteResult checkToken(){
    		//1、从header中或者参数中获取token值
    		//2、校验token是否在内存数据库redis或zk中存在
    		//2.1 如果不存在证明已经执行过,就抛出异常或者返回校验失败的消息
    		//2.2 如果存在证明是第一次执行,就执行下面的业务操作
    		//3、从zk或者redis中删除token
    		//3.1 如果删除失败就证明其他请求已经删除,抛出异常或者校验失败的消息
    		//3。2 如果删除成功,就返回校验成功的信息
    
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    2.3 去重表

    2.3.1 基本原理

    去重表的机制和唯一id的情况比较类似,都是将具有唯一标识的字段作为判断标识,第二次请求过来的时候发现已经有了就会执行失败或者利用数据库的能力导致业务执行失败。

    2.3.2 伪代码

    插入相同name的数据时

    insert into test (id,name,pwd) value ('1','test','test');
    
    • 1

    就会唯一索引冲突的错误:

    Duplicate entry 'test' for key 'id'
    
    • 1

    2.4 版本控制

    2.4.1 基本原理

    版本控制其实是乐观锁的原理,在数据中增加版本,只有在版本相等的时候才去执行修改数据或者执行业务。
    不过乐观锁存在失效的问题,即ABA问题,但是如果版本一直累加,还会有问题吗?当然就不会了。乐观锁一般是用于读多写少的场景。

    2.4.2 伪代码
    update test set name='test1' where id = 'uuid' version = 1
    
    • 1

    2.5 状态控制

    2.5.1 基本原理

    如执行,未执行,执行中三个状态,只有在状态为执行时才被允许执行。不过状态控制需要用悲观锁加持,要不肯定是会出问题的。这个其实类似乐观锁的版本控制,但是这里加了悲观锁,防止数据更改过程中被其他线程或者请求修改。

    2.5.2 伪代码
    update test set name='test1' where id = 'uuid' state = 1
    
    • 1

    三、结语

    道阻且长,行则将至,行而不辍,未来可期,加油。

    如果你觉得文章不错,对你的进步有那么一点帮助,那么就给点个赞,如果觉得文章非常对你的胃口,那么欢迎你关注我,这里有资源,有内推,有和你志同道合的朋友,咱们一起打怪升级。

  • 相关阅读:
    电脑一键重装系统后如何打开事件查看器
    计算机竞赛 基于深度学习的人脸性别年龄识别 - 图像识别 opencv
    Flutter状态管理 — 探索Flutter中的状态
    浅析安防监控系统/AI视频智能分析算法:河道水文水位超标算法应用
    mac下vue-cli从2.9.6升级到最新版本
    【Python基础:面向对象之魔法方法】
    log4j-slf4j-impl cannot be present with log4j-to-slf4j 之类的问题,解决maven依赖冲突
    HALCON: 对象(object)从声明(declaration)到结束(finalization)
    IEJoin: 提高 Databend range join 性能
    2331. 计算布尔二叉树的值-深度优先遍历
  • 原文地址:https://blog.csdn.net/just_for_that_moment/article/details/126168608