1. 程式人生 > >Zookeeper基礎+Zookeeper實戰分散式鎖

Zookeeper基礎+Zookeeper實戰分散式鎖

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;
import 
java.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();
        }
    }
}