zookeeper學習__分佈式共享鎖簡單Demo

zookeeper是一個分佈式協調服務,爲用戶的分佈式應用提供協調服務。使用範圍有:主從協調、服務器節點動態上下線、統一配置管理、分佈式共享鎖、統一名稱服務……
文章利用zookeeper實現簡單的分佈式鎖

  • zookeeper雖然提供的服務很多,但底層只有兩個功能
    1.管理程序提交的數據;
    2.爲程序提供數據節點監聽服務

分佈式鎖的簡單實現

分佈式系統多個應用需要操作同一個資源,爲資源操作線程安全問題,創建分佈式鎖,應用取得鎖才能操作資源,否則阻塞直到分佈鎖到該應用節點時才能操作資源。
思路:多個應用在zookeeper上註冊,zookeeper採用排序最小的分配鎖,如果是最小就獲取鎖並操作數據,然後刪除該節點。

zookeeper集羣安裝

  • zookeeper超過半數以上集羣便可存活,因此適合安裝奇數節個集羣。
  • 官網上下載zookeeper-3.x.x.tar.gz包上傳到linux虛擬機中解壓,在zoo.cfg文件中配置各集羣節點的ip和端口。
# zoo.cfg配置
server.1=192.168.10.121:2888:3888
server.2=192.168.10.122:2888:3888
server.3=192.168.10.123:2888:3888
  • 依次啓動各羣集節點的zookeeper:cd /usr/local/zookeeper ./bin zkServer.sh start啓動zookeeper服務

Java實現

通過連接集羣的Zookeeper對象操作節點,主要方法有create/delete/exists,創建zookeeper時可創建監聽對象及監聽回調方法,當節點狀態改變時則觸發事件(監聽僅一次有效),因此可重新通過get(… true)使監聽方法激活爲true.

public class DistributedClient {

    //zookeeper主機
    private String hosts = "192.168.10.121:2181,192.168.10.122:2181,192.168.10.123:2181";

    //超時時間
    private int SESSION_TIME_OUT = 2000;

    private String subNode = "/subNode";
    private String groupNode = "/group";

    private ZooKeeper zk;
    private volatile String thisPath; //當前節點

    public void connectZookeeper() throws Exception {
        zk = new ZooKeeper(hosts, SESSION_TIME_OUT, new Watcher() {
            //監聽回調 
            public void process(WatchedEvent event) {
                if (event.getType() == EventType.NodeChildrenChanged 
                        && groupNode.equals(event.getPath())) {
                    //獲取子節點,並對父節點進行監聽
                    try {
                        List<String> childrenList = zk.getChildren(groupNode, true);
                        String thisNode = thisPath.substring((groupNode + "/").length());
                        //比較自己是否是最小的節點
                        Collections.sort(childrenList);
                        if (0 == childrenList.indexOf(thisNode)) {
                            doSomething();  //特定的業務邏輯,用完鎖之後需要刪除
                            //重新註冊一次鎖, 帶序號的鎖
                            thisPath = zk.create(groupNode + subNode,
                                    null, 
                                    Ids.OPEN_ACL_UNSAFE,
                                    CreateMode.EPHEMERAL_SEQUENTIAL);
                        }
                    } catch (Exception e) {
                        System.err.println("zookeeper is error");
                    }

                }
            }

        });

        if(null == zk.exists(groupNode, true)) {
            zk.create(groupNode, null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); //父節點必須爲persistent纔可創建子節點
        }
        //初始化創建鎖
        thisPath = zk.create(groupNode + subNode,
                null, 
                Ids.OPEN_ACL_UNSAFE,
                CreateMode.EPHEMERAL_SEQUENTIAL);
        Thread.sleep(1000);
        List<String> childrenNodes = zk.getChildren(groupNode, true);
        if (1 == childrenNodes.size()) {
            doSomething();
            thisPath = zk.create(groupNode + subNode,
                    null, 
                    Ids.OPEN_ACL_UNSAFE,
                    CreateMode.EPHEMERAL_SEQUENTIAL);
        }
    }

    /**
     * 特寫業務實現
     * @throws Exception 
     * @throws InterruptedException 
     */
    private void doSomething() throws Exception {
        System.out.println("get this lock" + thisPath);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            System.out.println("finish use this lock, will to release: " + thisPath);
            zk.delete(this.thisPath, -1); //-1表示不指定版本
        }

    }

    @Test
    public void testNode() {
        try {
            for (int i = 0; i < 5; i++)
            {
                new Thread() {
                    public void run() {
                        try {
                            DistributedClient dl = new DistributedClient();
                            dl.connectZookeeper();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }.start();

            }
            Thread.sleep(Integer.MAX_VALUE);
        } catch (Exception e) {
            System.err.println("zookeeper connect error");
            e.printStackTrace();
        }
    }

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章