基于Consul的分布式锁主要利用Key/Value存储API中的acquire和release操作来实现。acquire和release操作是类似Check-And-Set的操作:
acquire操作只有当锁不存在持有者时才会返回true,并且set设置的Value值,同时执行操作的session会持有对该Key的锁,否则就返回false
release操作则是使用指定的session来释放某个Key的锁,如果指定的session无效,那么会返回false,否则就会set设置Value值,并返回true
未被上锁
image.png被上锁
image.png编码如下
package com.qxwz.ops.station.change.util;
import com.ecwid.consul.v1.ConsulClient;
import com.ecwid.consul.v1.kv.model.PutParams;
import com.ecwid.consul.v1.session.model.NewSession;
import java.time.LocalDateTime;
import java.util.Objects;
/**
* 基于Consul的互斥锁
*
* @author muxin.sun
*/
public class Lock {
private static final String prefix = "lock/"; // 同步锁参数前缀
private volatile String sessionId;
private final ConsulClient consulClient;
private final String sessionName;
private final String lockKey;
/**
*
* @param consulClient consul client
* @param sessionName 同步锁的session名称
* @param lockKey 同步锁在consul的KV存储中的Key路径,会自动增加prefix前缀,方便归类查询
*/
public Lock(final ConsulClient consulClient,
final String sessionName,
final String lockKey) {
this.consulClient = consulClient;
this.sessionName = sessionName;
this.lockKey = prefix + lockKey;
}
/**
* 获取同步锁
*
* @param block 是否阻塞,直到获取到锁为止
* @return true OR false 获取锁成功
*/
public Boolean lock(boolean block) throws RuntimeException {
if (Objects.isNull(sessionId)) {
synchronized (Lock.class) {
if (Objects.isNull(sessionId)) {
sessionId = createSession(sessionName);
while(true) {
PutParams putParams = new PutParams();
putParams.setAcquireSession(sessionId);
if(consulClient.setKVValue(lockKey, "lock:" + LocalDateTime.now(), putParams).getValue()) {
return true;
} else if (block) {
continue;
}
return false;
}
}
}
}
throw new RuntimeException(sessionId + " - Already locked!");
}
/**
* 释放同步锁
*
* @return true OR false 释放同步锁成功
*/
public Boolean unlock() {
PutParams putParams = new PutParams();
putParams.setReleaseSession(sessionId);
boolean result = consulClient.setKVValue(lockKey, "unlock:" + LocalDateTime.now(), putParams).getValue();
consulClient.sessionDestroy(sessionId, null);
return result;
}
/**
* 创建session
* @param sessionName session name
* @return sessionId
*/
private String createSession(final String sessionName) {
NewSession newSession = new NewSession();
newSession.setName(sessionName);
return consulClient.sessionCreate(newSession, null).getValue();
}
}
参考如下:http://blog.didispace.com/spring-cloud-consul-lock-and-semphore/
网友评论