接口幂等性

接口幂等性


幂等.png

一、什么是幂等

幂等(Idempotence)是一个数学和计算科学概念,简单的来说:一个操作多次执行产生的结果与一次执行产生的结果一致,不会因多次执行而产生负面影响。如等电梯时,我们按一次按钮和按多次结果是一样,或者刷公交卡时,二次刷卡会提示刷卡重复。

二、幂等发生场景

  1. 表单重复提交:

    在填写页面form表单时,不小心快速保存了两次,对应的后台产生了两条相同的记录。

  2. 接口超时重试:

    为解决接口调用超时,我们引入了重试机制,但如果因为网络抖动、临时故障等问题导致第一次请求没及时收到返回结果(实际上服务端业务处理成功),那么就会重试接口,从而产生重复数据。

  3. 消息重复消费:

    mq消费者在读取消息时,如果读取到重复的消息,也会导致重复消费问题。

三、幂等发生在哪些操作

所有的操作最终对应的数据库都是CURD。因此幂等最终反映在select、update、insert、delete上。

  • 对于select查询,无论查询一次还是多次,其返回的结果都是一致的,因此,所以select查询是天然幂等;

  • 对于delete删除,如果在不考虑返回结果情况下,删除一次或多次,其也是具有幂等性;

  • 对于insert新增,新增一次或多次,对应产生重复记录,其不具有幂等性;

  • 对于update更新,如果是直接更新设置,不管是执行多少次,都是幂等的(比如:update user set status=1 where id=1),但如果是更新计算,那么就存在幂等问题(比如:update user set status=status+1 where id=1)。

因此,幂等问题主要发生在新增操作以及更新计算操作中。

四、如何保证幂等

  1. insert前先select判断

    在执行新增操作时,先查询是否存在,如果存在,执行更新操作,如果不存在,才进行新增操作。方案简单实用,但如果对于多节点并发场景中,该方案仍然会存在重复数据的幂等问题,需要结合其他方案进行优化。

1.png
  1. 增加唯一索引

    在表中建立唯一索引,需要注意的是,如果二次请求操作,需要对数据库抛出DuplicateKeyException进行捕获,正常返回处理成功结果。

    2.png
  2. 引入token

    需要两次请求完成一次业务操作,第一次请求获取token,第二次请求带上这个token,完成业务操作。

3.png
  1. 采用悲观锁
    悲观锁适合高并发并且对数据的准确性要求很高的场景,如支付、库存场景。悲观锁常用的是数据库表的for update语句,原则:一锁二判三更新
    如下对于支付场景案例,多个端扣除账户金额时,需要保证账户金额充足才能扣减,否则会造成预支情形。引入悲观锁机制,在每笔金额扣减时,先查询金额,对当前用户金额记录进行加锁,防止并发修改数据,导致并发事务预支扣减。

    `begin;`
    
    `select * from user_account where userId=xxx for update;`
    
    `update user_account set account=account-pay where userId=xxx;`
    
    `commit;`
    
4.png
  1. 采用乐观锁
    由于悲观锁,锁的记录行,如商品库存系统,某类商品并发场景下会造成大量的请求累积,从而直接影响接口性能。为提高性能问题,采用乐观锁机制。乐观锁,通过在表中引入timestamp或version字段进行版本控制更新。

    假设有一张商品库存表goods_stock,包含id,goodsId(商品id), stock(库存数量),version(版本号)四个字段。

    步骤1:根据商品id查询库存表信息
    
            `select goodsId, stock,version from goods_stock where goodId=xxx`
    
    步骤2:根据商品id和当前版本号进行扣减库存
    
        `update goods_stock set stock=stock - buyCount,version=version+1 where goodsId=xxx and version=xxx`
    
    步骤3:如果更新失败,进入重试 。
    
5.png
  1. 采用分布式锁
    不论是悲观锁,还是乐观锁,都是属于数据库层面上分布式锁。还有基于zookeeper和redis的分布式锁,一般常用的redis来作为分布式锁,同时spring官网也推荐使用redisson这个框架api。这里不做详细介绍,像分布式锁单点问题;集群后,加锁成功,master未来及复制到slave上导致锁信息丢失问题;由于GC或网络延迟导致的任务时间变长,从而导致执行时间超过锁过期时间,其他线程获取锁;以及为解决以上问题,引入redLock是如何的原理。在分布式锁文章中再做详细介绍。

  2. 建立防重表
    防重表,也是利用数据库的唯一索引约束,在业务表所在的数据库中单独创建一个去重表。每次请求来时,先执行去重表插入记录,如果成功执行业务表逻辑,如果失败,结束。
    这里,有个小插曲,很多人可能会疑惑,既然是用了唯一索引约束,那又跟上面方案2唯一索引有啥区别的,为什么不直接在业务表里采用唯一索引进行去重,反而单独设计一张去重表里增加维护数据库表的难度。是这样的,我们的业务可能涉及到的不止一张表,而唯一索引又是通过这个多个业务表的多个字段来确认唯一性的,那么这时候,就只能通过去重表来去解决。

    6.png

  3. 采用状态机
    对于有些业务存在业务状态控制流转,每个状态都有前置状态和后置状态,例如工单系统:待审批、审批中、撤销、审批通过、审批拒绝。订单支付系统:待提交、待支付、已支付、取消。待提交的后置状态为待支付,已支付的上一状态必须为待支付状态,取消的上一状态必须为待支付状态。
    状态机方案从某一定的程度上可以理解为乐观锁的版本号方案,但不同的是前者基于业务层面的,后者基于数据库层面,同时后者是递增方式。总体来说,处理的业务场景不同。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容

  • 阿里巴巴 JAVA 开发手册 1 / 32 Java 开发手册 版本号 制定团队 更新日期 备 注 1.0.0 阿...
    糖宝_阅读 7,554评论 0 5
  • 概念分布式一致性问题随处可见,任何一个实体/联接模型,都可能存在分布式一致性问题。如果把单机拆开来看,CPU、内存...
    田涛347阅读 906评论 0 0
  • 1、安装mysql (1)下载mysql的repo源:命令:wgethttp://repo.mysql.com/m...
    瘦到一百斤的蓝胖子阅读 250评论 0 0
  • 一、编程规约 (一)命名规约 【强制】 代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束。反...
    喝咖啡的蚂蚁阅读 1,504评论 0 2
  • 前言 本开发规范基于《阿里巴巴Java开发手册终极版》修改,并集成我们自己的项目开发规范,整合而成。 为表示对阿里...
    4ea0af17fd67阅读 5,638评论 0 5