JAVAEE分布式技术之Zookeeper技术

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: JAVAEE分布式技术之Zookeeper技术

1,课程回顾
2,本章重点

zk节点类型

zk的常用命令及ACL权限管理

java操作zk(java代码模拟集群管理)

3,具体内容
3.1 zk节点和节点类型

znode数据存储图的讲解

节点类型:

1、PERSISTENT–持久化目录节点

客户端与zookeeper断开连接后,该节点依旧存在

2、PERSISTENT_SEQUENTIAL-目持久化顺序编号录节点

客户端与zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号

3、EPHEMERAL-临时目录节点

客户端与zookeeper断开连接后,该节点被删除,临时节点不可以创建子节点

4、EPHEMERAL_SEQUENTIAL-临时顺序编号目录节点

客户端与zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号

3.2 常用命令:

3.2.1 客户端链接:

保证集群启动

使用zkCli.sh默认链接本机

zkCli.sh

close 关闭会话

quit 退出 或者直接使用quit

或者使用 zkCli -server ip或者主机名:端口号 链接相应服务器

zkCli.sh -server 192.168.23.11:2181

zkCli.sh -server cluster3:2181

或者是在zk命令行: connect ip地址或者主机名称:端口号, 链接相应服务器

[zk: 192.168.23.12:2181(CONNECTED) 0] connect 192.168.170.42:2181

connect cluster3:2181

quit 退出

3.2.2 常用命令:

help 帮助命令,会显示所有zk的命令

ls 存储路径 查看路径下的信息(路径必须是绝对路径)

ls [-s] [-w] [-R] path

列出子节点 -s状态( State) -R 递归查看所有子节点(Recursive) -w 添加监听(watch)

ls / 查看根目录下的内容

ls -R / 递归查看根节点所有子节点

ls -w / 查看并监听根目录,如果根下子节点发生变化都会被监听到,但是只监听一次(提高zk效率)

在另外一个会话中执行:

create /frame1 ‘frame1’

create /frame2 ‘frame2’ 发现只有一次有监控信息

在原会话中执行

ls -w /

在另外一个会话中执行:

delete /frame2

delete /frame1 发现只有一次有监控信息

close 关闭与服务端的链接

close

quit 退出

create [-s] [-e] path [data] [acl]

-s 创建有序节点

-e 创建临时节点

data 节点内容

acl(access control list) 访问控制权限

创建持久节点

create /frame ‘frame’

create /frame/spring ‘spring’

ls /frame

close

quit

zkCli.sh 再次连接,发现会话ID发生变化,说明不上一次会话

ls /

ls /frame 断开会话后持久化节点依然存在

创建持久有序节点

create -s /frame/spring/ioc ‘ioc1’

create -s /frame/spring/ioc ‘ioc2’

create -s /frame/spring/ioc ‘ioc3’

ls /frame/spring 发现3个持久有序节点

quit 退出

zkCli.sh 再次连接,发现会话ID发生变化,说明不上一次会话

ls /frame/spring 发现3个持久有序节点依然存在

create /frame/spring/ioc0000000000/ioccontainer ‘iocc’ 在持久有序节点下还可以创建子节点

ls /frame/spring/ioc0000000000

总结: 只要持久节点,都可以有子节点

创建临时节点:create -e 路径 “字符串信息” (-e是创建短暂节点)

create -e /frame/spring/aop ‘aop’

ls -s /frame/spring/aop 发现 ephemeralOwner 就是依赖当前会话ID

ls -s /

ls -s /frame 发现持久节点 ephemeralOwner 都是0x0

create /frame/spring/aop/cglibproxy ‘cglibproxy’

create -e /frame/spring/aop/cglibproxy ‘cglibproxy’ 都错误 临时节点不能有子节点

创建 临时有序节点

create -e -s /frame/spring/mvc ‘mvc1’

create -e -s /frame/spring/mvc ‘mvc2’

create -e -s /frame/spring/mvc ‘mvc3’

ls /frame/spring

create -e -s /frame/spring/mvc0000000005/ds ‘DespatcherServlet’

