幂等性解决方案

场景

我们实际系统中有很多操作,是不管做多少次,都应该产生一样的效果或返回一样的结果。 例如

1. 前端重复提交选中的数据,应该后台只产生对应这个数据的一个反应结果;
2. 我们发起一笔付款请求,应该只扣用户账户一次钱,当遇到网络重发或系统bug重发,也应该只扣一次钱;
3. 发送消息,也应该只发一次,同样的短信发给用户,用户会哭的;
4. 创建业务订单,一次业务请求只能创建一个,创建多个就会出大问题等等。

概念

幂等(idempotent、idempotence)是一个数学与计算机学概念,常见于抽象代数中。 在编程中.一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。

比如一次select id from users where id=1 执行三次,结果一样,但是update score=score+1 from users where id=1 执行三次发生的结果就不一样了。

解决方案

1. token实现

具体流程步骤:

1. 客户端会先发送一个请求去获取 token,服务端会生成一个全局唯一的 ID 作为 token 保存在 redis 中,同时把这个 ID 返回给客户端
2. 客户端第二次调用业务请求的时候必须携带这个 token
3. 服务端会校验这个 token,如果校验成功,则执行业务,并删除 redis 中的 token
4. 如果校验失败,说明 redis 中已经没有对应的 token,则表示重复操作,直接返回指定的结果给客户端

注意:
对 redis 中是否存在 token 以及删除的代码逻辑建议用 Lua 脚本实现,保证原子性
全局唯一 ID 可以用百度的 uid-generator、美团的 Leaf 去生成

2. 基于mysql

具体流程步骤:

1. 建立一张去重表,其中某个字段需要建立唯一索引
2. 客户端去请求服务端,服务端会将这次请求的一些信息插入这张去重表中
3. 因为表中某个字段带有唯一索引,如果插入成功,证明表中没有这次请求的信息,则执行后续的业务逻辑
4. 如果插入失败,则代表已经执行过当前请求,直接返回

3. redis

具体流程步骤:

1. 客户端先请求服务端,会拿到一个能代表这次请求业务的唯一字段
2. 将该字段以 SETNX 的方式存入 redis 中,并根据业务设置相应的超时时间
3. 如果设置成功,证明这是第一次请求,则执行后续的业务逻辑
4. 如果设置失败,则代表已经执行过当前请求,直接返回

幂等的其他实现方法

1.分布式锁

redlock

2.状态机

典型的状态机是松鼠状态机, 状态机的核心思路是假设state=4 如果要改成5,那么之前的状态必须为4,不能为3或者6

3.悲观锁

获取数据的时候加锁获取。select * from table_xxx where id=’xxx’ for update; 注意:id字段一定是主键或者唯一索引,不然是锁表,会死人的悲观锁使用时一般伴随事务一起使用,数据锁定时间可能会很长,根据实际情况选用

4.乐观锁

乐观锁只是在更新数据那一刻锁表,其他时间不锁表,所以相对于悲观锁,效率更高。乐观锁的实现方式多种多样可以通过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# >= ,这个情景适合不用版本号,只更新是做数据安全校验,适合库存模型,扣份额和回滚份额,性能更高

总之,当你去设计一个接口的时候,幂等都是首要考虑的问题,防止数据被重复提交,重复消费,重复扣款等问题发生。电商系统的库存超卖也是个幂等问题。

参考资料

https://zhuanlan.zhihu.com/p/345512692

https://blog.csdn.net/u011635492/article/details/81058153


This entry was posted in 互联网观察, 数学与算法 and tagged . Bookmark the permalink.
月小升QQ 2651044202, 技术交流QQ群 178491360
首发地址:月小升博客https://java-er.com/blog/midengxing-sulo/
无特殊说明,文章均为月小升原创,欢迎转载,转载请注明本文地址,谢谢
您的评论是我写作的动力.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

*