Zookeeper分佈式鎖原理筆記

Zookeeper分佈式鎖原理筆記

zookeeper以樹結構主要保存分佈式協調信息狀態

zookeeper簡單問題篇跳轉我前文8.2章節

Zookeeper基礎

znode結構
	path 唯一路徑
	childNode 子節點
	stat 狀態屬性,如創建時事務id,判斷是否是臨時節點等
	type 節點類型,4種
	data 數據,可有可無 bytes[]

create /yun1 "I am data1"
get /yun1 會返回節點數據 I am data1
create /yun1/yun2 創建yun1的子節點yun2
ls /yun1 會返回yun1下所有子節點,如yun2
get -s/yun1 返回yun1節點stat狀態屬性

4種節點類型
	持久節點,默認
	持久序號節點
	臨時節點,不能再有子節點,客戶端關閉後會刪除
	臨界序號節點,不能再有子節點,客戶端關閉後會刪除
	
	create -s或-e分別指定使用序號節點和使用臨時節點
	序號節點:ZK會自動爲給定節點名加上一個不斷遞增數字後綴

臨時節點作用場景
	yun1節點下有n個機器在執行
	yun1會有n個臨時子節點,當其中一個機器掛了,這臺機器所屬臨時節點會刪除

zookeeper分佈式鎖

場景:假設銀行賬戶讀取數據時候,不能修改賬戶數據 ,賬戶ID爲333

流程
1 創建臨時序號節點 account/333000001,其他人創建則33300000n
2 獲取所有序號比自己小的節點
3 是否全部爲讀節點,是則跳4,否則代表前面有寫節點在拿鎖則跳5
4 獲得鎖成功
5 添加子節點更換成監聽,監聽觸發等待獲取鎖

1 /333-R000001 獲得鎖
2 /333-R000002 獲得鎖
3 /333-W000003 等待鎖,監聽上一個節點
4 /333-R000004 等待鎖,因爲讀4前面有了寫3在等待,監聽上一個節點

爲什麼設計監聽上一個節點?

如果全讓父節點通知所有子節點,會瞬間帶來超大併發量,只監聽上一個節點避免了這個問題

實現

public class Lock{
	private String lockId;
	private String path;
	private boolean active;
	構造函數,get和set方法略過
}

public class ZookeeperLock{	
	//創建臨時序號節點
	private ZkClient zkClient;	
	public ZookeeperLock(){
		zkClient = new ZkClient("192.168.0.149:2181"//連接zk server,5000//session超時時間,20000//連接超時時間);
	}
	
	//獲得鎖
	public Lock lock(String lockId, long timeout){
		Lock lockNode = createLockNode(lockId);//創建還沒拿鎖的新臨時節點
		lockNode = tryActiveLock(lockNode);//嘗試拿鎖
		if(!lockNode.isActive()//沒激活成功,沒拿到鎖){
			try{
				synchronized(lockNode){
					lockNode.wait(timeout);
				}
			}catch(~){
				//拋出異常處理
			}			
		}
		return lockNode;
	}
	//激活鎖
	public Lock tryActiveLock(Lock lockNode){
		//判斷是否獲得鎖
		
		//按照順序獲得所有排列好的子節點
		List<String> list = zkClient.getChildren("/tuling-lock").stream().sorted().map(p->"/tuling-lock/"+p).collect(Collections.toList());
		String firstPath = list.get(0);
		if(firstPath.equals(lockNode.getPath())){
			lockNode.setActive(true);
		}else{//沒拿到鎖,添加上一個節點監聽

			String upNodePath = list.get(list.indexOf(lockNode.getPath())-1);
			//實現對上一個節點監聽
			zkClient.subscribeDataChanges(upNodePath, new IZkDataListener(){					
					~
					@Override
					public void handleDataDeleted(~){
						//節點刪除了,再次嘗試獲得鎖
						Lock lock = tryActiveLock(lockNode);
						synchronized(lockNode){
							if(lock.isActive()){
								lockNode.notify();//成功獲得鎖
							}
							zkClient.unsubscribeDataChanges(~);
						}
					}
				}
			)
		}
		return lockNode;
	}
	//釋放鎖
	public void unlock(Lock lock){
	
	}
	//創建臨時節點
	public Lock createLockNode(String lockId){
		//創建寫鎖,這裏寫死了
		String path = zkClient.createEphemeralSequential("/tuling-lock"+lockId//path,"w"//data);
		Lock lock = new Lock();
		lock.setActive(false);
		lock.setId(lockId);
		lock.setPath(path);
		return lock;
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章