ls -s /frame/spring/mvc0000000005 发现 ephemeralOwner 就是依赖当前会话ID

quit

zkCli.sh

ls /frame/spring/ 退出quit当前节点,再次链接zkCli.sh查看,发现临时节点不存在

总结:   只要是临时节点,都不可以有孩子

在zk1查看节点 get 路径 [watch] 获取数据时,启动监听,监听数据(只生效一次)

[zk: localhost:2181(CONNECTED) 18] get /aaa watch

在zk2在另一链接上:

[zk: localhost:2181(CONNECTED) 0] set /aaa 11

zk1截图:

get [-s] [-w] path

查看节点数据 -s 包含节点状态 -w 添加监听

get /frame/spring

get -s /frame/spring

set /frame/spring ‘spirng1’

get -s /frame/spring

set /frame/spring ‘spirng111’

get -s /frame/spring

create /frame/spring/boot ‘boot’

get -s /frame/spring

delete /frame/spring/boot

get -s /frame/spring

get -w /frame/spring 查看节点内容并监控 但是也是只监控一次

在另外一个会话中,改变/frame/spring的内容

set /frame/spring ‘spirng4’

set /frame/spring ‘spirng5’ 发现只有一次可以触发监控

zxid:节点创建时的zxid

ctime:节点创建时间

mZxid:节点最近一次更新时的zxid

mtime:节点最近一次更新的时间

pZxid: 表示该节点的子节点列表最后一次修改的事务ID,添加子节点或删除子节点就会影响子节点列表,但是修改子节点的数据内容则不影响该ID

cversion:子节点更新次数

dataVersion:本节点数据更新次数

aclVersion:节点ACL(授权信息)的更新次数

ephemeralOwner:如果该节点为临时节点,ephemeralOwner值表示与该节点绑定的session id. 如果该节点不是临时节点,ephemeralOwner值为0

dataLength:节点数据长度,本例中为hello world的长度

numChildren:子节点个数

set 更新节点内容:

set /frame/spring ‘spring1’ 更新节点内容

delete [-v version] path 删除单个节点

删除节点,(不能存在子节点)

delete /frame/spring/mvc0000000008

create /frame/spring/boot ‘boot’

create /frame/spring/boot/sarun ‘SpringApplicationrun’

delete /frame/spring/boot 错误

deleteall path

删除路径及所有子节点

deleteall /frame/spring/boot

stat查看节点的状态

stat /frame/spring

setquota增加配额

setquota -n|-b val path

-n 设置子节点的配额数量

-b 设置节点内容的长度

setquota -n 3 /frame 为/frame路径设置子节点数量限制 包含自己在内,最多3个子节点

listquota /frame 查看配额

ls /frame 查看子节点

在另外一个会话中打开日志:

tail -f /usr/zookeeper/logs/zookeeper-root-server-cluster1.out

create /frame/mybatis ‘ORM’

create /frame/hibernate ‘ORM’ 第二次创建目录时就会提示

listquota查询配额

listquota path

-1 表示无限, 即没有限制

listquota /frame

delquota删除配额

delquota [-n|-b] path

delquota /frame 删除所有配额

3.2.3 ACL权限控制:

ACL:Access Control List 访问控制列表

相关命令:

getAcl 获取某个节点的acl权限信息

setAcl 设置某个节点的acl权限信息

addauth 输入认证授权信息,注册时输入明文密码(登录),但是在zk的系统里,密码是以加密后的形式存在的

特性:

ZooKeeper的权限控制是基于每个znode节点的,需要对每个节点设置权限

  每个znode支持设置多种权限控制方案和多个权限

  子节点不会继承父节点的权限,客户端无权访问某节点,但可能可以访问它的子节点

授权格式:

授权策略:授权对象: 权限

scheme: id: Permission

  Scheme:(计划)授权的策略 包含下面:

