参考链接
引言
什么是幂等
摘自百度百科。
幂等(idempotent、idempotence)是一个数学与计算机学概念,常见于抽象代数中。
在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。例如,“setTrue()”函数就是一个幂等函数,无论多次执行,其结果都是一样的.更复杂的操作幂等保证是利用唯一交易号(流水号)实现。
幂等的作用
无论是单机或者分布式系统都会遇到并发的问题,除了使用类似流量控制等的方法之外,当请求真正到达后端服务器之后,幂等设计
就可以作为一种解决方案了。
基于消息队列的分布式架构的系统中,由于各种原因,比如网络波动等,队列里面的消息就会重发,从本质上来说,系统自动产生了一个并发请求。简单一点也可以理解为一个webapi接口被完全“相同”的参数调用了多次,这时候幂等就派上用处了。
看了一些文章,总结一下基本的手段。
具体方法
总的来说,幂等实现中关键的其实是防并发的问题。系统只要先防止并发问题,然后再根据唯一的业务主键返回对应的结果就好。
单机系统的lock()
.net的lock或者java的ReentrantLock等高级语言中都有关键字,基本的用法就是构造一个对象,对于关键的步骤,lock这个对象,然后执行业务代码,操作完成再释放。
去重表
我们在执行完所有的数据库操作之后,往一张冗余表插入一条更新记录,根据数据库唯一主键,如果数据已经存在就会报错,然后回滚操作。
Multiversion concurrency control
字面上理解就是多版本并发控制。是一种基于数据库
的并发控制。我们可以让关键的数据表多一个version字段。先获取记录值$oldVersion,然后更新的时候增加条件version=$oldVersion。用sql描述就是
select id, value1, version from table1 where id = $id; --version为$oldVersion
update table1 set value1=$newValue where id = $id and version = $oldVersion; -- 比原先id=$id 多一个version=$oldVersion条件。
select id, value1, version from table1 where id = $id; --version为$oldVersion
update table1 set value1=$newValue where id = $id and version = $oldVersion; -- 比原先id=$id 多一个version=$oldVersion条件。
这样,代码中就能通过判断受影响的行数是否为1来判断此次更新是否成功。
这属于一种乐观锁的实现。所以,一般可以加上一些重试机制来优化用户体验。EFCore中的并发控制也是基于这种实现。
select for update 悲观锁
简单来说锁记录,阻止其他进程更新记录,或者是读取记录(需要设置隔离等级)。
详细内容等下一篇总结mysql数据库锁相关的内容时再说。
先查后改
修改之前我们先查一下“记录”是否存在,如果有,就直接返回,才执行操作。这个记录可以是数据库里面的,并发量大的时候不能用,因为会出现两个进程都读取到不存在的情况。这时候就需要通过redis等高速缓存来实现。因为本身redis是单线程的,所有可以保证同一时间只有一个进程获取到。