Zookeeper基礎+Zookeeper實戰分散式鎖
阿新 • • 發佈:2018-11-08
Zookeeper基礎
一、Zookeeper概述
什麼是ZooKeeper
ZooKeeper是一個分散式開源框架,提供了協調分散式應用的基本服務,它向外部應用暴露一組通用服務——分散式同步(Distributed Synchronization)、命名服務(Naming Service)、叢集維護(Group Maintenance)等,簡化分散式應用協調及其管理的難度,提供高效能的分散式服務。ZooKeeper本身可以以Standalone模式安裝執行,不過它的長處在於通過分散式ZooKeeper叢集(一個Leader,多個Follower),基於一定的策略來保證ZooKeeper叢集的穩定性和可用性,從而實現分散式應用的可靠性。Zookeeper是一個分散式協調服務,為使用者的分散式應用程式提供協調服務
1、zookeeper是為別的分散式程式服務的
2、Zookeeper本身就是一個分散式程式(只要有半數以上節點存活,zk就能正常服務)
3、Zookeeper所提供的服務涵蓋:主從協調、伺服器節點動態上下線、統一配置管理、分散式共享鎖、統> 一名稱服務等
4、雖然說可以提供各種服務,但是zookeeper在底層其實只提供了兩個功能:
管理(儲存,讀取)使用者程式提交的資料(類似namenode中存放的metadata);
併為使用者程式提供資料節點監聽服務;
二、Zookeeper結構
三、Windows環境下搭建Zookeeper
解壓zookeeper-3.4.10.tar.gz ,重新命名配置檔案zoo_sample.cfg 為 zoo.cfg解壓ZooInspector.zip(zk視覺化客戶端)
啟動zk服務端:zkServer.cmd
啟動zk客戶端:zkCli.cmd
檢視節點資訊:ls /
建立節點資訊:create /test 值
建立子節點資訊:create /test/001 值
獲取節點內容: get /test
修改節點內容: set /test "修該值"
刪除節點 : delete /test
退出客戶端:quit
四、Java語言操作Zookeeper
五、建立Zookeeper臨時節點
六、Watcher事件通知
Zookeeper實戰分散式鎖
一、使用Zookeeper實現分散式鎖概述
二、解決生產訂單號執行緒安全問題
三、實現分散式鎖解決方案
四、Zookeeper概述
五、使用Zookeeper實現分散式鎖
/** * lock鎖 自定義分散式鎖 * Created by yz on 2018/4/7. */ public interface Lock { // 獲取鎖 public void getLock(); // 釋放鎖 public void unLock(); }
import org.I0Itec.zkclient.ZkClient; importjava.util.concurrent.CountDownLatch; /** * 重構重複程式碼,將重複程式碼交給子類執行 * Created by yz on 2018/4/7. */ public abstract class ZookeeperAbstractLock implements Lock{ // zk連線地址 private static final String CONNECTSTRING="127.0.0.1:2181"; // 建立zk連線 protected ZkClient zkClient = new ZkClient(CONNECTSTRING); protected static final String PATH="/lock"; protected CountDownLatch countDownLatch = null; @Override public void getLock() { if(tryLock()){ System.out.println("-----獲取鎖成功-----"); }else{ // 等待 waitLock(); // 訊號量通知,重新獲取鎖 getLock(); } } // 等待 abstract void waitLock(); // 是否獲取鎖成功,成功返回true,失敗返回false abstract Boolean tryLock(); @Override public void unLock() { if(zkClient !=null){ zkClient.close(); System.out.println("釋放鎖資源成功"); } } }
import org.I0Itec.zkclient.IZkDataListener; import java.util.concurrent.CountDownLatch; /** * Created by yz on 2018/4/7. */ public class ZookeeperDistrbuteLock extends ZookeeperAbstractLock{ @Override void waitLock() { // 使用zk事件監聽,獲取到節點被刪除 IZkDataListener iZkDataListener = new IZkDataListener() { // 當節點發生改變執行 @Override public void handleDataChange(String s, Object o) throws Exception { } // 當節點被刪除後執行 @Override public void handleDataDeleted(String s) throws Exception { if(countDownLatch !=null){ // 喚醒await countDownLatch.countDown(); } } }; //註冊節點資訊 zkClient.subscribeDataChanges(PATH,iZkDataListener); // 檢測節點 if(zkClient.exists(PATH)){ // 建立訊號量 countDownLatch = new CountDownLatch(1); try { // 等待 countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } } // 刪除事件通知 zkClient.unsubscribeDataChanges(PATH,iZkDataListener); } /** * 是否獲取鎖成功,成功返回true,失敗返回false */ @Override Boolean tryLock() { try { zkClient.createEphemeral(PATH); return true; } catch (RuntimeException e) { return false; } } }
import java.text.SimpleDateFormat; import java.util.Date; /** * 生成訂單號規則 使用時間戳+業務id * Created by yz on 2018/4/7. */ public class OrderNumGenerator { // 業務ID private static int count = 0; //生成訂單號 public String getNumber(){ try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); return simpleDateFormat.format(new Date())+"_"+ ++count; } }
/** * 訂單生成呼叫業務邏輯 * Created by yz on 2018/4/7. */ public class OrderService implements Runnable{ // 生成訂單號 OrderNumGenerator orderNumGenerator = new OrderNumGenerator(); // 使用zk分散式鎖 private Lock lock = new ZookeeperDistrbuteLock(); @Override public void run() { try { //上鎖 lock.getLock(); getNumber(); } catch (Exception e) { e.printStackTrace(); }finally { // 是否鎖資源 lock.unLock(); } } public void getNumber(){ String number = orderNumGenerator.getNumber(); System.out.println(Thread.currentThread().getName()+",##number:"+number); } public static void main(String[] args) { System.out.println("#模擬生成訂單號..."); for (int i = 0; i < 100; i++) { new Thread(new OrderService()).start(); } } }