zookeeper集群

本文详细介绍了如何在CentOS虚拟机上搭建Zookeeper集群,包括安装JDK,设置集群配置,启动验证及解决遇到的问题。同时,展示了使用java客户端ZkClient连接Zookeeper集群的示例,包括监听节点变化、数据变化和状态变化的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前期准备

1.VmWare , CentOS-7 ,Linux下JDK ,Zookeeper安装文件(https://zookeeper.apache.org/releases.html),xshell


在VmWare中安装3台CentOS虚拟机,ip分别为192.168.200.129;192.168.200.130;192.168.200.131,设置虚拟机网络模式为NAT,可以和物理主机通信。

安装jdk

使用xshell连接三台虚拟机,将zookeeper文件上传到虚拟机上 ,并解压到/usr/zookeeper 目录

进入/usr/zookeeper/conf目录下,复制zoo_sample.cfg ,新文件名为zoo.cfg

编辑zoo.cfg文件 ,vim zoo.cfg

这是源文件

# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial 
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between 
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
dataDir=/tmp/zookeeper
# the port at which the clients will connect
clientPort=2181


在后面加上如下内容

server.1=192.168.200.129:2888:3888
server.2=192.168.200.130:2888:3888
server.3=192.168.200.131:2888:3888

servie [1,2,3]分别代表三台机器,2888端口号是zookeeper服务之间通信的端口。 3888端口是zookeeper与其他连接应客户端通信的端口

dataDir=/tmp/zookeeper 这个目录下需要创建一个文件 myid ,192.168.200.129 的myid内容1 ,192.168.200.130的myid内容为2 ,192.168.200.131的内容为3

这里主要用于标识集群中的每一台机器。


启动验证

进入/usr/zookeeper/bin 目录

./zkServer.sh start 启动  输入jps查看输出(当看到QuorumPeerMain字样输出,代表启动成功)

./zkServer.sh status 查看集群状态 (当看到master 、follow字样代表集群启动成功 master是调度主节点 ,follow是子节点)

./zkServer.sh stop 是停止服务


安装中出现的问题 类似如下错误

java.net.NoRouteToHostException: No route to host

Cannot open channel to 2 at election address /192.168.200.129:3888

检查防火墙是否关闭

这里可以参考这篇文章(http://blog.youkuaiyun.com/c233728461/article/details/52679558)



使用java客户端连接zookeeper集群

创建一个Maven工程 
打开pom.xml文件添加zookeeper依赖

<dependency>

<groupId>org.apache.zookeeper</groupId>

<artifactId>zookeeper</artifactId>

<version>3.4.6</version>

</dependency>

<!--zkclient -->

<dependency>

<groupId>com.101tec</groupId>

<artifactId>zkclient</artifactId>

<version>0.7</version>

</dependency>

这里使用别人写的开源zkclient,来操作zk


以下copy自别处

zkClient 针对 zk 的一次性watcher,做了重新封装,然后定义了 stateChanged、znodeChanged、dataChanged 三种监听器。

public class ZkClientTest {


    public static void main(String[] args) {
        ZkClient zkClient = new ZkClient("192.168.200.129:2181,192.168.200.130:2181,192.168.200.131:2181");
        String node = "/myapp";


        // 订阅监听事件
        childChangesListener(zkClient, node);
        dataChangesListener(zkClient, node);
        stateChangesListener(zkClient);


        if (!zkClient.exists(node)) {
            zkClient.createPersistent(node, "hello zookeeper");
        }
        System.out.println(zkClient.readData(node));


        zkClient.updateDataSerialized(node, new DataUpdater<String>() {


            public String update(String currentData) {
                return currentData + "-123";
            }
        });
        System.out.println(zkClient.readData(node));




        try {
            TimeUnit.SECONDS.sleep(3000000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    /**
     * 订阅children变化
     *
     * @param zkClient
     * @param path
     * @author SHANHY
     * @create 2016年3月11日
     */
    public static void childChangesListener(ZkClient zkClient, final String path) {
        zkClient.subscribeChildChanges(path, new IZkChildListener() {


            public void handleChildChange(String parentPath, List<String> currentChilds) throws Exception {
                System.out.println("clildren of path " + parentPath + ":" + currentChilds);
            }


        });
    }


    /**
     * 订阅节点数据变化
     *
     * @param zkClient
     * @param path
     * @author SHANHY
     * @create 2016年3月11日
     */
    public static void dataChangesListener(ZkClient zkClient, final String path) {
        zkClient.subscribeDataChanges(path, new IZkDataListener() {


            public void handleDataChange(String dataPath, Object data) throws Exception {
                System.out.println("Data of " + dataPath + " has changed.");
            }


            public void handleDataDeleted(String dataPath) throws Exception {
                System.out.println("Data of " + dataPath + " has Deleted.");
            }


        });
    }


    /**
     * 订阅状态变化
     *
     * @param zkClient
     * @author SHANHY
     * @create 2016年3月11日
     */
    public static void stateChangesListener(ZkClient zkClient) {
        zkClient.subscribeStateChanges(new IZkStateListener() {


            public void handleStateChanged(KeeperState state) throws Exception {
                System.out.println("handleStateChanged");
            }


            public void handleSessionEstablishmentError(Throwable error) throws Exception {
                System.out.println("handleSessionEstablishmentError");
            }


            public void handleNewSession() throws Exception {
                System.out.println("handleNewSession");
            }
        });
    }
}

ZkClient 做了便捷的包装,对Watch做了增强处理。 
subscribeChildChanges实际上是通过exists和getChildren关注了两个事件。这样当create(“/path”)时,对应path上通过getChildren注册的listener也会被调用。另外subscribeDataChanges实际上只是通过exists注册了事件。因为从上表可以看到,对于一个更新,通过exists和getData注册的watcher要么都会触发,要么都不会触发。

关于session超时的问题,ZkClient 貌似还是有对 Session Expired 处理的,在ZkClient.processStateChanged方法中。虽然能重新连接,但是连接上是一个新的 session,原有创建的ephemeral znode和watch会被删除,程序上你可能需要处理这个问题。

最后说几点关于ZkClient的注意事项: 
1. 创建节点的时候一定要先判断节点是否存在,如果直接使用zkclient创建一个已经存在的节点,则会抛出异常。 
2. 使用zkclient创建节点的时候,path描述的路径,预新增的最终节点之前的所有父节点都必须要存在,否则会抛出异常。所以根据自己需要做好处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值