etcd中的锁是tryLock模式(每次lock都是尝试lock),也就是尝试锁定某个key,如果该key当前状态下是被锁定的话,就无法锁定。引入etcd租约,该租约的效果是给该锁添加失效时长,租约到期,该锁失效,自动释放。代码如下:
import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import com.coreos.jetcd.Client; import com.coreos.jetcd.Lease; import com.coreos.jetcd.Lock; import com.coreos.jetcd.data.ByteSequence; import com.test.errorcode.EtcdError; import com.test.exception.EtcdException; import com.test.service.DistributedLock; @Service public class DistributedLockImpl implements DistributedLock { private static final Log logger = LogFactory.getLog(DistributedLockImpl.class); @Autowired private Lock lockClient; @Autowired private Lease leaseClient; @Value("${etcd.ttlOfLease}")//配置文件中配置租约的时长 private long ttlOfLease; @Value("${etcd.connectionTimeout}")//连接超时时长 private long connectionTimeout; @Value("${etcd.lockTimeout}")//尝试锁定的超时时长 private long lockTimeout; public Long lock(String lockName) throws EtcdException{ logger.debug("start to lock required resource:[" + lockName + "]"); Long leaseId = 0L; // 创建一个租约,租约有效期为ttlOfLease,租约获取超时时间为connectionTimeout try { leaseId = leaseClient.grant(ttlOfLease).get(connectionTimeout, TimeUnit.SECONDS).getID(); logger.debug("release id is [" + leaseId + "]"); } catch (InterruptedException | ExecutionException | TimeoutException e) { logger.error("create lease error " + e); throw new EtcdException(EtcdError.LEASE_CREATE_ERROR); } // 执行加锁操作,并为锁对应的key绑定租约 try { lockClient.lock(ByteSequence.fromString(lockName), leaseId).get(lockTimeout, TimeUnit.MILLISECONDS); } catch (InterruptedException | ExecutionException | TimeoutException e) { logger.error("lock resource [" + lockName + "]" + "failed." + e); logger.error("revoke lease [" + leaseId + "]"); leaseClient.revoke(leaseId); throw new EtcdException(EtcdError.GET_RESOURCE_LOCK_ERROR, lockName); } return leaseId; } /** * 解锁操作,释放锁、解除租约 * * @param lockName:锁名 * @param lockResult:加锁操作返回的结果 */ public void unLock(String lockName, Long leaseId) { logger.debug("start to unlock required resource:[" + lockName + "]" + " whth lease[" + leaseId + "]"); try { // 释放锁 lockClient.unlock(ByteSequence.fromString(lockName)).get(connectionTimeout, TimeUnit.SECONDS); // 删除租约 if (null != leaseId) { leaseClient.revoke(leaseId); } } catch (InterruptedException | ExecutionException | TimeoutException e) { logger.error("unlock resource [" + lockName + "]" + "failed." + e); throw new EtcdException(EtcdError.DELETE_RESOURCE_LOCK_ERROR, lockName); } } }
jar包为:
compile 'com.coreos:jetcd-core:0.0.2' compile 'org.mousio:etcd4j:2.10.0'