API接⼝设计幂等性解决⽅案
在编程中.⼀个幂等操作的特点是其任意多次执⾏所产⽣的影响均与⼀次执⾏的影响相同。幂等函数,或幂等⽅法,是指可以使⽤相同参数重复执⾏,并能获得相同结果的函数。这些函数不会影响系统状态,也不⽤担⼼重复执⾏会对系统造成改变。例如,“getUsername()和setTrue()”函数就是⼀个幂等函数. 更复杂的操作幂等保证是利⽤唯⼀交易号(流⽔号)实现.
我的理解:幂等就是⼀个操作,不论执⾏多少次,产⽣的效果和返回的结果都是⼀样的。
1、查询操作:查询⼀次和查询多次,在数据不变的情况下,查询结果是⼀样的。select是天然的幂等操作;
2、删除操作:删除操作也是幂等的,删除⼀次和多次删除都是把数据删除。(注意可能返回结果不⼀样,删除的数据不存在,返回0,删除的数据多条,返回结果多个) ;
3、唯⼀索引:防⽌新增脏数据。⽐如:⽀付宝的资⾦账户,⽀付宝也有⽤户账户,每个⽤户只能有⼀个
资⾦账户,怎么防⽌给⽤户创建资⾦账户多个,那么给资⾦账户表中的⽤户ID加唯⼀索引,所以⼀个⽤户新增成功⼀个资⾦账户记录。要点:唯⼀索引或唯⼀组合索引来防⽌新增数据存在脏数据(当表存在唯⼀索引,并发时新增报错时,再查询⼀次就可以了,数据应该已经存在了,返回结果即可);
4、token机制:防⽌页⾯重复提交。
原理上通过session token来实现的(也可以通过redis来实现)。当客户端请求页⾯时,服务器会⽣成⼀个随机数Token,并且将Token放置到session当中,然后将Token发给客户端(⼀般通过构造hidden表单)。
下次客户端提交请求时,Token会随着表单⼀起提交到服务器端。
服务器端第⼀次验证相同过后,会将session中的Token值更新下,若⽤户重复提交,第⼆次的验证判断将失败,因为⽤户提交的表单中的Token没变,但服务器端session 中Token已经改变了。
5、悲观锁
获取数据的时候加锁获取。select * from table_xxx where id='xxx' for update; 注意:id字段⼀定是主键或者唯⼀索引,不然是锁表,会死⼈的;悲观锁使⽤时⼀般伴随事务⼀起使⽤,数据锁定时间可能会很长,根据实际情况选⽤;
api设计6、乐观锁——乐观锁只是在更新数据那⼀刻锁表,其他时间不锁表,所以相对于悲观锁,效率更⾼。乐观锁的实现⽅式多种多样可以通过version或者其他状态条件:
1. 通过版本号实现update table_xxx set name=#name#,version=version+1 where version=#version#如下图(来⾃⽹上);
2. 通过条件限制 update table_xxx set avai_amount=avai_amount-#subAmount# where avai_amount-#subAmount# >= 0要求:quality-#subQuality# >= ,这个情景适合不⽤版本号,只更新是做数据安全校验,适合库存模型,扣份额和回滚份额,性能更⾼;
7、分布式锁
如果是分布是系统,构建全局唯⼀索引⽐较困难,例如唯⼀性的字段没法确定,这时候可以引⼊分布式锁,通过第三⽅的系统(redis或zookeeper),在业务系统插⼊数据或者更新数据,获取分布式锁,然后做操作,之后释放锁,这样其实是把多线程并发的锁的思路,引⼊多多个系统,也就是分布式系统中得解决思路。要点:某个长流程处理过程要求不能并发执⾏,可以在流程执⾏之前根据某个标志(⽤户ID+后缀等)获取分布式锁,其他流程执⾏时获取锁就会失败,也就是同⼀时间该流程只能有⼀个能执⾏成功,执⾏完成后,释放分布式锁(分布式锁要第三⽅系统提供);
8、select + insert
并发不⾼的后台系统,或者⼀些任务JOB,为了⽀持幂等,⽀持重复执⾏,简单的处理⽅法是,先查询下⼀些关键数据,判断是否已经执⾏过,在进⾏业务处理,就可以了。注意:核⼼⾼并发流程不要⽤这种⽅法;
9、状态机幂等
在设计单据相关的业务,或者是任务相关的业务,肯定会涉及到状态机(状态变更图),就是业务单据上⾯有个状态,状态在不同的情况下会发⽣变更,⼀般情况下存在有限状态机,这时候,如果状态机已经处于下⼀个状态,这时候来了⼀个上⼀个状态的变更,理论上是不能够变更的,这样的话,保证了有限状态机的幂等。注意:订单等单据类业务,存在很长的状态流转,⼀定要深刻理解状态机,对业务系统设计能⼒提⾼有很⼤帮助
10、对外提供接⼝的api如何保证幂等
如银联提供的付款接⼝:需要接⼊商户提交付款请求时附带:source来源,seq序列号;source+seq在数据库⾥⾯做唯⼀索引,防⽌多次付款(并发时,只能处理⼀个请求)。
重点:对外提供接⼝为了⽀持幂等调⽤,接⼝有两个字段必须传,⼀个是来源source,⼀个是来源⽅序列号seq,这个两个字段在提供⽅系统⾥⾯做联合唯⼀索引,这样当第三⽅调⽤时,先在本⽅系统⾥⾯
查询⼀下,是否已经处理过,返回相应处理结果;没有处理过,进⾏相应处理,返回结果。注意,为了幂等友好,⼀定要先查询⼀下,是否处理过该笔业务,不查询直接插⼊业务系统,会报错,但实际已经处理了。
幂等与是不是分布式⾼并发还有JavaEE都没有关系。关键的是操作是不是幂等的。⼀个幂等的操作典型如:把编号为5的记录的A字段设置为0这种操作不管执⾏多少次都是幂等的。⼀个⾮幂等的操作典型如:把编号为5的记录的A字段增加1这种操作显然就不是幂等的。要做到幂等性,从接⼝设计上来说不设计任何⾮幂等的操作即可。譬如说需求是:当⽤户点击赞同时,将答案的赞同数量+1。改为:当⽤户点击赞同时,确保答案赞同表中存在⼀条记录,⽤户、答案。赞同数量由答案赞同表统计出来。总之幂等性应该是合格程序员的⼀个基因,在设计系统时,是⾸要考虑的问题,尤其是在像⽀付宝,银⾏,互联⽹⾦融公司等涉及的都是钱的系统,既要⾼效,数据也要准确,所以不能出现多扣款,多打款等问题,这样会很难处理,⽤户体验也不好。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论