- Zookerper
- 修改如下内容:
- 启动之前
- 启动之后
- The number of milliseconds of each tick
- The number of ticks that the initial
- synchronization phase can take
- The number of ticks that can pass between
- sending a request and getting an acknowledgement
- the directory where the snapshot is stored.
- do not use /tmp for storage, /tmp here is just
- example sakes.
- the port at which the clients will connect
- the maximum number of client connections.
- increase this if you need to handle more clients
- maxClientCnxns=60
- Be sure to read the maintenance section of the
- administrator guide before turning on autopurge.
- http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance">http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
- 在文件中添加与 server 对应的编号(注意:上下不要有空行,左右不要有空格)
- 例如:2
- 注意:添加 myid 文件,一定要在 Linux 里面创建,在 notepad++里面很可能乱码
- 并分别在 hadoop103、hadoop104 上修改 myid 文件中内容为 3、4
- 修改数据存储路径配置
- 增加如下配置
- 内容
- 节点信息说明
- 创建节点的事务id 每次修改 ZooKeeper状态都会产生一ZooKeeper事务 ID。事务 ID 是 ZooKeeper 中所有修改总的次序。每次修改都有唯一的cxid,如果 cxid1 小于cxid2,那么 zxid1 在 zxid2 之前发生。
- znode 被创建的毫秒数(从 1970 年开始)
- znode 最后更新的事务 zxid
- znode 最后修改的毫秒数(从 1970 年开始)
- znode 最后更新的子节点 zxid
- znode 子节点变化号,znode 子节点修改次数
- znode 数据变化号
- :znode 访问控制列表的变化号
- 如果是临时节点,这个是 znode 拥有者的 session id。如果不是临时节点则是 0
- znode 的数据长度
- znode 子节点数量
- 1. 在主机hadoop104上注册监听/zookeeper/demo1 节点数据变化
- 2. 在hadoop103上修改/sanguo 节点的数据
- 3. 观察 hadoop104 主机收到数据变化的监听
- 注意:在hadoop103再多次修改/sanguo的值,hadoop104上不会再收到监听。因为注册
- 1. 在 hadoop104 主机上注册监听/sanguo 节点的子节点变化
- 2. 在 hadoop103 主机/sanguo 节点上创建子节点
- 3.观察 hadoop104 主机收到子节点变化的监听
- 注意:节点的路径变化,也是注册一次,生效一次。想多次生效,就需要多次注册。
Zookerper
1.简介
zookeeper是一个开源的分布式的,为分布式框架提供协调服务的Apcahe项目<br />
2. 工作机制
从设计模式的角度理解:zookeeper是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据发生变化,zookeeper就负责通知已经注册的观察者,做出相应的反应。<br />
3.特点

