日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

zookeeper進(jìn)階

 貪挽懶月 2022-06-20 發(fā)布于廣東

接著上周的zookeeper入門,再來聊聊剩下的東西。包括zookeeper通知機(jī)制和集群的搭建。




通知機(jī)制watch

這個watch和redis中的watch是十分相似的。客戶端注冊監(jiān)聽它關(guān)心的節(jié)點目錄,目錄一旦發(fā)生變化,zk就會通知客戶端。打個比方:你在看電視劇,中途插播廣告了,你不想看廣告,就出去玩了,并且你跟你媽媽說廣告播完了就通知你。在這里,你就是客戶端,你媽媽就是watch,在那里監(jiān)控著電視里播的內(nèi)容,一旦發(fā)現(xiàn)廣告播完了,就會告訴你。所以watch就是異步 + 通知 + 觸發(fā)機(jī)制。getData()、getChildren()和exist()都可以設(shè)置watcher。

1、對watch的理解:

  • 觸發(fā):觸發(fā)分為一次性觸發(fā)和永久觸發(fā)。一次性觸發(fā)就是zk觀察一個節(jié)點,當(dāng)發(fā)生變化就通知客戶端,然后通知完就完事了,這個節(jié)點再次發(fā)生變化它也不管了。而永久觸發(fā)就是它一直在監(jiān)控著,只要有變化就會通知。

  • 為數(shù)據(jù)設(shè)置watch:

  • 時序性和一致性:zk在通知客戶端的時候,可以保證不同客戶端看到變化的順序是一致的。

  • 變化類型:變化分為三種,節(jié)點變化、數(shù)據(jù)變化或者兩者都變化。

