第1章 Zookeeper入门1.1 概述1.2 特色1.3 数据结构1.4 应用场景1.5 下载地址第2章 Zookeeper安装2.1 本地模式安装部署2.2 配置参数解读第3章 Zookeeper内部原理3.1 选举机制(面试重点)3.2 节点类型3.3 stat结构体3.4 监听器原理(面试重点)3.5 写数据流程第4章 Zookeeper实战(开发重点)4.1 分布式安装部署4.2 客户端命令行操做4.3 API应用4.3.1 Eclipse环境搭建4.3.2 建立ZooKeeper客户端4.3.3 建立子节点4.3.4 获取子节点并监听节点变化4.3.5 判断Znode是否存在4.4 监听服务器节点动态上下线案例第5章 企业面试真题5.1 请简述ZooKeeper的选举机制(半数机制)5.2 ZooKeeper的监听原理是什么?5.3 ZooKeeper的部署方式有哪几种?集群中的角色有哪些?集群最少须要几台机器?5.4 ZooKeeper的经常使用命令java
Zookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache项目。node
提供的服务包括:统一命名服务、统一配置管理、统一集群管理、服务器节点动态上下线、软负载均衡等。
统一命名服务linux
一、官网首页:
https://zookeeper.apache.org/面试
一、安装前准备
(1)安装jdk
(2)拷贝Zookeeper安装包到Linux系统下
(3)解压到指定目录spring
[atguigu@hadoop102 software]$ tar -zxvf zookeeper-3.4.10.tar.gz -C /opt/module/
二、配置修改
(1)将/opt/module/zookeeper-3.4.10/conf/这个路径下的zoo_sample.cfg修改成zoo.cfg;apache
[atguigu@hadoop102 conf]$ pwd
/opt/module/zookeeper-3.4.10/conf
[atguigu@hadoop102 conf]$ mv zoo_sample.cfg zoo.cfg
(2)打开zoo.cfg文件,修改dataDir路径:vim
[atguigu@hadoop102 zookeeper-3.4.10]$ vim zoo.cfg
修改以下内容:api
dataDir=/opt/module/zookeeper-3.4.10/zkData
(3)在/opt/module/zookeeper-3.4.10/这个目录上建立zkData文件夹ruby
[atguigu@hadoop102 zookeeper-3.4.10]$ mkdir zkData
三、操做Zookeeper
(1)启动Zookeeper:bash
[atguigu@hadoop102 zookeeper-3.4.10]$ bin/zkServer.sh start
(2)查看进程是否启动:
[atguigu@hadoop102 zookeeper-3.4.10]$ jps
4020 Jps
4001 QuorumPeerMain
(3)查看状态:
[atguigu@hadoop102 zookeeper-3.4.10]$ bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg
Mode: standalone
(4)启动客户端:
[atguigu@hadoop102 zookeeper-3.4.10]$ bin/zkCli.sh
(5)退出客户端:
[zk: localhost:2181(CONNECTED) 0] quit
(6)中止Zookeeper服务:
[atguigu@hadoop102 zookeeper-3.4.10]$ bin/zkServer.sh stop
Zookeeper中的配置文件zoo.cfg中参数含义解读以下:
心跳机制
,而且设置最小的session超时时间为两倍心跳时间。(session的最小超时时间是2*tickTime)Follower跟随者服务器
与Leader领导者服务器
之间初始链接时能容忍的最多心跳数(tickTime的数量),用它来限定集群中的Zookeeper服务器链接到Leader的时限。1)半数机制(Paxos 协议):集群中半数以上机器存活,集群可用。因此Zookeeper适合安装奇数台服务器。
2)Zookeeper虽然在配置文件中并无指定Master和Slave。可是,Zookeeper工做时,是有一个节点为Leader,其余则为Follower,Leader是经过内部的选举机制
临时产生的。
3)以一个简单的例子来讲明整个选举的过程。
假设有五台服务器组成的Zookeeper集群,它们的id从1-5,同时它们都是最新启动的,也就是没有历史数据,在存放数据量这一点上,都是同样的。假设这些服务器依序启动,来看看会发生什么,以下图所示。
(1)服务器1启动,此时只有它一台服务器启动了,它发出去的报文没有任何响应,因此它的选举状态一直是LOOKING状态。
(2)服务器2启动,它与最开始启动的服务器1进行通讯,互相交换本身的选举结果,因为二者都没有历史数据,因此id值较大的服务器2胜出,可是因为没有达到超过半数以上的服务器都赞成选举它(这个例子中的半数以上是3),因此服务器一、2仍是继续保持LOOKING状态。
(3)服务器3启动,根据前面的理论分析,服务器3成为服务器一、二、3中的老大,而与上面不一样的是,此时有三台服务器选举了它,因此它成为了此次选举的Leader。
(4)服务器4启动,根据前面的分析,理论上服务器4应该是服务器一、二、三、4中最大的,可是因为前面已经有半数以上的服务器选举了服务器3,因此它只能接收当小弟的命了。
(5)服务器5启动,同4同样当小弟。
10)dataLength - znode的数据长度
11)numChildren - znode子节点数量
一、集群规划
在hadoop10二、hadoop103和hadoop104三个节点上部署Zookeeper。
二、解压安装
(1)解压Zookeeper安装包到/opt/module/目录下
[atguigu@hadoop102 software]$ tar -zxvf zookeeper-3.4.10.tar.gz -C /opt/module/
(2)同步/opt/module/zookeeper-3.4.10/目录内容到hadoop10三、hadoop104
[atguigu@hadoop102 module]$ xsync zookeeper-3.4.10/
三、配置服务器编号
(1)在/opt/module/zookeeper-3.4.10/这个目录下建立zkData
[atguigu@hadoop102 zookeeper-3.4.10]$ mkdir -p zkData
(2)在/opt/module/zookeeper-3.4.10/zkData目录下建立一个myid的文件
[atguigu@hadoop102 zkData]$ touch myid
添加myid文件,注意必定要在linux里面建立,在notepad++里面极可能乱码。
(3)编辑myid文件
[atguigu@hadoop102 zkData]$ vim myid
在文件中添加与server对应的编号:
2
(4)拷贝配置好的zookeeper到其余机器上
[atguigu@hadoop102 zkData]$ xsync myid
并分别在hadoop10二、hadoop103上修改myid文件中内容为三、4
四、配置zoo.cfg文件
(1)重命名/opt/module/zookeeper-3.4.10/conf这个目录下的zoo_sample.cfg为zoo.cfg
[atguigu@hadoop102 conf]$ mv zoo_sample.cfg zoo.cfg
(2)打开zoo.cfg文件
[atguigu@hadoop102 conf]$ vim zoo.cfg
修改数据存储路径配置
dataDir=/opt/module/zookeeper-3.4.10/zkData
增长以下配置
#######################cluster##########################
server.2=hadoop102:2888:3888
server.3=hadoop103:2888:3888
server.4=hadoop104:2888:3888
(3)同步zoo.cfg配置文件
[atguigu@hadoop102 conf]$ xsync zoo.cfg
(4)配置参数解读
server.A=B:C:D。
A是一个数字,表示这个是第几号服务器;
集群模式下配置一个文件myid,这个文件在dataDir目录下,这个文件里面有一个数据就是A的值,Zookeeper启动时读取此文件,拿到里面的数据与zoo.cfg里面的配置信息比较从而判断究竟是哪一个server。
B是这个服务器的ip地址;
C是这个服务器与集群中的Leader服务器交换信息
的端口;
D是万一集群中的Leader服务器挂了,须要一个端口来从新进行选举,选出一个新的Leader,而这个端口就是用来执行选举时
服务器相互通讯的端口。
四、集群操做
(1)分别启动Zookeeper
[atguigu@hadoop102 zookeeper-3.4.10]$ bin/zkServer.sh start
[atguigu@hadoop103 zookeeper-3.4.10]$ bin/zkServer.sh start
[atguigu@hadoop104 zookeeper-3.4.10]$ bin/zkServer.sh start
(2)查看状态
[atguigu@hadoop102 zookeeper-3.4.10]# bin/zkServer.sh status
JMX enabled by default
Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg
Mode: follower
[atguigu@hadoop103 zookeeper-3.4.10]# bin/zkServer.sh status
JMX enabled by default
Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg
Mode: leader
[atguigu@hadoop104 zookeeper-3.4.5]# bin/zkServer.sh status
JMX enabled by default
Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg
Mode: follower
一、启动客户端
[atguigu@hadoop103 zookeeper-3.4.10]$ bin/zkCli.sh
二、显示全部操做命令
[zk: localhost:2181(CONNECTED) 1] help
三、查看当前znode中所包含的内容
[zk: localhost:2181(CONNECTED) 0] ls /
[zookeeper]
四、查看当前节点详细数据
[zk: localhost:2181(CONNECTED) 1] ls2 /
[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个普通节点
[zk: localhost:2181(CONNECTED) 3] create /sanguo "zhuge"
Created /sanguo
[zk: localhost:2181(CONNECTED) 4] create /sanguo/shuguo "liubei"
Created /sanguo/shuguo
六、得到节点的值
[zk: localhost:2181(CONNECTED) 5] get /sanguo
zhuge
cZxid = 0x100000003
ctime = Wed Aug 29 00:03:23 CST 2018
mZxid = 0x100000003
mtime = Wed Aug 29 00:03:23 CST 2018
pZxid = 0x100000004
cversion = 1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 7
numChildren = 1
[zk: localhost:2181(CONNECTED) 6]
[zk: localhost:2181(CONNECTED) 6] get /sanguo/shuguo
liubei
cZxid = 0x100000004
ctime = Wed Aug 29 00:04:35 CST 2018
mZxid = 0x100000004
mtime = Wed Aug 29 00:04:35 CST 2018
pZxid = 0x100000004
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 6
numChildren = 0
七、建立短暂节点
[zk: localhost:2181(CONNECTED) 7] create -e /sanguo/wuguo "zhouyu"
Created /sanguo/wuguo
(1)在当前客户端是能查看到的
[zk: localhost:2181(CONNECTED) 3] ls /sanguo
[wuguo, shuguo]
(2)退出当前客户端而后再重启客户端
[zk: localhost:2181(CONNECTED) 12] quit
[atguigu@hadoop104 zookeeper-3.4.10]$ bin/zkCli.sh
(3)再次查看根目录下短暂节点已经删除
[zk: localhost:2181(CONNECTED) 0] ls /sanguo
[shuguo]
八、建立带序号的节点
(1)先建立一个普通的根节点/sanguo/weiguo
[zk: localhost:2181(CONNECTED) 1] create /sanguo/weiguo "caocao"
Created /sanguo/weiguo
(2)建立带序号的节点
[zk: localhost:2181(CONNECTED) 2] create -s /sanguo/weiguo/xiaoqiao "jinlian"
Created /sanguo/weiguo/xiaoqiao0000000000
[zk: localhost:2181(CONNECTED) 3] create -s /sanguo/weiguo/daqiao "jinlian2"
Created /sanguo/weiguo/daqiao0000000001
[zk: localhost:2181(CONNECTED) 4] create -s /sanguo/weiguo/diaocan "jinlian3"
Created /sanguo/weiguo/diaocan0000000002
若是原来没有序号节点,序号从0开始依次递增。若是原节点下已有2个节点,则再排序时从2开始,以此类推。
九、修改节点数据值
[zk: localhost:2181(CONNECTED) 6] set /sanguo/weiguo "simayi"
十、节点的值变化监听
(1)在hadoop104主机上注册监听/sanguo节点数据变化
[zk: localhost:2181(CONNECTED) 8] get /sanguo watch
(2)在hadoop103主机上修改/sanguo节点的数据
[zk: localhost:2181(CONNECTED) 1] set /sanguo "xisi"
(3)观察hadoop104主机收到数据变化的监听
WATCHER::
WatchedEvent state:SyncConnected type:NodeDataChanged path:/sanguo
注意:该注册监听一次,那么就只生效一次。下次须要从新注册。
十一、节点的子节点变化监听(路径变化)
(1)在hadoop104主机上注册监听/sanguo节点的子节点变化
[zk: localhost:2181(CONNECTED) 1] ls /sanguo watch
[aa0000000001, server101]
(2)在hadoop103主机/sanguo节点上建立子节点
[zk: localhost:2181(CONNECTED) 2] create /sanguo/jin "simayi"
Created /sanguo/jin
(3)观察hadoop104主机收到子节点变化的监听
WATCHER::
WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/sanguo
注意:该注册监听一次,那么就只生效一次。下次须要从新注册。
十二、删除节点
[zk: localhost:2181(CONNECTED) 4] delete /sanguo/jin
1三、递归删除节点
[zk: localhost:2181(CONNECTED) 15] rmr /sanguo/shuguo
1四、查看节点状态
[zk: localhost:2181(CONNECTED) 17] stat /sanguo
cZxid = 0x100000003
ctime = Wed Aug 29 00:03:23 CST 2018
mZxid = 0x100000011
mtime = Wed Aug 29 00:21:23 CST 2018
pZxid = 0x100000014
cversion = 9
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 1
一、建立一个Maven工程
二、添加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>
<!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.10</version>
</dependency>
</dependencies>
三、拷贝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
/**
* 建立ZooKeeper客户端
* @throws IOException
*/
@Before
public void init() throws IOException {
zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
public void process(WatchedEvent event) {
// 再次启动监听
try {
zkClient.getChildren("/", true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* 建立子节点
* @throws Exception
*/
@Test
public void create() throws Exception {
// 参数1:要建立的节点的路径; 参数2:节点数据 ; 参数3:节点权限 ;参数4:节点的类型
String nodeCreated = zkClient.create("/atguigu", "jinlian".getBytes(), Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
System.out.println(nodeCreated);
}
/**
* 获取子节点并监听节点变化
* @throws Exception
*/
@Test
public void getChildren() throws Exception {
List<String> children = zkClient.getChildren("/", true);
for (String child : children) {
System.out.println(child);
}
// 延时阻塞
Thread.sleep(Long.MAX_VALUE);
}
/**
* 判断znode是否存在
* @throws Exception
*/
@Test
public void exist() throws Exception {
Stat stat = zkClient.exists("/eclipse", false);
System.out.println(stat == null ? "not exist" : "exist");
}
一、需求
某分布式系统中,主节点能够有多台,能够动态上下线,任意一台客户端都能实时感知到主节点服务器的上下线。
二、需求分析,以下图所示
[zk: localhost:2181(CONNECTED) 10] create /servers "servers"
Created /servers
(1)服务器端向Zookeeper注册代码
package com.atguigu.zookeeper;
import java.io.IOException;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
public class DistributeServer {
public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
// 一、链接zookeeper集群
DistributeServer server = new DistributeServer();
server.getConnect();
// 二、注册服务器节点
server.registerServer(args[0]);
// 三、业务逻辑功能
server.business(args[0]);
}
private void business(String hostname) throws InterruptedException {
System.out.println(hostname + " is working ...");
Thread.sleep(Long.MAX_VALUE);
}
private String parentNode = "/servers";
private void registerServer(String hostname) throws KeeperException, InterruptedException {
String path = zkClient.create(parentNode + "/server", hostname.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
System.out.println(hostname + " is online " + path);
}
private String connectString = "hadoop102:2181,hadoop103:2181,hadoop104:2181";
private int sessionTimeout = 2000;
private ZooKeeper zkClient = null;
private void getConnect() throws IOException {
zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
public void process(WatchedEvent event) {
}
});
}
}
(2)客户端代码
package com.atguigu.zookeeper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
public class DistributeClient {
public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
// 一、链接zookeeper集群
DistributeClient client = new DistributeClient();
client.getConnect();
// 二、获取子节点并监听节点变化
client.getChildren();
// 三、业务逻辑功能
client.business();
}
private void business() throws InterruptedException {
System.out.println("client is working ...");
Thread.sleep(Long.MAX_VALUE);
}
private String parentNode = "/servers";
private void getChildren() throws KeeperException, InterruptedException {
// 一、获取服务器子节点信息,而且对父节点进行监听
List<String> children = zkClient.getChildren(parentNode , true);
// 二、存储服务器信息列表
ArrayList<String> hosts = new ArrayList<String>();
// 三、遍历全部节点,获取节点中的主机名称信息
for (String child : children) {
byte[] data = zkClient.getData(parentNode + "/" + child, false, null);
hosts.add(new String(data));
}
// 四、打印服务器列表信息
System.out.println(hosts);
}
private String connectString = "hadoop102:2181,hadoop103:2181,hadoop104:2181";
private int sessionTimeout = 2000;
private ZooKeeper zkClient = null;
private void getConnect() throws IOException {
zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
public void process(WatchedEvent event) {
// 再次启动监听
try {
getChildren();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
详见3.1。
详见3.4。
(1)部署方式单机模式、集群模式。
(2)角色:Leader和Follower。
(3)集群最少须要机器数:3。
ls create get delete set……