这是我参与8月更文挑战的第15天,活动详情查看:8月更文挑战
一、集群安装
这里,提前准备好了三台机器,名为 hadoop101,Hadoop102、hadoop103.
我们需要在三台机器上都安装上 zookeeper。
1、将安装包上传到 linux 并解压,然后重命名为zookeeper
tar -zxvf zookeeper-3.5.7.tar.gz -C /opt/module/
2、配置服务器的编号。
三台服务器的编号需要自己新建一个myid 文件,同时在 zoo.cfg 目录中指向这个文件所在的文件夹。
我们在 zookeeper 目录下创建一个 zkData 文件夹,然后里面新增myid 文件,写上编号1
mkdir zkData
touch myid
在文件中添加与 server 对应的编号:
1
其他两台分别编上 2 和 3 。
3、配置 zoo.cfg 文件 将 conf/zoo_sample.cfg 重命名为 zoo.cfg
vim conf/zoo.cfg
修改dataDir
dataDir=/opt/sofeware/zookeeper/zkData
在文件末尾添加集群配置:
#######################cluster##########################
server.1=hadoop101:2888:3888
server.2=hadoop102:2888:3888
server.3=hadoop103:2888:3888
这里的配置参数需要讲解一下:
server.A=B:C:D。
A 是一个数字,表示这个是第几号服务器;
集群模式下配置一个文件myid,这个文件在dataDir目录下,这个文件里面有一个数据就是A的值,Zookeeper启动时读取此文件,拿到里面的数据与zoo.cfg里面的配置信息比较从而判断到底是哪个server。
B 是这个服务器的地址;
C 是这个服务器Follower与集群中的Leader服务器交换信息的端口;
D 是万一集群中的Leader服务器挂了,需要一个端口来重新进行选举,选出一个新的Leader,而这个端口就是用来执行选举时服务器相互通信的端口。
4、集群操作
可以直接启动 bin/zkServer.sh start 。但是需要每台机器上都配置下
集群下面为了方便写了个群起脚本
#!/bin/bash
for i in hadoop101 hadoop102 hadoop103
do
echo "===== $i zookeeper======"
case $1 in
"start")
echo "==================== START $i ZOOKEEPER ==================== "
ssh $i /opt/sofeware/zookeeper/bin/zkServer.sh start
;;
"status")
echo "==================== STATUS $i ZOOKEEPER ==================== "
ssh $i /opt/sofeware/zookeeper/bin/zkServer.sh status
;;
"stop")
echo "==================== STOP $i ZOOKEEPER ==================== "
ssh $i /opt/sofeware/zookeeper/bin/zkServer.sh stop
;;
*)
echo "Input error"
exit
;;
esac
done
直接群起:
[root@hadoop101 bin]# zkServer.sh start
查看状态:
[root@hadoop101 bin]# zkServer.sh status
===== hadoop101 zookeeper======
==================== STATUS hadoop101 ZOOKEEPER ====================
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /opt/sofeware/zookeeper/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost.
Mode: follower
===== hadoop102 zookeeper======
==================== STATUS hadoop102 ZOOKEEPER ====================
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /opt/sofeware/zookeeper/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost.
Mode: leader
===== hadoop103 zookeeper======
==================== STATUS hadoop103 ZOOKEEPER ====================
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /opt/sofeware/zookeeper/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost.
Mode: follower
可以看到 那台是主机、哪些是从机信息。
二、客户端基本命令
| 命令基本语法 | 功能描述 |
|---|---|
| help | 显示所有操作命令 |
| ls path | 使用 ls 命令来查看当前znode的子节点 [可监听]-w 监听子节点变化-s 附加次级信息 |
| create | 普通创建-s 含有序列-e 临时(重启或者超时消失) |
| get path | 获得节点的值 [可监听]-w 监听节点内容变化-s 附加次级信息 |
| set | 设置节点的具体值 |
| stat | 查看节点状态 |
| delete | 删除节点 |
| deleteall | 递归删除节点 |
2.1 启动客户端
bin/zkCli.sh
2.2 显示所有操作命令
[zk: localhost:2181(CONNECTED) 1] help
2.3 查看当前节点包含的内容
[zk: localhost:2181(CONNECTED) 0] ls /
[zookeeper]
2.4 查看当前节点详细数据
[zk: localhost:2181(CONNECTED) 2] ls2 /
'ls2' has been deprecated. Please use 'ls [-s] path' instead.
[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
2.5 创建普通节点
[zk: localhost:2181(CONNECTED) 3] create /jiangxi "nanchang"
Created /jiangxi
[zk: localhost:2181(CONNECTED) 4] create /jiangxi/nc "hl"
Created /jiangxi/nc
2.6 获得节点的值
[zk: localhost:2181(CONNECTED) 5] get /jiangxi
nanchang
[zk: localhost:2181(CONNECTED) 6] get /jiangxi/nc
hl
2.7 创建临时节点
create -e /jiangxi/yichun "ll"
这个临时节点在重启客户端之后就无法见到了。
2.8 创建带序号的节点
[zk: localhost:2181(CONNECTED) 7] create -s /jiangxi "jinxian"
Created /jiangxi0000000001
[zk: localhost:2181(CONNECTED) 8] create -s /jiangxi "yushan"
Created /jiangxi0000000002
2.9 修改节点的值
[zk: localhost:2181(CONNECTED) 9] set /jiangxi "xiazhen"
[zk: localhost:2181(CONNECTED) 10] get /jiangxi
xiazhen
2.10 节点的值变化监听
hadoop102 机器开启监听:
[zk: localhost:2181(CONNECTED) 8] get -w /jiangxi
hadoop101 机器修改值之后,hadoop102 能观测到该值变化
[zk: localhost:2181(CONNECTED) 1]
WATCHER::
WatchedEvent state:SyncConnected type:NodeDataChanged path:/jiangxi
如果节点的子节点发生变化,则信息如下:
WATCHER::
WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/jiangxi
2.11 删除节点
delete /jiangxi/yushan
2.12 查看节点状态
[zk: localhost:2181(CONNECTED) 1] stat /jiangxi
cZxid = 0x100000002
ctime = Fri Aug 13 14:34:44 CST 2021
mZxid = 0x100000008
mtime = Fri Aug 13 14:39:31 CST 2021
pZxid = 0x100000003
cversion = 1
dataVersion = 2
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 7
numChildren = 1
三、API应用
1、添加 jar 包
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.5.7</version>
</dependency>
</dependencies>
2、APi 测试
public class ZookeeperTest {
public static String connectString = "hadoop101:2181,hadoop102:2181,hadoop103:2181";
private static int sessionTimeout = 2000;
private ZooKeeper zkClient = null;
/**
* 创建 zookeeper 客户端
* @throws IOException
*/
@Before
public void init() throws IOException {
zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
// 收到事件通知后的回调函数(用户的业务逻辑)
System.out.println(watchedEvent.getType()+"--"+watchedEvent.getPath());
// 再次启动监控
try {
zkClient.getChildren("/",true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* 创建子节点
* @throws InterruptedException
* @throws KeeperException
*/
@Test
public void create() throws InterruptedException, KeeperException {
// 参数1:要创建的节点的路径;
// 参数2:节点数据 ;
// 参数3:节点权限 ;
// 参数4:节点的类型
String node = zkClient.create("/xiaolei","leilei".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
}
/**
* 获取子节点并监听节点变化
*/
@Test
public void getChildren() throws InterruptedException, KeeperException {
List<String> children = zkClient.getChildren("/", true);
for (String child : children) {
System.out.println(child);
}
// 延时阻塞,保持服务器在线
Thread.sleep(Long.MAX_VALUE);
}
/**
* 判断zookeeper 是否存在
* @throws InterruptedException
* @throws KeeperException
*/
@Test
public void exist() throws InterruptedException, KeeperException {
Stat exists = zkClient.exists("/xiaolei", false);
if(exists==null){
System.out.println("not exist");
}else{
System.out.println("exist");
}
}
}
四、zookeeper 总结
4.1 什么是 zookeeper
概述+作用+内部结构+应用场景+优缺点。
zookeeper 它是在大数据或者分布式领域中的一个常用的中间件,它主要用来当作注册中心的存在,用于服务注册和服务发现。它的内部结构和 linux文件系统很相似,整体看作一颗树,每个节点叫做 znode,默认能够存储 1mb的数据,这个节点也分为临时节点和持久两种类型, 总结下来,它就是一个分布式协调服务的框架。
4.2 zookeeper 都有哪些功能
它提供的服务包括:
- 统一命名管理:客户端应用能够根据指定名字来获取资源或服务的地址,提供者等信息。
- 统一配置管理:把公共的配置文件抽取出来,分发给其他系统。
- 统一集群管理:监控节点存活状态、运行请求等;
- 软负载均衡:让访问最少的服务器去处理最新的客户端请求。
- 分布式锁:临时顺序节点实现的。独占锁、共享锁。独占锁即一次只能有一个线程使用资源,共享锁是读锁共享,读写互斥,即可以有多线线程同时读同一个资源,如果要使用写锁也只能有一个线程使用。Zookeeper 可以对分布式锁进行控制。
4.3 ZAB 协议你了解吗
Zookeeper 的核心是原子广播机制,这个机制保证了各个 server 之间的同步。实现这个机制的协议叫做 Zab 协议。Zab 协议有两种模式,它们分别是恢复模式和广播模式。
恢复模式
当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数 server 完成了和 leader 的状态同步以后,恢复模式就结束了。状态同步保证了 leader 和 server 具有相同的系统状态。
广播模式
一旦 leader 已经和多数的 follower 进行了状态同步后,它就可以开始广播消息了,即进入广播状态。这时候当一个 server 加入 ZooKeeper 服务中,它会在恢复模式下启动,发现 leader,并和 leader 进行状态同步。待到同步结束,它也参与消息广播。ZooKeeper 服务一直维持在 Broadcast 状态,直到 leader 崩溃了或者 leader 失去了大部分的 followers 支持。
4.4 znode 节点类型
(1)PERSISTENT-持久节点
除非手动删除,否则节点一直存在于 Zookeeper 上
(2)EPHEMERAL-临时节点
临时节点的生命周期与客户端会话绑定,一旦客户端会话失效(客户端与zookeeper 连接断开不一定会话失效),那么这个客户端创建的所有临时节点都会被移除。
(3)PERSISTENT_SEQUENTIAL-持久顺序节点
基本特性同持久节点,只是增加了顺序属性,节点名后边会追加一个由父节点维护的自增整型数字。
(4)EPHEMERAL_SEQUENTIAL-临时顺序节点
基本特性同临时节点,增加了顺序属性,节点名后边会追加一个由父节点维护的自增整型数字。
4.5 通知机制
客户端会对某个 znode 建立一个 watcher 事件,当该znode 发生变化时,这些 client 会收到 zk 的通知,然后 client 可以根据 znode 变化来做出业务上的改变等。