2、數(shù)據(jù)變化之一次性觸發(fā)demo:

    public String getZnode(String path) throws KeeperException, InterruptedException {
        String result = null;
        byte[] bytes = zooKeeper.getData(path, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
                try {
                    getNewData(path);
                } catch (KeeperException | InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, new Stat());
        result = new String(bytes);
        return result;
    }

    private String getNewData(String path) throws KeeperException, InterruptedException {
        String result = null;
        byte[] bytes = zooKeeper.getData(path, falsenew Stat());
        result = new String(bytes);
        System.out.println("監(jiān)控到值有變化,新值:" + result);
        return result;
    }

    public static void main(String[] args) throws Exception {
        Watches watches = new Watches();
        ZooKeeper zooKeeper = watches.startZk();
        watches.setZooKeeper(zooKeeper);
        if (watches.getZooKeeper().exists(PATH,false) == null){
            watches.createZnode(PATH,"hello");
            String returnInfo = watches.getZnode(PATH);
            System.out.println("第一次拿到的值:" + returnInfo);
            System.in.read();
        }
    }

首先在getZnode方法里的getData方法里面的參數(shù)Watcher不是false,而是new了一個,重寫其方法,在里面再次調(diào)用獲取數(shù)據(jù)的方法。在main方法里面先將節(jié)點設(shè)置"hello",會打印出“第一次拿到的值為hello”。由于有System.in.read(),所以main線程不會結(jié)束,此時我們在Linux中啟動zkCli.sh,將節(jié)點值設(shè)置為“niubi”,控制臺就會立即打印出新的值。但是再次更改,不會再監(jiān)控。

3、數(shù)據(jù)變化之永久觸發(fā)demo:
第一次設(shè)置的值是"xixi",然后就監(jiān)控"xixi",然后改成"haha",發(fā)現(xiàn)值變了,那么就會通知,這時再監(jiān)控"heihei",如果再次修改,又會觸發(fā)通知。也就是說每次都是監(jiān)控最新值。

// 定義全局變量存儲從zk中拿到的值
private String oldValue = null;

// 獲取zk節(jié)點值的方法
public String getZnode(String path) throws KeeperException, InterruptedException {
        String result = null;
        byte[] bytes = zooKeeper.getData(path, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
                try {
                    // 獲取新值
                    getNewData(path);
                } catch (KeeperException | InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, new Stat());
        result = new String(bytes);
        // 將本次獲取到的值存起來
        oldValue = result;
        return result;
}

// 獲取新值的方法
private boolean getNewData(String path) throws KeeperException, InterruptedException {
        String result = null;
        // 獲取新值的時候再new 一個 watcher,再對當(dāng)前獲取到的值進(jìn)行監(jiān)控
        byte[] bytes = zooKeeper.getData(path, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
                try {
                    // 在這里再次調(diào)用自己本身,實現(xiàn)長效監(jiān)控,相當(dāng)于遞歸
                    getNewData(path);
                } catch (KeeperException | InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, new Stat());
        result = new String(bytes);
        String newValue = result;
        if (oldValue.equals(newValue)){
            System.out.println("監(jiān)控到值沒有變化,新舊值都為:" + result);
            return false;
        }else {
            System.out.println("監(jiān)控到值有變化,舊值為:" + oldValue +  
                                              ", 新值為:" + newValue);
            // 新值變成了老值,繼續(xù)下一次的監(jiān)控
            oldValue = newValue;
            return true;
        }
}

4、子節(jié)點變化demo:
監(jiān)控子節(jié)點變化也就說我們監(jiān)控一個父節(jié)點,當(dāng)發(fā)現(xiàn)這個父節(jié)點下面有子節(jié)點的增刪時,就會觸發(fā)通知。更多細(xì)節(jié)請看下面的代碼以及注釋。

    // 1. 獲得zk實例
    public ZooKeeper startZk() throws IOException {
        return new ZooKeeper(CONNECTURL, SESSION_TIMEOUT, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent
{
                // 一開始if條件不會成立,因為還沒有獲取子節(jié)點,所以沒有子節(jié)點變化
                if (watchedEvent.getType() == Event.EventType.NodeChildrenChanged && watchedEvent.getPath().equals(PATH)){
                    // 如果path父節(jié)點下的子節(jié)點有變化,就打印出這些節(jié)點
                    printChildNode(PATH);
                }else {
                    // 第一次執(zhí)行會進(jìn)入這個else,會獲取path下所有的子節(jié)點
                    aquireParentNode(PATH);
                }
            }
        });
    }

    // 獲取需要監(jiān)控的父節(jié)點下的初始子節(jié)點, path就是要監(jiān)控的父節(jié)點
    private void aquireParentNode(String path{
        List<String> childNodes = null;
        try {
            childNodes = zooKeeper.getChildren(path, true);
            System.out.println(path + " 下的初始子節(jié)點有: " + childNodes );
        } catch (KeeperException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    // 如果path節(jié)點下的子節(jié)點有變化,就打印出這些子節(jié)點
    private void printChildNode(String path{
        List<String> childNodes = null;
        try {
            childNodes = zooKeeper.getChildren(path, true);
            System.out.println("監(jiān)控到 " + path + " 下的子節(jié)點發(fā)生變化,變化后的子節(jié)點列表為:" + childNodes );
        } catch (KeeperException | InterruptedException e) {
            e.printStackTrace();
        }
    }

六、zookeeper集群


zookeeper集群搭建

集群就是在多臺機(jī)器上安裝相同的應(yīng)用,一起對外提供服務(wù)。zookeeper的集群節(jié)點數(shù)得是奇數(shù),奇數(shù)節(jié)點可以防腦裂,利于選舉等。具體的可以百度一下,網(wǎng)友都總結(jié)得非常好。下面來搭建一個偽集群(在同一臺虛擬機(jī)上利用不同的端口啟動三個zookeeper服務(wù))。

  • 1、拷貝三個zookeeper,分別命名為zookeeper01,zookeeper02和zookeeper03。

    image.png
  • 2、然后分別在zookeeper01、02和03目錄下創(chuàng)建data目錄,在data目錄下創(chuàng)建一個myid文件,vim打開myid文件,分別對應(yīng)輸入1、2、3,然后保存。即zookeeper01的myid文件內(nèi)容是1,02的myid內(nèi)容是2,03的myid文件內(nèi)容是3。

  • 3、修改配置文件,配置內(nèi)容如下:

tickTime=2000
initLimit=10
syncLimit=5

# dataDir指向剛才創(chuàng)建的data目錄
dataDir=/opt/zookeeper/zookeeper01/data
clientPort=2181
admin.serverPort=8081
quorumListenOnAllIPs=true

4lw.commands.whitelist=*
# 集群配置
server.1=127.0.0.1:2881:3881
server.2=127.0.0.1:2882:3882
server.3=127.0.0.1:2883:3883

這里是zookeeper01的配置,02和03的配置只要修改dataDir、clientPort和admin.serverPort就好了。比如我的02的clientPort是2182,admin.serverPort是8082,03的是2183和8083。集群配置的公式是:

server.a=b:c:d

a是服務(wù)器編號,與myid文件中的編號一致;b是服務(wù)器IP;c是leader和master通信的端口,特別注意這個不是clientPort;d是選舉時用的端口。

  • 4、可能會遇到的問題:拒接連接、地址已被占用。解決辦法:

1. 排查是否防火墻的原因
systemctl status firewalld.service

2. 關(guān)閉selinux
vim /etc/sysconfig/selinux
注釋掉原先的內(nèi)容,添加一行:
SELINUX=disabled

3. 注釋掉hosts文件中127.0.0.1這一行

以上操作基本上可以解決這些問題。



轉(zhuǎn)一轉(zhuǎn)
贊一贊
看一看

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多