- zookeeper:一个领导者,多个追随者组成
- 集群中只要有半数以上节点存活,zookeeper就能正常工作,所以zookeeper推荐安装奇数太服务器
- 全局数据一致性:每个server保存一份相同的数据副本,client无论连接到哪一台服务器,获取到的数据都是一致的
- 更新请求顺序执行:来自同一个client的更新请求按其发送的顺序依次执行
- 数据更新原子性:follower更新数据,要么成功,要么失败
-
4. 数据结构
zookeeper数据模型的结构与Linux文件系统类似,整体上可以看做是一棵树,每个节点看做一个ZNode。每个ZNode默认可以存储1MB数据,通过其路径唯一标识
5 应用
提供的服务包括:统一命名服务、统一配置服务、统一集群管理、服务器动态上下线,软负载均衡等
5.1 统一命名服务
5.2 统一配置管理
5.3 统一集群管理
5.4 服务器动态上下线
5.5 软负载均衡
6.本地化安装
6.1 下载地址
https://zookeeper.apache.org/
6.2 安装
- 解压到指定目录
tar -zxvf apache-zookeeper-3.5.7-bin.tar.gz -C /opt/module/
- 修改名称
mv apache-zookeeper-3.5.7-bin/ zookeeper-3.5.7
- 修改配置
- 拷贝 /opt/module/zookeeper-3.5.7/conf 这个路径下的 zoo_sample.cfg 为 zoo.cfg;
cp zoo_sample.cfg zoo.cfg
- 拷贝 /opt/module/zookeeper-3.5.7/conf 这个路径下的 zoo_sample.cfg 为 zoo.cfg;
在/opt/module/zookeeper-3.5.7/这个目录上创建 zkData 文件夹
mkdir zkData# 复制文件路径cd zkDatapwd
- 打开 zoo.cfg 文件,修改 dataDir 路径:(指定数据存放目录) ``` zookeeper-3.5.7]$ vim zoo.cfg
修改如下内容:
dataDir=/opt/module/zookeeper-3.5.7/zkData
<a name="a5fe1881"></a>### 6.3 启动- 启动zookbin/zkServer.sh start
bin/zkServer.sh start
- 查看进程是否启动
[zookeeper-3.5.7]$ jps
启动之前
[root@bogon conf]# jps 1503 Jps [root@bogon conf]#
启动之后
[root@bogon conf]# jps 1530 QuorumPeerMain 1562 Jps [root@bogon conf]#
- 查看状态
[root@bogon conf]# ../bin/zkServer.sh status ZooKeeper JMX enabled by default Using config: /opt/module/zookeeper-3.7.0_rw/bin/../conf/zoo.cfg Client port found: 2181. Client address: localhost. Client SSL: false. Mode: standalone
<br />至此单机版服务器启动完毕,接下来启动客户端- 启动客户端
[root@bogon conf]# ../bin/zkCli.sh
- 退出客户端
[zk: localhost:2181(CONNECTED) 1] quit
- 停止 Zookeeper
[root@bogon conf]# ../bin/zkServer.sh stop ZooKeeper JMX enabled by default Using config: /opt/module/zookeeper-3.7.0_rw/bin/../conf/zoo.cfg Stopping zookeeper … STOPPED [root@bogon conf]# ../bin/zkServer.sh status ZooKeeper JMX enabled by default Using config: /opt/module/zookeeper-3.7.0_rw/bin/../conf/zoo.cfg Client port found: 2181. Client address: localhost. Client SSL: false. Error contacting service. It is probably not running. [root@bogon conf]#
<a name="49b9e74c"></a>### 6.4 配置文件参数解读
The number of milliseconds of each tick
tickTime=2000 # 通信心跳时间,Zookeeper服务器与客户端心跳时间,单位毫秒
The number of ticks that the initial
synchronization phase can take
initLimit=10 # LF初始通信时限:Leader和Follower初始通信时,能容忍的最多心跳数
The number of ticks that can pass between
sending a request and getting an acknowledgement
syncLimit=5 # LF同步通信时限:Leader和Follower之间通信时间如果超过syncLimit * tickTime,Leader认为Follwer死掉,从服务器列表中删除Follwer。
the directory where the snapshot is stored.
do not use /tmp for storage, /tmp here is just
example sakes.
dataDir=/opt/module/zookeeper-3.7.0_rw/zkData # 保存Zookeeper中的数据 注意:默认的tmp目录,容易被Linux系统定期删除,所以一般不用默认的tmp目录。
the port at which the clients will connect
clientPort=2181 # 客户端连接端口,通常不做修改。
the maximum number of client connections.
increase this if you need to handle more clients
maxClientCnxns=60
#
Be sure to read the maintenance section of the
administrator guide before turning on autopurge.
#
http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
<a name="1fc40b5a"></a>## 7 集群化安装- 集群规划<br />在 hadoop102、hadoop103 和 hadoop104 三个节点上都部署 Zookeeper。- 解压安装1. 解压 Zookeeper 安装包到/opt/module/目录下
[atguigu@hadoop102 software]$ tar -zxvf apache-zookeeper-3.5.7-bin.tar.gz -C /opt/module/
2. 修改 apache-zookeeper-3.5.7-bin 名称为 zookeeper-3.5.7
[atguigu@hadoop102 module]$ mv apache-zookeeper-3.5.7-bin/ zookeeper-3.5.7
- 配置服务器编号1. 在/opt/module/zookeeper-3.5.7/这个目录下创建 zkData
[atguigu@hadoop102 zookeeper-3.5.7]$ mkdir zkData
2. 在/opt/module/zookeeper-3.5.7/zkData 目录下创建一个 myid 的文件
[atguigu@hadoop102 zkData]$ vi myid
在文件中添加与 server 对应的编号(注意:上下不要有空行,左右不要有空格)
例如:2
注意:添加 myid 文件,一定要在 Linux 里面创建,在 notepad++里面很可能乱码
3. 拷贝配置好的 zookeeper 到其他机器上
[atguigu@hadoop102 module ]$ xsync zookeeper-3.5.7
并分别在 hadoop103、hadoop104 上修改 myid 文件中内容为 3、4
- 配置zoo.cfg文1. 重命名/opt/module/zookeeper-3.5.7/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.5.7/zkData
增加如下配置
#################cluster
server.2=hadoop102:2888:3888 # hadoop102 没配置的话 换成主机ip server.3=hadoop103:2888:3888 server.4=hadoop104:2888:3888
3. 配置参数解读
server.A=B:C:D。 A 是一个数字,表示这个是第几号服务器; 集群模式下配置一个文件 myid,这个文件在 dataDir 目录下,这个文件里面有一个数据就是 A 的值,Zookeeper 启动时读取此文件,拿到里面的数据与 zoo.cfg 里面的配置信息比较从而判断到底是哪个 server。 B 是这个服务器的地址; C 是这个服务器 Follower 与集群中的 Leader 服务器交换信息的端口; D 是万一集群中的 Leader 服务器挂了,需要一个端口来重新进行选举,选出一个新的 Leader,而这个端口就是用来执行选举时服务器相互通信的端口。
4. 同步配置文件
- 集群操作
1. 分别启动 Zookeeper
[atguigu@hadoop102 zookeeper-3.5.7]$ bin/zkServer.sh start [atguigu@hadoop103 zookeeper-3.5.7]$ bin/zkServer.sh start [atguigu@hadoop104 zookeeper-3.5.7]$ bin/zkServer.sh start
2. 查看状态
[atguigu@hadoop102 zookeeper-3.5.7]# bin/zkServer.sh status JMX enabled by default Using config: /opt/module/zookeeper-3.5.7/bin/../conf/zoo.cfg Mode: follower
[atguigu@hadoop103 zookeeper-3.5.7]# bin/zkServer.sh status JMX enabled by default Using config: /opt/module/zookeeper-3.5.7/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.5.7/bin/../conf/zoo.cfg Mode: follower
- 编写集群启动脚本
1. 在 hadoop102 的/home/atguigu/bin 目录下创建脚本
[atguigu@hadoop102 bin]$ vim zk.sh
内容
case $1 in “start”){ for i in hadoop102 hadoop103 hadoop104 do echo ————— zookeeper $i 启动 —————— ssh $i “/opt/module/zookeeper-3.5.7/bin/zkServer.sh start” done };;
“stop”){ for i in hadoop102 hadoop103 hadoop104 do echo ————— zookeeper $i 停止 —————— ssh $i “/opt/module/zookeeper-3.5.7/bin/zkServer.sh stop” done };;
“status”){ for i in hadoop102 hadoop103 hadoop104 do echo ————— zookeeper $i 状态 —————— ssh $i “/opt/module/zookeeper-3.5.7/bin/zkServer.sh status” done };; esac
2. 增加脚本执行权限
[atguigu@hadoop102 bin]$ chmod u+x zk.sh
3. Zookeeper 集群启动脚本
[atguigu@hadoop102 module]$ zk.sh start
4. Zookeeper 集群停止脚本
[atguigu@hadoop102 module]$ zk.sh stop
<a name="80d4c9a8"></a>
## 8 选举机制
- 第一次启动

- 非第一次启动

<a name="02ab6848"></a>
## 9. 客户端 命令行操作
- 命令行语法
| 命令 | 功能 |
| --- | --- |
| heip | 显示所有操作命令 |
| ls 路径 | 查看当前节点ZNode 节点信息<br /> -w 监听子节点个数变化<br /> -s 显示详细信息 |
| create 节点名 节点数据 | 创建节点 <br /> -s 有序序列<br /> -e (ephemeral) 临时节点(重启或者超时时消失) <br /> -p (persistent) 长久节点 |
| get path | 获取节点的值 <br /> -w 获取节点数值,同时监听节点数值的变化 <br /> -s 显示详细信息 |
| set node value | 设置节点数值 |
| stat node | 查看节点状态 |
| delete node | 删除节点 |
| deleteall 父节点 | 递归删除父节点下所有节点 |
- 具体使用
1. 显示所有指令
[zk: localhost:2181(CONNECTED) 0] help
2. 查看节点信息
[zk: localhost:2181(CONNECTED) 1] ls / [zookeeper] [zk: localhost:2181(CONNECTED) 2] ls /zookeeper [config, quota] [zk: localhost:2181(CONNECTED) 3] ls /zookeeper/config [] [zk: localhost:2181(CONNECTED) 4]
3. 查看节点的详细数据
[zk: localhost:2181(CONNECTED) 4] ls -s /
节点信息说明
[zookeeper]
创建节点的事务id 每次修改 ZooKeeper状态都会产生一ZooKeeper事务 ID。事务 ID 是 ZooKeeper 中所有修改总的次序。每次修改都有唯一的cxid,如果 cxid1 小于cxid2,那么 zxid1 在 zxid2 之前发生。
cZxid = 0x0
znode 被创建的毫秒数(从 1970 年开始)
ctime = Wed Dec 31 19:00:00 EST 1969
znode 最后更新的事务 zxid
mZxid = 0x0
znode 最后修改的毫秒数(从 1970 年开始)
mtime = Wed Dec 31 19:00:00 EST 1969
znode 最后更新的子节点 zxid
pZxid = 0x0
znode 子节点变化号,znode 子节点修改次数
cversion = -1
znode 数据变化号
dataVersion = 0
:znode 访问控制列表的变化号
aclVersion = 0
如果是临时节点,这个是 znode 拥有者的 session id。如果不是临时节点则是 0
ephemeralOwner = 0x0
znode 的数据长度
dataLength = 0
znode 子节点数量
numChildren = 1
<br />
4. 创建节点
- 创建普通节点(默认永久节点,不带序号)
[zk: localhost:2181(CONNECTED) 6] create /zookeeper/demo1 “zhangfei” Created /zookeeper/demo1 [zk: localhost:2181(CONNECTED) 7] get /zookeeper/demo1 zhangfei
- 创建带序号的节点(如果原来没有序号节点,序号从 0 开始依次递增。如果原节点下已有 2 个节点,则再排序时从 2 开始,以此类推)
[zk: localhost:2181(CONNECTED) 14] create -s /zookeeper “xuhao” Created /zookeeper/demo10000000001 [zk: localhost:2181(CONNECTED) 17] ls /zookeeper [config, demo1, demo10000000001, quota]
- 创建临时节点不带序号(关闭连接后节点消失)
[zk: localhost:2181(CONNECTED) 18] create -e /zookeeper/demo2 “no” Created /zookeeper/demo2 [zk: localhost:2181(CONNECTED) 19] ls /zookeeper [config, demo1, demo10000000001, demo2, quota]
- 创建临时带序号节点(关闭连接后节点消失)
[zk: localhost:2181(CONNECTED) 2] create -e -s /zookeeper/demo “11” Created /zookeeper/demo0000000003 [zk: localhost:2181(CONNECTED) 4] ls /zookeeper [config, demo0000000003, demo1, demo10000000001, quota]
5. 修改节点数据
[zk: localhost:2181(CONNECTED) 8] set /zookeeper/demo1 “xishi” [zk: localhost:2181(CONNECTED) 9] get /zookeeper/demo1 xishi
6. 节点数值变化监听
1. 在主机hadoop104上注册监听/zookeeper/demo1 节点数据变化
[zk: localhost:2181(CONNECTED) 5] get -w /zookeeper/demo1 xishi
2. 在hadoop103上修改/sanguo 节点的数据
[zk: localhost:2181(CONNECTED) 1] set /zookeeper/demo1 “666”
3. 观察 hadoop104 主机收到数据变化的监听
[zk: localhost:2181(CONNECTED) 6] WATCHER:: WatchedEvent state:SyncConnected type:NodeDataChanged path:/zookeeper/demo1
注意:在hadoop103再多次修改/sanguo的值,hadoop104上不会再收到监听。因为注册
一次,只能监听一次。想再次监听,需要再次注册。
7. 节点的子节点变化监听
1. 在 hadoop104 主机上注册监听/sanguo 节点的子节点变化
[zk: localhost:2181(CONNECTED) 1] ls -w /sanguo [shuguo, weiguo]
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
注意:节点的路径变化,也是注册一次,生效一次。想多次生效,就需要多次注册。
8. 删除节点
[zk: localhost:2181(CONNECTED) 10] delete /zookeeper/demo0000000003 [zk: localhost:2181(CONNECTED) 11] delete /zookeeper/demo1Node not empty: /zookeeper/demo1 [zk: localhost:2181(CONNECTED) 12] deleteall /zookeeper/demo1
<a name="2e0a439f"></a>
## 9 监听器原理
客户端在注册监听它关心的节点,当目录下节点数据发生改变时(数据改变、节点删除/增加、子目录节点删除/增加),zookeeper会通知客户端。监听机制保证zookeeper保存的任何数据改变都能快速的响应到监听该节点的应用程序<br />
<a name="cb5ad9b8"></a>
## 10 java客户端 API操作
- 创建pom项目
- 引入依赖
```java
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</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.7.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
- 编写log4j配置文件
要在项目的 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
- 创建主启动类(Mian_demo1)
- 连接
public void init() throws IOException { String url= "192.168.1.19:2181"; int sessionTimeout = 200000; zooKeeper = new ZooKeeper(url, sessionTimeout, new Watcher() { @Override public void process(WatchedEvent watchedEvent) { System.out.println("Watcher"); } }); }
- 连接
- 创建节点
public void creatNode() throws KeeperException, InterruptedException { // 参数 1:要创建的节点的路径; 参数 2:节点数据 ; 参数 3:节点权限 ;参数 4:节点的类型 final String s = zooKeeper.create("/java1", "allen".getBytes(StandardCharsets.UTF_8), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL); System.out.println(s); }
获取节点数值并检测节点变化 ``` // 获取节点数据并观测数据(只能监测一次)
@Test public void getNodeAndWath() throws KeeperException, InterruptedException { final Watcher watcher = new Watcher() {
@Override public void process(WatchedEvent event) { System.out.println(event.toString()); }}; // 一次性监听 数据改变一次后就不在监听 final byte[] data = zooKeeper.getData(“/java”, watcher, new Stat()); String s = new String(data); System.out.println(s); Thread.sleep(Long.MAX_VALUE); }
// 获取节点数据并观测数据(监测多次)
// 1. 改造连接 zookeeper函数 @Before public void init() throws IOException { String url= “192.168.1.19:2181”; int sessionTimeout = 200000; zooKeeper = new ZooKeeper(url, sessionTimeout, new Watcher() { @Override public void process(WatchedEvent watchedEvent) { System.out.println(“Watcher”);
byte[] data =null;
try {
data = zooKeeper.getData("/java", true, new Stat());
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
String s = new String(data);
System.out.println(s);
}
});
}
// 2. 使用连接函数中的检测 @Test public void getNodeAndWath() throws KeeperException, InterruptedException { final Watcher watcher = new Watcher() { @Override public void process(WatchedEvent event) { System.out.println(event.toString()); } }; // 永久性监听 使用init()函数中的监听 ,执行完毕之后再次进行监听 final byte[] data = zooKeeper.getData(“/java”, true, new Stat()); String s = new String(data); System.out.println(s); Thread.sleep(Long.MAX_VALUE); }
4. 判断节点是否存在
@Test
public void existNode() throws KeeperException, InterruptedException {
final Stat exists = zooKeeper.exists("/java", false);
System.out.println(exists);
final Stat exist2 = zooKeeper.exists("/java/dddd", false);
System.out.println(exist2);
}
5. 获取某节点下的子节点,并持续监听
@Before
public void init() throws IOException {
String url= "192.168.1.19:2181";
int sessionTimeout = 200000;
zooKeeper = new ZooKeeper(url, sessionTimeout, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
System.out.println("Watcher");
List<String> childrens = null;
try {
childrens = zooKeeper.getChildren("/", true);
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(childrens);
}
});
}
@Test
public void getPathNode() throws KeeperException, InterruptedException {
final List
11 写请求原理


12 分布式锁
- 概念
什么叫做分布式锁呢?保持独占,这样其他进程就无法访问该资源,”进程 1”用完该资源以后就将锁释放掉,让其他进程来获得锁,那么通过这个锁机制,我们就能保证了分布式系统中多个进程能够有序的访问该临界资源。那么我们把这个分布式环境下的这个锁叫作分布式锁。比如说”进程 1”在使用该资源的时候,会先去获得锁,”进程 1”获得锁以后会对该资源
13 面试真题
- 选举机制
半数机制,超过半数的投票通过,即通过。- 第一次启动选举规则:
投票过半数时,服务器 id 大的胜出 - 第二次启动选举规则:
①EPOCH 大的直接胜出
②EPOCH 相同,事务 id 大的胜出
③事务 id 相同,服务器 id 大的胜出
- 第一次启动选举规则:
- 生产集群安装多少 zk 合适?
安装奇数台 ,生产经验:- 10 台服务器:3 台 zk;
- 20 台服务器:5 台 zk;
- 100 台服务器:11 台 zk;
- 200 台服务器:11 台 zk
