分布式锁-心跳模式
什么是分布式锁?
分布式锁是一种在分布式系统中实现同步和控制的机制。在多个进程或者节点之间共享数据或资源时,为了避免数据竞争等问题出现,需要对其进行同步和控制。分布式锁是一种实现这种同步和控制的机制。
分布式锁的工作原理是通过在系统中创建共享锁,保证同一时间只有一个进程或者节点可以对锁定资源进行访问或更新,从而实现同步和控制。
分布式锁可以实现在分布式系统中对全局共享资源或者一部分资源进行访问控制和同步。如果没有使用分布式锁,多个进程或者节点同时对同一个资源进行访问或修改是非常危险的,可能引发各种竞态条件。因此,分布式锁在分布式系统中起到了非常重要的作用。
分布式锁的实现方式
Java中的分布式锁可以通过以下几种方式实现:
-
基于数据库实现分布式锁:
将锁信息存储在共享的数据库中,在需要加锁的时候先尝试插入一条记录,若插入成功,则成功获取到锁,否则已经有其他进程持有锁,需要等待该锁被释放后再尝试获取。
-
基于缓存实现分布式锁:
将锁信息存储在分布式缓存中,如Redis,同时利用Redis的原子性操作实现加锁和解锁,即通过SETNX命令尝试将键值对设置成锁状态,若设置成功则成功获取锁,否则已有其他应用持有锁。
-
基于Zookeeper实现分布式锁:
通过Zookeeper的临时节点机制实现分布式锁。当需要加锁时,创建具有唯一名称和标识的临时znode节点,如果创建成功则获取锁,如果创建失败则表示锁已经被其他进程持有,需要等待该锁被释放后再尝试获取。
需要注意的是,在分布式系统中使用锁需要考虑一些特殊情况,如节点故障、并发冲突、死锁等。因此,在实现分布式锁时需要考虑应用场景,根据需求选择适当的实现方式,并解决潜在的问题。
通过Reids来实现分布式锁
心跳模式
Redis分布式锁的心跳模式是一种保证锁有效性的机制。在并发环境下,锁的有效性可能会受到网络闪断等因素的影响,导致锁不被及时释放,从而造成锁的失效。Redis分布式锁的心跳模式通过定期发送心跳信息,保持锁的有效性,从而防止锁的失效。
具体来说,当客户端持有正在使用的锁时,会启动一个定时器,每隔一段时间发送一个心跳请求更新锁的过期时间,确保锁一直保持有效。如果控制锁的线程崩溃或者断电,由于超时时间已经设定,Redis会在到期时间之后自动将锁释放掉。
在Redis中,使用setex命令创建一个锁,并保证设置过期时间的同时,才能创建成功。获取锁使用setnx命令,采用自旋锁的机制,直到获取到锁或者超时才退出等待。释放锁的时候,使用Lua脚本来保证原子性。
心跳模式的应用使Redis分布式锁更加健壮和实用,避免了锁失效的问题,确保了分布式锁的正确性。但是心跳模式会带来更多的网络开销和额外的代码实现。
具体代码实现看以下例子:
配置类:
import jakarta.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@ConditionalOnProperty(
name = {
"distributed-lock-conf.enabled"},
havingValue = "true"
)
@Component
@ConfigurationProperties(
prefix = "distributed-lock-conf"
)
public class DistributedLockConf {
private static final Logger logger = LoggerFactory.getLogger(DistributedLockConf.class);
private Boolean enabled = false;
private Integer tryTimes = 3;
private Boolean throwException = true;
private Integer secondsToExpire = 10;
private RedisConf redisConf = new RedisConf();
private Integer heartbeatSeconds = 2;
public DistributedLockConf() {
}
public Boolean getEnabled() {
return this.enabled;
}
public DistributedLockConf setEnabled(Boolean enabled) {
this.enabled = enabled;
return this;
}
public Integer getTryTimes() {
return this.tryTimes;
}
public DistributedLockConf setTryTimes(Integer tryTimes) {
this.tryTimes = tryTimes;
return this;
}
public Boolean getThrowException() {
return this.throwException;
}
public DistributedLockConf setThrowException(Boolean throwException) {
this.throwException = throwException;
return this;
}
public RedisConf getRedisConf() {
return this.redisConf;
}
public DistributedLockConf setRedisConf(RedisConf redisConf) {
this.redisConf = redisConf;
return this;
}
public Integer getSecondsToExpire() {
return this.secondsToExpire;
}
public DistributedLockConf