郑州网站制作建设,南宁网站设计要多少钱,seo是什么意思职业,网站怎么做统计【Spring Cloud系列】- 分布式系统中实现幂等性的几种方式 文章目录 【Spring Cloud系列】- 分布式系统中实现幂等性的几种方式一、概述二、什么是幂等性三、幂等性需关注几个重点四、幂等性有什么用五、常见用来保证幂等的手段5.1 MVCC方案5.2 去重表5.3 去重表5.4 select in…【Spring Cloud系列】- 分布式系统中实现幂等性的几种方式 文章目录 【Spring Cloud系列】- 分布式系统中实现幂等性的几种方式一、概述二、什么是幂等性三、幂等性需关注几个重点四、幂等性有什么用五、常见用来保证幂等的手段5.1 MVCC方案5.2 去重表5.3 去重表5.4 select insert5.5 状态机幂等5.6 token机制防止页面重复提交5.7 对外提供接口的api如何保证幂等5.7 全局唯一ID 5.8 分布式锁六、总结 一、概述
在开发订单系统时我们常遇见支付问题既用户购买商品后支付支付扣款成功但是返回结果的时候网络异常此时钱已经扣了用户再次点击按钮此时会进行第二次扣款返回结果成功用户查询余额发现多扣钱了流水记录也变成了两条。在以前的单应用系统中我们只需要把数据操作放入事务中即可发生错误立即回滚但是再响应客户端的时候也有可能出现网络中断或者异常问题。如果保证一个订单从创建到支付成功整个订单生命周期中数据是一致不因异常而改变。这种机制就需要用到幂等性。
二、什么是幂等性
幂等是一个数学与计算机的概念常见于常见于抽象代数中。
幂等函数或幂等方法是指可以使用相同参数重复执行并能获得相同结果的函数。这些函数不会影响系统状态也不用担心重复执行会对系统造成改变。
幂等性任意多次执行对资源本身所产生的影响均与一次执行的影响相同
接口的幂等性实际上就是接口可重复调用在调用方多次调用的情况下接口最终得到的结果是一致的有些接口可以天然的幂等性比如查询接口调用一次和调用多次对系统得到的结果是一样的。并不会因为调用的次数改变查询的结果。
插入INSERT和修改UPDATE方法是非幂等性的需要通过机制在需要的场景处理以确保多次执行无副作用。
删除delete执行一次或多次都是结果为空即结果一致并且无副作用所以在根据主键ID删除可以认为是伪幂等性的根据非主键删除的如果多次执行无副作用都是把数据删除也可以认为是伪幂等性。
三、幂等性需关注几个重点
幂等不仅仅只是一次或多次请求对资源没有副作用比如查询数据库操作没有增删改因此没有对数据库有任何影响幂等还包括第一次请求的时候对资源产生了副作用但是以后的多次请求都不会再对资源产生副作用。幂等关注的是以后的多次请求是否对资源产生的副作用而不关注结果。网络超时等问题不是幂等性的讨论范围。 幂等性是系统服务对外一种承诺而不是实现承诺只要调用接口成功外部多次调用对系统的影响是一致的。声明为幂等的服务会认为外部调用失败是常态并且失败之后必然会有重试。 四、幂等性有什么用
业务开发中经常会遇到重复提交的情况无论是由于网络问题无法收到请求结果而重新发起请求或是前端的操作抖动而造成重复提交情况。 在交易系统支付系统这种重复提交造成的问题有尤其明显比如
用户在APP上连续点击了多次提交订单后台应该只产生一个订单向支付宝发起支付请求由于网络问题或系统BUG重发支付宝应该只扣一次钱。 很显然声明幂等的服务认为外部调用者会存在多次调用的情况为了防止外部多次调用对系统数据状态的发生多次改变将服务设计成幂等。出库单反复请求产生多个出库单信息。
五、常见用来保证幂等的手段
5.1 MVCC方案
多版本并发控制该策略主要使用update with condition更新带条件来防止来保证多次外部请求调用对系统的影响是一致的。在系统设计的过程中合理的使用乐观锁通过version或者updateTimetimestamp等其他条件来做乐观锁的判断条件这样保证更新操作即使在并发的情况下也不会有太大的问题。例如
select * from tablename where condition#condition# //取出要跟新的对象带有版本versoin
update tableName set name#name#,versionversion1 where version#version#在更新的过程中利用version来防止其他操作对对象的并发更新导致更新丢失。为了避免失败通常需要一定的重试机制。
5.2 去重表
在插入数据的时候插入去重表利用数据库的唯一索引特性保证唯一的逻辑。
这种方法适用于在业务中有唯一标的插入场景中比如在以上的支付场景中如果一个订单只会支付一次所以订单ID可以作为唯一标识。这时我们就可以建一张去重表并且把唯一标识作为唯一索引在我们实现时把创建支付单据和写入去去重表放在一个事务中如果重复创建数据库会抛出唯一约束异常操作就会回滚。
5.3 去重表
select for update整个执行过程中锁定该订单对应的记录。注意这种在DB读大于写的情况下尽量少用。
5.4 select insert
并发不高的后台系统或者一些任务JOB为了支持幂等支持重复执行简单的处理方法是先查询下一些关键数据判断是否已经执行过在进行业务处理就可以了。注意核心高并发流程不要用这种方法。
5.5 状态机幂等
在设计单据相关的业务或者是任务相关的业务肯定会涉及到状态机就是业务单据上面有个状态状态在不同的情况下会发生变更一般情况下存在有限状态机这时候如果状态机已经处于下一个状态这时候来了一个上一个状态的变更理论上是不能够变更的这样的话保证了有限状态机的幂等。
这种方法适合在有状态机流转的情况下比如就会订单的创建和付款订单的付款肯定是在之前这时我们可以通过在设计状态字段时使用int类型并且通过值类型的大小来做幂等比如订单的创建为1000付款成功为1。付款失败为999。
5.6 token机制防止页面重复提交
业务要求页面的数据只能被点击提交一次
发生原因由于重复点击或者网络重发或者nginx重发等情况会导致数据被重复提交
解决办法
集群环境采用token加redisredis单线程的处理需要排队单JVM环境采用token加redis或token加jvm内存
处理流程
数据提交前要向服务的申请tokentoken放到redis或jvm内存token有效时间提交后后台校验token同时删除token生成新的token返回token特点:要申请一次有效性可以限流
5.7 对外提供接口的api如何保证幂等
如微信提供的付款接口需要接入商户提交付款请求时附带source来源seq序列号。sourceseq在数据库里面做唯一索引防止多次付款(并发时只能处理一个请求)
**总结**幂等性应该是合格程序员的一个基因在设计系统时是首要考虑的问题尤其是在像支付宝银行互联网金融公司等涉及的都是钱的系统既要高效数据也要准确所以不能出现多扣款多打款等问题这样会很难处理用户体验也不好 。
5.7 全局唯一ID
如果使用全局唯一ID就是根据业务的操作和内容生成一个全局ID在执行操作前先根据这个全局唯一ID是否存在来判断这个操作是否已经执行。如果不存在则把全局ID存储到存储系统中比如数据库、redis等。如果存在则表示该方法已经执行。
从工程的角度来说使用全局ID做幂等可以作为一个业务的基础的微服务存在在很多的微服务中都会用到这样的服务在每个微服务中都完成这样的功能会存在工作量重复。另外打造一个高可靠的幂等服务还需要考虑很多问题比如一台机器虽然把全局ID先写入了存储但是在写入之后挂了这就需要引入全局ID的超时机制。
使用全局唯一ID是一个通用方案可以支持插入、更新、删除业务操作。但是这个方案看起来很美但是实现起来比较麻烦下面的方案适用于特定的场景但是实现起来比较简单。
5.8 分布式锁
在进入方法时先去获取锁假如获取到锁就继续后面的流程。假如没有获取到锁就等待锁的释放直到获取到锁。当执行完方法时释放锁。当然锁要设个超时时间防止意外没有释放到锁。它用来解决分布式系统的幂等性常用的实现方案是 redis 和 zookeeper 等工具。
六、总结
幂等性增加了额外控制幂等的业务逻辑复杂化了业务功能把并行执行的功能改为串行执行降低了执行效率。
幂等性虽然复杂化了业务功能和降低了执行效率但为了保证系统的正确性是必要的。就上面更新 X 的例子在单台服务器上给那段代码加上锁并给 X 设为 volatile就保证来数据的正确性了。在分布式环境下并且 X 是从数据库或者文件里查询出来的用上面加锁的方式实现就不能保证数据的正确性了这时候就需要用到分布式锁了。所以保证方法或接口的幂等性是非常有必要的因为数据是不能出现任何问题的。