文章目录
三、Zookeeper实战(开发重点)
3.1 分布式安装部署
1)集群规划
在 hadoop105、hadoop106 和 hadoop107 三个节点上部署 Zookeeper。
2)解压安装
(1)解压Zookeeper安装包到/opt/module/目录下,并可以自定义名称
[xiaoxq@hadoop105 software]$ tar -zxvf zookeeper-3.5.7.tar.gz -C /opt/module/
[xiaoxq@hadoop105 module]$ mv apache-zookeeper-3.5.7-bin.tar.gz zookeeper-3.5.7
(2)同步/opt/module/zookeeper-3.5.7目录内容到hadoop106、hadoop107
[xiaoxq@hadoop105 module]$ xsync zookeeper-3.5.7/
3)配置服务器编号
(1)在/opt/module/zookeeper-3.5.7/这个目录下创建zkData
[xiaoxq@hadoop105 zookeeper-3.5.7]$ mkdir -p zkData
(2)在/opt/module/zookeeper-3.5.7/zkData目录下创建一个myid的文件
[xiaoxq@hadoop105 zkData]$ touch myid
添加myid文件,注意一定要在linux里面创建,在notepad++里面很可能乱码
(3)编辑myid文件
[xiaoxq@hadoop105 zkData]$ vi myid
在文件中添加与server对应的编号:
5
(4)拷贝配置好的zookeeper到其他机器上
[xiaoxq@hadoop105 zkData]$ xsync myid
并分别在hadoop106、hadoop107 上修改myid文件中内容为 6、7
4)配置zoo.cfg文件
(1)重命名/opt/module/zookeeper-3.5.7/conf这个目录下的zoo_sample.cfg为zoo.cfg
[xiaoxq@hadoop105 conf]$ mv zoo_sample.cfg zoo.cfg
(2)打开zoo.cfg文件
[xiaoxq@hadoop105 conf]$ vim zoo.cfg
修改数据存储路径配置
dataDir=/opt/module/zookeeper-3.5.7/zkData
增加如下配置
#######################cluster##########################
server.5=hadoop105:2888:3888
server.6=hadoop106:2888:3888
server.7=hadoop107:2888:3888
(3)同步zoo.cfg配置文件
[xiaoxq@hadoop105 conf]$ xsync zoo.cfg
(4)配置参数解读
server.A=B:C:D。
A是一个数字,表示这个是第几号服务器;
集群模式下配置一个文件 myid,这个文件在 dataDir 目录下,这个文件里面有一个数据就是A的值,Zookeeper 启动时读取此文件,拿到里面的数据与 zoo.cfg 里面的配置信息比较从而判断到底是哪个 server。
B是这个服务器的地址;
C是这个服务器 Follower 与集群中的 Leader 服务器交换信息的端口;
D是万一集群中的 Leader 服务器挂了,需要一个端口来重新进行选举,选出一个新的 Leader,而这个端口就是用来执行选举时服务器相互通信的端口。
5)集群操作
(1)分别启动Zookeeper
[xiaoxq@hadoop105 zookeeper-3.5.7]$ bin/zkServer.sh start
[xiaoxq@hadoop106 zookeeper-3.5.7]$ bin/zkServer.sh start
[xiaoxq@hadoop107 zookeeper-3.5.7]$ bin/zkServer.sh start
(2)查看状态
[xiaoxq@hadoop105 zookeeper-3.5.7]$ bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /opt/module/zookeeper-3.5.7/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost.
Mode: follower
[xiaoxq@hadoop106 zookeeper-3.5.7]$ bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /opt/module/zookeeper-3.5.7/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost.
Mode: follower
[xiaoxq@hadoop107 zookeeper-3.5.7]$ bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /opt/module/zookeeper-3.5.7/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost.
Mode: leader
3.2 客户端命令行操作
命令基本语法 | 功能描述 |
---|---|
help | 显示所有操作命令 |
ls path | 使用 ls 命令来查看当前znode的子节点-w 监听子节点变化-s 附加次级信息 |
create | 普通创建-s 含有序列-e 临时(重启或者超时消失) |
get path | 获得节点的值-w 监听节点内容变化-s 附加次级信息 |
set | 设置节点的具体值 |
stat | 查看节点状态 |
delete | 删除节点 |
deleteall | 递归删除节点 |
1)启动客户端
[xiaoxq@hadoop105 zookeeper-3.5.7]$ bin/zkCli.sh
WatchedEvent state:SyncConnected type:None path:null
[zk: localhost:2181(CONNECTED) 0]
2)显示所有操作命令
[zk: localhost:2181(CONNECTED) 0] help
3)查看当前znode中所包含的内容
[zk: localhost:2181(CONNECTED) 1] ls /
[zookeeper]
4)查看当前节点详细数据
[zk: localhost:2181(CONNECTED) 2] ls -s /
[zookeeper]cZxid = 0x0
ctime = Thu Jan 01 08:00:00 CST 1970
mZxid = 0x0
mtime = Thu Jan 01 08:00:00 CST 1970
pZxid = 0x0
cversion = -1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 1
5)分别创建2个普通节点
[zk: localhost:2181(CONNECTED) 4] create /xiyouji "wukong"
Created /xiyouji
[zk: localhost:2181(CONNECTED) 5] create /xiyouji/tianting "yudi"
Created /xiyouji/tianting
6)获得节点的值
[zk: localhost:2181(CONNECTED) 6] get /xiyouji
wukong
[zk: localhost:2181(CONNECTED) 7] get -s /xiyouji
wukong
cZxid = 0x100000002
ctime = Mon Jul 27 20:14:59 CST 2020
mZxid = 0x100000002
mtime = Mon Jul 27 20:14:59 CST 2020
pZxid = 0x100000003
cversion = 1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 6
numChildren = 1
[zk: localhost:2181(CONNECTED) 8] get -s /xiyouji/tianting
yudi
cZxid = 0x100000003
ctime = Mon Jul 27 20:17:48 CST 2020
mZxid = 0x100000003
mtime = Mon Jul 27 20:17:48 CST 2020
pZxid = 0x100000003
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 0
7)创建临时节点
[zk: localhost:2181(CONNECTED) 9] create -e /xiyouji/lingshan "rulai"
Created /xiyouji/lingshan
(1)在当前客户端是能查看到的
[zk: localhost:2181(CONNECTED) 10] ls /xiyouji
[lingshan, tianting]
(2)退出当前客户端然后再重启客户端
[zk: localhost:2181(CONNECTED) 11] quit
[xiaoxq@hadoop105 zookeeper-3.5.7]$ bin/zkCli.sh
(3)再次查看根目录下短暂节点已经删除(lingshan)
[zk: localhost:2181(CONNECTED) 0] ls /xiyouji
[tianting]
8)创建带序号的节点
(1)先创建一个普通的根节点/xiyouji/donghai
[zk: localhost:2181(CONNECTED) 1] create /xiyouji/donghai "longwang"
Created /xiyouji/donghai
(2)创建带序号的节点
[zk: localhost:2181(CONNECTED) 2] create /xiyouji/donghai "longwang"
Node already exists: /xiyouji/donghai
[zk: localhost:2181(CONNECTED) 3] create -s /xiyouji/donghai "longwang"
Created /xiyouji/donghai0000000003
[zk: localhost:2181(CONNECTED) 4] create -s /xiyouji/donghai "longwang"
Created /xiyouji/donghai0000000004
[zk: localhost:2181(CONNECTED) 5] ls /xiyouji
[donghai, donghai0000000003, donghai0000000004, tianting]
如果节点下原来没有子节点,序号从0开始依次递增。如果原节点下已有2个节点,则再排序时从2开始,以此类推。
9)修改节点数据值
[zk: localhost:2181(CONNECTED) 6] set /xiyouji/donghai "guichengxiang"
[zk: localhost:2181(CONNECTED) 8] get /xiyouji/donghai
guichengxiang
10)节点的值变化监听
(1)在 hadoop105 主机上注册监听 /xiyouji 节点
[zk: localhost:2181(CONNECTED) 9] get -w /xiyouji
wukong
(2)在 hadoop106 主机上修改/xiyouji节点的数据
[zk: localhost:2181(CONNECTED) 0] set /xiyouji "xiabing"
(3)观察 hadoop105 主机收到数据变化的监听
[zk: localhost:2181(CONNECTED) 10]
WATCHER::
WatchedEvent state:SyncConnected type:NodeDataChanged path:/xiyouji
11)节点的子节点变化监听(路径变化)
(1)在hadoop106主机上注册监听/xiyouji节点的子节点变化
[zk: localhost:2181(CONNECTED) 1] ls -w /xiyouji
[donghai, donghai0000000003, donghai0000000004, tianting]
(2)在hadoop105主机/xiyouji节点上创建子节点
[zk: localhost:2181(CONNECTED) 10] create /xiyouji/huaguozan "houzi"
Created /xiyouji/huaguozan
(3)观察hadoop106主机收到子节点变化的监听
[zk: localhost:2181(CONNECTED) 2]
WATCHER::
WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/xiyouji
12)删除节点
[zk: localhost:2181(CONNECTED) 2] delete /xiyouji/huaguozan
13)递归删除节点
[zk: localhost:2181(CONNECTED) 4] deleteall /xiyouji/tianting
14)查看节点状态
[zk: localhost:2181(CONNECTED) 6] stat /xiyouji
cZxid = 0x100000002
ctime = Mon Jul 27 20:14:59 CST 2020
mZxid = 0x10000000e
mtime = Mon Jul 27 20:31:32 CST 2020
pZxid = 0x100000011
cversion = 9
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 7
numChildren = 3
3.3 API 应用
3.3.1 IDEA环境搭建
1)创建一个MavenModule
2)添加pom文件
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
</dependency>
<dependency> <groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.5.7</version>
</dependency>
</dependencies>
3)拷贝log4j.properties文件到项目根目录
需要在项目的src/main/resources目录下,新建一个文件,命名为“log4j.properties”,在文件中填入。
log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
3.3.2 初始化 ZooKeeper 客户端
public class ZkClient {
private String connectString;
private int sessoinTimeout;
private ZooKeeper zkClient;
//1.获取客户端对象
@Before
public void init() throws IOException {
connectString = "hadoop105:2181,hadoop106:2181,hadoop107:2181";
sessoinTimeout = 4000;
//参数解读 1集群连接字符串 2连接超时时间 单位:毫秒 3当前客户端默认的监控器
zkClient = new ZooKeeper(connectString, sessoinTimeout, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
}
});
}
@After
public void close() throws InterruptedException {
//3.关闭客户端对象
zkClient.close();
}
}
3.3.3 获取子节点列表,不监听
@Test
public void ls() throws IOException, KeeperException, InterruptedException {
//2.用客户端对象做各种操作
List<String> children = zkClient.getChildren("/", false);
System.out.println(children);
}
运行结果
[zk: localhost:2181(CONNECTED) 0] ls /
[xiyouji, zookeeper]
3.3.4 获取子节点列表,并监听
@Test
public void getAndWatch() throws KeeperException, InterruptedException {
//判断节点是否存在
Stat stat = zkClient.exists("/xiyouji", false);
if (stat == null){
System.out.println("节点不存在");
return;
}
//节点存在
byte[] data = zkClient.getData("/xiyouji", new Watcher() {
@Override
public void process(WatchedEvent event) {
System.out.println(event);
}
}, stat);
System.out.println(new String(data));
//线程阻塞,睡眠
Thread.sleep(Long.MAX_VALUE);
}
3.3.5 创建子节点
@Test
public void getAndWatch() throws KeeperException, InterruptedException {
//判断节点是否存在
Stat stat = zkClient.exists("/xiyouji", false);
if (stat == null){
System.out.println("节点不存在");
return;
}
//节点存在
byte[] data = zkClient.getData("/xiyouji", new Watcher() {
@Override
public void process(WatchedEvent event) {
System.out.println(event);
}
}, stat);
System.out.println(new String(data));
//线程阻塞,睡眠
Thread.sleep(Long.MAX_VALUE);
}
3.3.6 判断Znode是否存在
@Test
public void exist() throws Exception {
Stat stat = zkClient.exists("/xiyouji", false);
System.out.println(stat == null ? "not exist" : "exist");
}
3.3.7 获取子节点存储的数据,不监听
@Test
public void get() throws KeeperException, InterruptedException {
//判断节点是否存在
Stat stat = zkClient.exists("/xiyouji", false);
if (stat == null) {
System.out.println("节点不存在...");
return;
}
byte[] data = zkClient.getData("/xiyouji", false, stat);
System.out.println(new String(data));
}
3.3.8 获取子节点存储的数据,并监听
@Test
public void getAndWatch() throws KeeperException, InterruptedException {
//判断节点是否存在
Stat stat = zkClient.exists("/xiyouji", false);
if (stat == null) {
System.out.println("节点不存在...");
return;
}
byte[] data = zkClient.getData("/xiyouji", new Watcher() {
@Override
public void process(WatchedEvent event) {
System.out.println(event);
}
}, stat);
System.out.println(new String(data));
//线程阻塞
Thread.sleep(Long.MAX_VALUE);
}
3.3.9设置节点的值
@Test
public void set() throws KeeperException, InterruptedException {
//判断节点是否存在
Stat stat = zkClient.exists("/xiyouji", false);
if (stat == null) {
System.out.println("节点不存在...");
return;
}
//参数解读 1节点路径 2节点的值 3版本号
zkClient.setData("/xiyouji", "nverguo".getBytes(), stat.getVersion());
}
3.3.10删除空节点
@Test
public void delete() throws KeeperException, InterruptedException {
//判断节点是否存在
Stat stat = zkClient.exists("/aaa", false);
if (stat == null) {
System.out.println("节点不存在...");
return;
}
zkClient.delete("/aaa", stat.getVersion());
}
3.3.11 删除非空节点,递归实现
//封装一个方法,方便递归调用
public void deleteAll(String path, ZooKeeper zk) throws KeeperException, InterruptedException {
//判断节点是否存在
Stat stat = zkClient.exists(path, false);
if (stat == null) {
System.out.println("节点不存在...");
return;
}
//先获取当前传入节点下的所有子节点
List<String> children = zk.getChildren(path, false);
if (children.isEmpty()) {
//说明传入的节点没有子节点,可以直接删除
zk.delete(path, stat.getVersion());
} else {
//如果传入的节点有子节点,循环所有子节点
for (String child : children) {
//删除子节点,但是不知道子节点下面还有没有子节点,所以递归调用
deleteAll(path + "/" + child, zk);
}
//删除完所有子节点以后,记得删除传入的节点
zk.delete(path, stat.getVersion());
}
}
//测试deleteAll
@Test
public void testDeleteAll() throws KeeperException, InterruptedException {
deleteAll("/xiyouji",zkClient);
}