首頁(yè)常見問題正文

Consul是什么?如何基于Consul創(chuàng)建分布鎖

更新時(shí)間:2023-07-11 來源:黑馬程序員 瀏覽量:

Consul是HashiCorp公司推出的開源工具,用于實(shí)現(xiàn)分布式系統(tǒng)的服務(wù)發(fā)現(xiàn)與配置。 Consul是分布式的、高可用的、可橫向擴(kuò)展的。它具備以下特性 :

服務(wù)發(fā)現(xiàn):consul通過DNS或者HTTP接口使服務(wù)注冊(cè)和服務(wù)發(fā)現(xiàn)變的很容易。 健康檢查:健康檢測(cè)使consul可以快速的告警在集群中的操作。 鍵/值存儲(chǔ):一個(gè)用來存儲(chǔ)動(dòng)態(tài)配置的系統(tǒng)。提供簡(jiǎn)單的HTTP接口,可以在任何地方操作。 多數(shù)據(jù)中心:無需復(fù)雜的配置,即可支持任意數(shù)量的區(qū)域。

一句話概況:Consul既可以用于注冊(cè)中心和配置中心,也可以做keyValue存儲(chǔ)。使用Consul做分布式鎖的底層原理就是keyValue存儲(chǔ)。

基于consul的分布式鎖

ConsulClient 是一個(gè)比較核心的類(consul客戶端),keyvalue存儲(chǔ)要用。

    private ConsulClient consulClient;

    @PostConstruct
    public void init(){
        consulClient = new ConsulClient(consulLockConfig.getHost(),consulLockConfig.getPort());
    }

createSession方法用于創(chuàng)建一個(gè)會(huì)話并返回sessionId,ttl是過期時(shí)間。我們?cè)卺尫沛i的時(shí)候會(huì)用到這個(gè)sessionId。

    /**
     * 創(chuàng)建一個(gè)sessionId
     * @param lockName
     * @param ttlSeconds
     * @return
     */
    private String createSession(String lockName,int ttlSeconds){
        NewSession session = new NewSession();
        //session.setBehavior(Session.Behavior.DELETE);
        session.setBehavior(Session.Behavior.RELEASE);
        session.setName("session " + lockName);
        session.setTtl(ttlSeconds + "s");
        return consulClient.sessionCreate(session, null).getValue();
    }

加鎖的實(shí)現(xiàn):

/**
 * 獲取鎖
 * @param lockName 鎖的名稱(key)
 * @param ttlSeconds 鎖的超時(shí)時(shí)間
 * @return
 */
private boolean tryLock(String lockName,int ttlSeconds){

	try {
		PutParams putParams = new PutParams();
		String sessionId = createSession(lockName, ttlSeconds);
		SessionIdHolder.setSessionId(sessionId);
		log.info("consul加鎖開始(線程:{},鎖名稱:{},sessionId:{})",Thread.currentThread().getName(), lockName,sessionId);
		putParams.setAcquireSession(sessionId);
		//2.將構(gòu)件好的LockContext存儲(chǔ)在consul中
		String key = consulLockConfig.PREFIX+lockName;
		//加鎖成功
		Boolean value = consulClient.setKVValue(key, sessionId, putParams).getValue();
		if(value){
			//開起一個(gè)新的線程去執(zhí)行鎖續(xù)命--調(diào)用看門狗的方式實(shí)現(xiàn)
			if(consulLockConfig.isRenewal()){  //如果續(xù)期
				new ConsulWatchDog(consulClient).watchSession(sessionId,ttlSeconds);//啟動(dòng)看門狗
			}
			log.info("consul加鎖成功(線程:{},鎖名稱:{},sessionId:{})",Thread.currentThread().getName(), lockName,sessionId);
			return true;
		}else{
			//將sessionId刪除
			//consulClient.deleteKVValue(key);
			log.info("consul加鎖失敗(線程:{},鎖名稱:{},sessionId:{})",Thread.currentThread().getName(), lockName,sessionId);
			return false;
		}
	}catch (Exception e){
		e.printStackTrace();
		return false;
	}
}

解鎖的實(shí)現(xiàn):

/**
 * 釋放鎖
 */
public boolean unLock(String lockName){
	//log.info("consul釋放鎖開始(線程:{},鎖名稱:{})",Thread.currentThread().getName(),lockName);
	String sessionId = SessionIdHolder.getSessionId();
	try {
		//先根據(jù)鎖名稱找到對(duì)應(yīng)的sessionId   session 是需要進(jìn)行存儲(chǔ)的  現(xiàn)在我們是通過一個(gè)lockContnt 假如說業(yè)務(wù)上不在一個(gè)微服務(wù)里釋放鎖 對(duì)應(yīng)的 其他微服務(wù)如何獲取到這把鎖呢
		String key = consulLockConfig.PREFIX+lockName;
		Response<GetValue> kvValue = consulClient.getKVValue(key);
		if(kvValue==null) return false;
		GetValue value = kvValue.getValue();
		if(value==null) return false;
		//log.info("consul釋放鎖開始(線程:{},鎖名稱:{},sessionId:{})",Thread.currentThread().getName(),lockName,sessionId);

		PutParams putParams = new PutParams();
		putParams.setReleaseSession(sessionId);
		consulClient.setKVValue(key, sessionId, putParams);

		//String sessionId = value.getDecodedValue();
		consulClient.sessionDestroy(sessionId, null);// key value也會(huì)被刪除 是使用的DELETE
		//刪除對(duì)應(yīng)的 sessionId存儲(chǔ)
		//consulClient.deleteKVValue(key);
		log.info("consul釋放鎖成功(線程:{},鎖名稱:{},sessionId:{})",Thread.currentThread().getName(),lockName,sessionId);
		return true;
	}catch (Exception e){
		e.printStackTrace();
		log.info("consul釋放鎖出錯(cuò)(線程:{},鎖名稱:{},sessionId:{})",Thread.currentThread().getName(),lockName,sessionId);
		return false;
	}
}


分享到:
在線咨詢 我要報(bào)名
和我們?cè)诰€交談!