幂等技术及实现方式

一、什么是幂等

幂等(idempotent)是一个数学与计算机的概念,常见于抽象代数。在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同,也不同担心重复执行会对系统造成改变,例如,setTrue()函数就是一个幂等函数,无论执行多少次,其结果都是一样的。

二、幂等的实现方案

幂等处理的是多次执行的问题,这并不仅仅出现在并发场景中,无论是顺序执行还是并发执行,都需要做好幂等,而幂等的核心是确保唯一性。实现幂等的方式有很多,比如建立数据库唯一索引、创建唯一数据和状态机约束、乐观锁等。

  • 2.1 建立数据库唯一索引

在数据库中创建唯一索引,用作幂等记录,可以防止插入重复数据。以一个插入业务数据的场景为例,可通过业务维度定义唯一索引作为幂等记录,在插入数据方法中,首先查询该幂等记录是否存在,如果存在则直接返回第一次执行的结果,如果不存在则继续执行,并发场景中可能存在多个线程同时插入幂等记录的情况,这种情况下唯一索引可确保只有一个线程可以插入幂等记录成功,其余线程抛异常。插入幂等记录成功的线程可以继续执行后续操作,抛异常的线程执行事务回滚操作。

  • 2.2 唯一数据

创建唯一数据的方式有很多种,比如基于tair或redis实现的分布式锁都属于创建唯一数据来实现幂等,以基于tair实现的分布式锁为例:


public boolean tryLock(String lockKey, int expireTime, boolean reentrant) {
...
	ResultCode code = tairManager.put(NAMESPACE, lockKey, getLockValue(), DEFAULT_VERSION, expireTime);
...
}

private String getLockValue() {
    return NetUtils.getLocalIp() + "_" + Thread.currentThread().getName();
}

将唯一标识作为key通过tryLock方法,如果返回true,说明当前是第一次调用,继续执行幂等方法,如果返回false,则说明key已经被锁定,这是可选择重试、自旋等待、抛异常等不同策略。

  • 2.3 状态机约束

通过状态机的约束可以实现幂等,如果状态机已处于下一个状态,这时候不能往回跳转到上一个状态,通过状态机的跳转约束,可以做到有线状态机的跳转约束,比如基于状态机实现的乐观锁:

update table set status=next_status where id=#{id} and status=#{status}

当前状态第一次被修改后,状态被修改为下一种状态,同一记录针对当前状态的其他修改会失败,程序跑出异常,这常见于并发场景的修改。

  • 2.4 基于版本控制的乐观锁

基于版本控制的乐观锁有多种实现方式,比如基于数据库的版本控制乐观锁实现、基于redis的版本控制乐观锁实现等,以数据库的版本控制乐观锁为例:

update table set version=version+1 where id=#{id} and version=#{version}

与基于状态机的乐观锁类似,当前版本第一次本修改后,版本加1,同一记录针对当前版本的其他修改会失败而抛出异常,这常见于并发场景。

参考

  • 幂等实现方式
  • 幂等与分布式锁

你可能感兴趣的:(并发,通用技术)