world:默认方式,相当于全部都能访问 代表所有人

 ip:使用客户端的主机IP作为ACL ID 。这个ACL表达式的格式为addr/bits ,此时addr中的有效位与客户端addr中的有效位进行比对。

  auth:使用已添加认证的用户认证(cli中可以通过addauth digest user:pwd 来添加当前上下文中的授权用户)

  digest:即用户名:密码这种方式认证,这也是业务系统中最常用的。用 username:password 字符串来产生一个MD5串,然后该串被用来作为ACL ID。认证是通过明文发送username:password 来进行的,当用在ACL时,表达式为username:base64 ,base64是password的SHA1摘要的编码。


  ID:授权的对象

权限赋予的用户或者一个实体,例如:IP 地址 或者是用户(授权) 或者是 anyone

  Permission:授予的权限 CRWDA

zookeeper支持的权限

CREATE©: 创建权限,可以在在当前node下创建child node

READ®: 读权限,可以获内容及子节点

WRITE(w): 写权限,可以向当前node写数据

DELETE(d): 删除权限,可以删除当前的child nodes

ADMIN(a): 管理权限,可以设置当前node的permission

测试:

world: getAcl /aaa //获取原来权限列表

setAcl /aaa world:anyone:cda //设置新的访问权限列表

getAcl /aaa //再次查看

get /aaa //没有r时,不可以查看节点内容

setAcl /aaa world:anyone:crwda //设置为原来的

get /aaa //又可以查看

ip: create /a1 ‘a1’ //创建新节点

setAcl /a1 ip:127.0.0.1:crwda

getAcl /a1

get /a1 //获取不到数据

quit //退出

zkCli.sh -server 127.0.0.1:2181 //重新登录

get /a1 //获取到数据

setAcl /a1 ip:192.168.23.91:cdwra,ip:192.168.23.92:cdwra

getAcl /a1

quit

zkCli.sh -server 192.168.23.91:2181 //重新登录,限制只能是本机登录

get /a1 //可以获取

zkCli.sh -server 192.168.23.93:2181 //在93登录

get /a1 //不可以

auth: create /a2 ‘a2’

getAcl /a2

addauth digest scott:tiger #增加授权用户,明文用户名和密码

setAcl /a2 auth:scott:cdwra  #授予权限

getAcl /a2 //设置时为明码,查看时,加密过的

get /a2 可以查看

重新链接后,需要再次添加授权用户才可以查看:

addauth digest admin:123 // 设置错误的认证信息

get /a2 // 不可以查看

addauth digest scott:tiger //设置正确的认证信息

get /a2 //可以

digest: create /a3 ‘a3’

getAcl /a3

setAcl /a3 digest:user:6DY5WhzOfGsWQ1XFuIyzxkpwdPo=:crwda #授权

getAcl /a3

rmr /a3 #直接删除没权限

addauth digest user:123456 #增加认证用户

rmr /a3 // 成功

3.3 zookeeper java api

使用下列地址查找依赖包:

https://mvnrepository.com/

1,创建项目,引入jar包

<dependency>
      <groupId>org.apache.zookeeper</groupId>
      <artifactId>zookeeper</artifactId>
      <version>3.4.13</version>
    </dependency>
       <!--日志 start-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.25</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.25</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.25</version>
            <scope>test</scope>
        </dependency>
        <!--日志end-->

2,增删改查

config.properties
#链接字符串 C:\Windows\System32\drivers\etc\hosts  和/etc/hosts
connectString=zk1:2181,zk2:2181,zk3:2181,zk4:2181,zk5:2181
#链接超时时长
sessionTimeout=2000
```java
package com.aaa.util;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Properties;
/**
 * fileName:ZookeeperUtil
 * description:
 * author:zz
 * createTime:2020/5/16 9:34
 * version:1.0.0
 */
public class ZookeeperUtil {
    private  Properties properties;
    //各个方法共享
    private ZooKeeper zooKeeper;
    /**
     * 空构造,初始化配置文件
     */
    public ZookeeperUtil(){
        InputStream inputStream = null;
        try {
            // Properties 是Map子孙类
             properties = new Properties();
            //使用任意类的Class对象中提供的getResourceAsStream读取配置文件为 输入字节流
            inputStream =ZookeeperUtil.class.getResourceAsStream("/config.properties");
            //加载内容
            properties.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if(inputStream!=null){
                    inputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 初始化zk
     */
    public void initZk(){
        try {
             zooKeeper = new ZooKeeper(properties.getProperty("connectString"),
                    Integer.valueOf(properties.getProperty("sessionTimeout")), new Watcher() {
                    @Override
                    public void process(WatchedEvent watchedEvent) {
                        System.out.println("当查看子节点或者查看节点数据时,使用watch时,在这回调");
                    }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 节点的创建
     * @param path  节点路径
     * @param nodeData  节点数据
     * @param type  节点类型 type=0 持久节点  type=1 临时节点  type=2 持久有序  type=3 临时有序
     * @return
     */
    public boolean createZKNode(String path,String nodeData,int type){
        //String path, byte[] data, List<ACL> acl, CreateMode createMode
        try {
            // nodeData.getBytes("utf-8") 支持中文的
            zooKeeper.create(path,nodeData.getBytes("utf-8"),
                    ZooDefs.Ids.OPEN_ACL_UNSAFE,// world:anyone:crwda
                    CreateMode.fromFlag(type)  //type=0 持久节点  type=1 临时节点  type=2 持久有序  type=3 临时有序
            );
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
    /**
     * 根据节点路径查询子节点
     * @param path  节点路径
     * @param isWatch  是否监控
     * @return
     */
    public List<String>  getChirdrenByPath(String path,boolean isWatch){
        try {
            //查询并返回
            return  zooKeeper.getChildren(path, isWatch);
        } catch (Exception e) {
            e.printStackTrace();
        } 
        return null;
    }
    /**
     * 根据节点路径删除节点
     * @param path
     * @return
     */
    public boolean deleteNodeByPath(String path){
        try {
            // version=-1 删除所有版本
            zooKeeper.delete(path,-1);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
    /**
     * 获取节点数据
     * @param path
     * @param isWatch
     * @return
     */
     public String getNodeData(String path,boolean isWatch){
         try {
             byte[] byteArray = zooKeeper.getData(path, isWatch, null);
             return new String(byteArray);
         } catch (KeeperException e) {
             e.printStackTrace();
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
         return null;
     }
    /**
     * 节点数据的更新
     * @param path
     * @return
     */
     public boolean updateNodeData(String path,String nodeData){
         try {
             zooKeeper.setData(path,nodeData.getBytes("utf-8"),-1);
             return true;
         } catch (Exception e) {
             e.printStackTrace();
         }
         return false;
     }
    /**
     * 判断节点是否存在
     * @param path
     * @return
     */
     public boolean  isNodeExist(String path){
         try {
             Stat exists = zooKeeper.exists(path, false);
             if(exists!=null)
                 return true;
         } catch (Exception e) {
             e.printStackTrace();
         }
         return false;
     }
}

ZookeeperUtil

ZKUtilTest
package com.aaa.test;
import com.aaa.util.ZookeeperUtil;
import org.apache.zookeeper.ZooKeeper;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.List;
/**
 * fileName:ZKUtilTest
 * description:
 * author:zz
 * createTime:2020/5/16 11:13
 * version:1.0.0
 */
public class ZKUtilTest {
    private ZookeeperUtil zookeeperUtil;
    /**
     * 执行Test之前执行的方法
     */
    @Before
    public void init(){
        //加载配置读取配置
        zookeeperUtil = new ZookeeperUtil();
        //使用配置连接zk集群
        zookeeperUtil.initZk();
    }
    /**
     * 测试创建节点方法
     */
    @Test
    public void testCreateZKNode(){
        boolean result = zookeeperUtil.createZKNode("/testCreateNode1/cnode", "子节点3", 2);
        if(result){
            System.out.println("操作成功");
        }else {
            System.out.println("操作失败");
        }
    }
    /**
     * 测试获取子节点
     */
    @Test
    public void testGetChirdrenByPath(){
        List<String> chirdren = zookeeperUtil.getChirdrenByPath("/testCreateNode1", false);
        System.out.println("子节点有:");
        for (String s : chirdren) {
            System.out.println(s);
        }
    }
    /**
     * 测试获取接单数据
     */
    @Test
    public void testGetNodeData(){
        String nodeData = zookeeperUtil.getNodeData("/testCreateNode1", false);
        System.out.println(nodeData);
    }
    /**
     * 测试更新数据
     */
    @Test
    public void testUpdateNodeData(){
        //测试节点是否存在
        if(zookeeperUtil.isNodeExist("/testCreateNode1")){
            boolean result = zookeeperUtil.updateNodeData("/testCreateNode1", "根节点。。。");
            if(result){
                System.out.println("操作成功");
            }else {
                System.out.println("操作失败");
            }
        }
    }
    /**
     * 测试删除节点
     */
    @Test
    public void testDeleteNodeByPath(){
        List<String> chirdren = zookeeperUtil.getChirdrenByPath("/testCreateNode1", false);
        //判断是否有子节点
        if(chirdren!=null&&chirdren.size()>0){
            //循环删除子节点
            for (String c : chirdren) {
                zookeeperUtil.deleteNodeByPath("/testCreateNode1/"+c);
            }
        }
        //在删除父节点
        boolean result  = zookeeperUtil.deleteNodeByPath("/testCreateNode1");
        if(result){
            System.out.println("操作成功");
        }else {
            System.out.println("操作失败");
        }
    }
    @After
    public void  distory(){
        System.out.println("最终执行的方法。。。");
    }
}
回顾:
           zk数据存储  树状,节点类型4中:
               持久节点,持久有序节点,临时节点,临时有序节点
           命令:
                  help   帮助命令(查看所有命令)
                  connect   ip(或者主机名称):端口(2181)
                  close   关闭当前的会话
                  quit    退出
                  create  [-s]  [-e]  /路径   内容   创建节点,默认就是持久节点,根据参数不同,创建不同节点
                  set   /路径    内容     修改节点内容
                  get   /路径   [watch]    获取节点内容[是否监听(只监听一次)]
                  getAcl   /路径       ACL (访问控制列表,对每个节点进行设置,不会级联子节点)
                                             默认: world:anyone:crwda
                  setAcl   /路径     schema:id:permission 
                                            schema:    world   ip   auth   digest 
                                            id:       anyone   ip     自定义用户(scott,admin) 
                                            permission:   create  是否创建子节点   
                                                                  read   获取当前节点内容
                                                                  write  修改当前节点内容
                                                                  delete   删除当前节点内容
                                                                  admin   是否可以修改ACL访问控制列表  
               delete  /路径     只能删除没有子节点的节点
               rmr     /路径     可以删除所有节点(有字节点也可以)
                ls      /路径   [watch]   查看子节点   [可以使用监听,子节点发生变化(添加和删除),只监听一次]
               histroy   返回最近使用的10条命令
           java  对zk的操作(和命令操作类似,只不过换成了 java代码)

3.4 java模拟zk管理其他集群

(练习zookeeper java 方法操作)

1,分析原理

2,开发代码

util类:

package com.aaa.test;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
 * fileName:LoadP
 * description:
 * author:zz
 * createTime:2020/7/14 21:11
 * version:1.0.0
 */
public class LoadP {
    /**
     * 加载配置文件方法
      * @param path
     * @return
     */
    public static Properties load(String path){
        Properties properties = new Properties();
        InputStream inputStream = LoadP.class.getResourceAsStream("/"+path);
        try {
            properties.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return properties;
    }
}
  服务注册:
package com.aaa.test.file;
import com.aaa.test.LoadP;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import java.util.Properties;
/**
 * fileName:HdfsServer
 * description:
 * author:zz
 * version:1.0.0
 */
public class HdfsServer {
    private ZooKeeper zooKeeper;
   // private static final String parentPath="/servers";
    private  Properties load = LoadP.load("zk.properties");
    /**
     * 获取连接
     * @throws Exception
     */
    public void getZKConnect() throws Exception{
        zooKeeper = new ZooKeeper(load.getProperty("cstr"), Integer.valueOf(load.getProperty("to")), new Watcher() {
            public void process(WatchedEvent watchedEvent) {
            }
        });
    }
    /**
     * 注册
     * @param serverName
     * @throws KeeperException
     * @throws InterruptedException
     */
    public void registerToZkCluster(String serverName) throws KeeperException, InterruptedException {
        Stat stat = zooKeeper.exists(load.getProperty("parentPath"), false);
        if(stat==null) {
            String parentPath = zooKeeper.create(load.getProperty("parentPath"), serverName.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            System.out.println("无父节点,创建:"+parentPath);
        }
        String s = zooKeeper.create(load.getProperty("parentPath") + "/hdfs", serverName.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        System.out.println(serverName+"主机上线了,注册节点为"+s);
    }
    /**
     * 处理业务
     * @param serverName
     * @throws InterruptedException
     */
    public void handleService(String serverName) throws InterruptedException {
        System.out.println(serverName+"开始工作,准备存储或者下载文件。。。");
        Thread.sleep(Integer.MAX_VALUE);
    }
    public static void main(String[] args) throws Exception {
        HdfsServer hdfsServer =new HdfsServer();
        hdfsServer.getZKConnect();
        //args[0]="cs1";
        hdfsServer.registerToZkCluster(args[0]);
        hdfsServer.handleService(args[0]);
    }
}
web服务感知:
package com.aaa.test.file;
import com.aaa.test.LoadP;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
/**
 * fileName:WebServer
 * description:
 * author:zz
 * version:1.0.0
 */
public class WebServer {
    private ZooKeeper zooKeeper;
    private  Properties load = LoadP.load("zk.properties");
    /**
     * 获取连接
     * @throws Exception
     */
    public void getZKConnect() throws Exception{
        zooKeeper = new ZooKeeper(load.getProperty("cstr"), Integer.valueOf(load.getProperty("to")), new Watcher() {
            public void process(WatchedEvent watchedEvent) {
                try {
                    watchServerList();
                } catch (KeeperException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
    }
    /**
     * 监控集群中服务器状态
     * @throws KeeperException
     * @throws InterruptedException
     */
    public void watchServerList() throws KeeperException, InterruptedException {
        List<String> children = zooKeeper.getChildren(load.getProperty("parentPath"), true);
        List<String> hdfsList =new ArrayList<String>();
        for (String child : children) {
            byte[] data = zooKeeper.getData(load.getProperty("parentPath") + "/" + child, false, null);
             hdfsList.add(new String(data));
        }
        System.out.println("工作的HDFS有:"+hdfsList);
    }
    /**
     * 运行web业务
     * @throws InterruptedException
     */
    public  void handleWebService() throws InterruptedException {
        System.out.println("web 服务器在正常工作。。。");
        Thread.sleep(Integer.MAX_VALUE);
    }
    public static void main(String[] args) throws Exception {
        WebServer webServer=new WebServer();
        webServer.getZKConnect();
        webServer.watchServerList();
        webServer.handleWebService();
    }
}

jar包运行:

java -cp  *.jar  含有main的类  参数

具体操作, cmd ->进入jar的存放目录,执行如下命令:

java -cp .\ZooKeeperDemo.jar com.aaa.zk.dp.FtpServers ftpa

java -cp .\ZooKeeperDemo.jar com.aaa.zk.dp.FtpServers ftpb

java -cp .\ZooKeeperDemo.jar com.aaa.zk.dp.FtpServers ftpc

java -cp .\ZooKeeperDemo.jar com.aaa.zk.dp.FtpServers ftpd

java -cp .\ZooKeeperDemo.jar com.aaa.zk.dp.FtpClients

4,知识点总结
5,本章面试题

相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
目录
相关文章
|
20天前
|
设计模式 架构师 前端开发
JavaEE企业级分布式高级架构师课程
本课程主要面向1-5年及以上工作经验的Java工程师,大纲由IT界知名大牛 — 廖雪峰老师亲自打造,由来自一线大型互联网公司架构师、技术总监授课,内容涵盖深入spring5设计模式/高级web MVC开发/高级数据库设计与开发/高级响应式web开发/分布式架构设计等主流核心技术。
21 1
JavaEE企业级分布式高级架构师课程
|
14天前
|
设计模式 安全 Java
【分布式技术专题】「Tomcat技术专题」 探索Tomcat技术架构设计模式的奥秘(Server和Service组件原理分析)
【分布式技术专题】「Tomcat技术专题」 探索Tomcat技术架构设计模式的奥秘(Server和Service组件原理分析)
20 0
|
15天前
|
NoSQL Java Redis
【分布式技术专题】「分布式技术架构」手把手教你如何开发一个属于自己的分布式锁的功能组件(二)
【分布式技术专题】「分布式技术架构」手把手教你如何开发一个属于自己的分布式锁的功能组件
13 0
|
1天前
|
分布式计算 Hadoop 大数据
大数据技术与Python:结合Spark和Hadoop进行分布式计算
【4月更文挑战第12天】本文介绍了大数据技术及其4V特性,阐述了Hadoop和Spark在大数据处理中的作用。Hadoop提供分布式文件系统和MapReduce,Spark则为内存计算提供快速处理能力。通过Python结合Spark和Hadoop,可在分布式环境中进行数据处理和分析。文章详细讲解了如何配置Python环境、安装Spark和Hadoop,以及使用Python编写和提交代码到集群进行计算。掌握这些技能有助于应对大数据挑战。
|
1天前
|
监控 负载均衡 Cloud Native
ZooKeeper分布式协调服务详解:面试经验与必备知识点解析
【4月更文挑战第9天】本文深入剖析ZooKeeper分布式协调服务原理,涵盖核心概念如Server、Client、ZNode、ACL、Watcher,以及ZAB协议在一致性、会话管理、Leader选举中的作用。讨论ZooKeeper数据模型、操作、会话管理、集群部署与管理、性能调优和监控。同时,文章探讨了ZooKeeper在分布式锁、队列、服务注册与发现等场景的应用,并在面试方面分析了与其它服务的区别、实战挑战及解决方案。附带Java客户端实现分布式锁的代码示例,助力提升面试表现。
19 2
|
14天前
|
存储 监控 安全
金石推荐 | 【分布式技术专题】「单点登录技术架构」一文带领你好好认识以下Saml协议的运作机制和流程模式
金石推荐 | 【分布式技术专题】「单点登录技术架构」一文带领你好好认识以下Saml协议的运作机制和流程模式
14 0
|
14天前
|
存储 Java 应用服务中间件
【分布式技术专题】「架构实践于案例分析」盘点互联网应用服务中常用分布式事务(刚性事务和柔性事务)的原理和方案
【分布式技术专题】「架构实践于案例分析」盘点互联网应用服务中常用分布式事务(刚性事务和柔性事务)的原理和方案
39 0
|
14天前
|
canal 消息中间件 关系型数据库
【分布式技术专题】「分布式技术架构」MySQL数据同步到Elasticsearch之N种方案解析,实现高效数据同步
【分布式技术专题】「分布式技术架构」MySQL数据同步到Elasticsearch之N种方案解析,实现高效数据同步
62 0
|
15天前
|
缓存 应用服务中间件 数据库
【分布式技术专题】「缓存解决方案」一文带领你好好认识一下企业级别的缓存技术解决方案的运作原理和开发实战(多级缓存设计分析)
【分布式技术专题】「缓存解决方案」一文带领你好好认识一下企业级别的缓存技术解决方案的运作原理和开发实战(多级缓存设计分析)
23 1
|
1月前
|
存储 供应链 安全
新一代数据库技术:融合区块链与分布式存储的未来前景
传统的数据库技术在面对大规模数据存储和安全性方面存在诸多挑战,而新一代数据库技术正在崭露头角。本文将探讨如何融合区块链与分布式存储技术,为数据库领域带来全新的发展机遇,并分析其在实际应用中的潜力与前景。