准备工作:三台机器!初始化本机环境,安装docker等
思路(具体步骤):三台服务器都要
- 登录
harbor
,拉取jdk
镜像,让通过编写脚本启动jdk
容器。 - 进入容器映射的目录,将二进制文件
zookeeper
包放进去,解压,配置相关文件即可。 - 三台服务器都配置完成了之后,启动。一个主节点,两个从节点
- 验证:随意挂掉一个
jdk
镜像,检查zookeeper
的状态选举情况变化。
注意:镜像重启之后,vim /etc/hosts里面内容会丢失,需要写个脚本配置一下。
修改主机名
第一台
[root@localhost zookeeper]# hostnamectl set-hostname zookeeper-01-test
第二台
[root@localhost zookeeper]# hostnamectl set-hostname zookeeper-02-test
[root@localhost zookeeper]# hostname -f
zookeeper-02-test
第二台
[root@localhost zookeeper]# hostnamectl set-hostname zookeeper-03-test
vim /etc/hosts # 配置host
第一台
vim /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2 jdk1.8 jdk1
10.8.46.190 zookeeper-03-test
10.8.46.197 zookeeper-02-test
0.0.0.0 zookeeper-01-test # 0.0.0.0
第二台
vim /etc/hosts
10.8.46.190 zookeeper-03-test
0.0.0.0 zookeeper-02-test # 0.0.0.0
10.8.46.35 zookeeper-01-test
第三台
vim /etc/hosts
0.0.0.0 zookeeper-03-test # 0.0.0.0
10.8.46.197 zookeeper-02-test
10.8.46.35 zookeeper-01-test
拉取jdk镜像
登录harbor,拉取jdk镜像,让通过编写脚本启动jdk容器。
[root@zookeeper-01-test ~]# docker login 10.249.0.137:80
[root@zookeeper-01-test ~]# docker pull 10.249.0.137:80/base/jdk-1.8:20210202
[root@zookeeper-01-test ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
10.249.0.137:80/base/jdk-1.8 20210202 1d4d64ab1ea2 17 months ago 834MB
启动镜像
编写jdk脚本启动jdk镜像,把zookeeper包放进去
[root@zookeeper-01-test ~]# cd /opt/script/setup/jdk/
[root@zookeeper-01-test jdk]# pwd
/opt/script/setup/jdk
[root@zookeeper-01-test jdk]# ll
总用量 4
-rwxr-xr-x. 1 root root 958 7月 26 15:55 install.sh
[root@zookeeper-01-test jdk]# vim install.sh
#!/bin/bash
#设置容器相关变量
cname="test-jdk-01" # 第二台服务器是:test-jdk-02
name="jdk1.8"
logs="/opt/data/"${cname}"/"
#创建目录
mkdir -p ${logs}
port2="2181"
port3="2888"
port4="3888"
# port3="10051"
#启动容器
echo -e "Start "${cname}" Container"
docker run -d -it -p ${port2}:${port2} -p ${port3}:${port3} -p ${port4}:${port4} --privileged=true --restart=always --name ${cname} --hostname ${name} -v ${logs}:/opt/data 10.249.0.137:80/base/jdk-1.8:20210202
解释说明:
--privileged
:可以有很多权限--name jdk1.8
:容器名字-i
:开启标准输入-it
:合起来实现和容器交互的作用,运行一个交互式会话 shell-d
:后台运行-p
:宿主机与容器映射端口
启动脚本,docker ps查看容器
[root@zookeeper-01-test jdk]# vim install.sh
[root@zookeeper-01-test jdk]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c315b46c828f 10.249.0.137:80/base/jdk-1.8:20210202 "/usr/sbin/sshd -D" 16 hours ago Up 15 hours 0.0.0.0:2181->2181/tcp, 0.0.0.0:2888->2888/tcp, 0.0.0.0:3888->3888/tcp, 22/tcp, 0.0.0.0:8080->8080/tcp test-jdk-01
[root@zookeeper-01-test jdk]#
在/opt目录,把zookeeper二进制包丢进去。
[root@zookeeper-01-test opt]# pwd
/opt
[root@zookeeper-01-test opt]# ll
总用量 22192
drwx--x--x. 4 root root 28 7月 26 10:50 containerd
drwxr-xr-x. 4 root root 43 7月 26 15:35 data
drwxr-xr-x. 3 root root 19 7月 26 10:53 script
-rw-r--r--. 1 root root 22724574 7月 26 14:35 zookeeper-3.4.9.tar.gz
[root@zookeeper-01-test opt]#
进容器里面看docker exec -it test-jdk-01 bash
[root@zookeeper-01-test opt]# docker exec -it test-jdk-01 bash
[root@jdk1 /]# cd /opt/data/
[root@jdk1 data]# ll
total 22192
-rw-r--r--. 1 root root 22724574 7月 26 17:08 zookeeper-3.4.9.tar.gz
[root@jdk1 data]#
解压压缩包
mkdir -p /usr/local/zookeeper
cd /opt
tar -zxvf zookeeper-3.4.9.tar.gz -C /usr/local/zookeeper
编辑配置文件
cd /usr/local/zookeeper/zookeeper-3.4.9/conf
cp zoo_sample.cfg zoo.cfg #将sample配置文件复制为正式的配置文件
vim zoo.cfg #开始编辑
dataDir=/home/zookeeper/data
dataLogDir=/home/zookeeper/logs
server.0=zookeeper-01-test:2888:3888
server.1=zookeeper-02-test:2888:3888
server.2=zookeeper-03-test:2888:3888
(3)创建目录以及要Id文件
mkdir -p /home/zookeeper/data
mkdir -p /home/zookeeper/logs
vim /home/zookeeper/data/myid
#创建myid文件,并编辑它,编辑的内容就是配置文件中server.后面跟着的号数。例如目前是在zookeeper-01-test机器上,则在myid文件中写入0
注意:我这里是用容器里面的,不需要重启,如果是宿主机上的需要重启:reboot
配置zookeeper
主机zookeeper-02-test、zookeeper-03-test进行如下配置
- 在主机第二台zookeeper-02-test 配置myid为1
vi /home/zookeeper/data/myid
#创建myid文件,并编辑它,编辑的内容就是配置文件中server.后面跟着的号数。例如目前是在zookeeper-02-test机器上,则在myid文件中写入1
- 在主机第三台zookeeper-02-test 配置myid为2
vi /home/zookeeper/data/myid
#创建myid文件,并编辑它,编辑的内容就是配置文件中server.后面跟着的号数。例如目前是在zookeeper-03-test机器上,则在myid文件中写入1
验证zookeeper集群
测试验证Zookeeper集群
(1)启动节点(分别在3台主机上执行)
/usr/local/zookeeper/zookeeper-3.4.9/bin/zkServer.sh start
检查运行情况(分别在3台主机上执行)
/usr/local/zookeeper/zookeeper-3.4.9/bin/zkServer.sh status
zookeeper-01-test |
---|
zookeeper-02-test |
zookeeper-03-test |
Zookeeper集群测试验证成功,至此顺利完成Zookeeper集群的搭建。
八股文
ZooKeeper 典型应用场景
ZooKeeper 通常被用于实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能。
- 分布式锁 : 通过创建唯一节点获得分布式锁,当获得锁的一方执行完相关代码或者是挂掉之后就释放锁。
- 命名服务 :可以通过 ZooKeeper 的顺序节点生成全局唯一 ID
- 数据发布/订阅 :通过 Watcher 机制 可以很方便地实现数据发布/订阅。当你将数据发布到 ZooKeeper 被监听的节点上,其他机器可通过监听 ZooKeeper 上节点的变化来实现配置的动态更新。
ZooKeeper和哪些大数据组件一起使用?
- Kafka : ZooKeeper 主要为 Kafka 提供 Broker 和 Topic 的注册以及多个 Partition 的负载均衡等功能。
- Hbase : ZooKeeper 为 Hbase 提供确保整个集群只有一个 Master 以及保存和提供 regionserver 状态信息(是否在线)等功能。
- Hadoop : ZooKeeper 为 Namenode 提供高可用支持。
ZooKeeper 集群为什么是奇数?
ZooKeeper 集群在宕掉几个 ZooKeeper 服务器之后,如果剩下的 ZooKeeper 服务器个数大于宕掉的个数的话整个 ZooKeeper 才依然可用。假如我们的集群中有 n 台 ZooKeeper 服务器,那么也就是剩下的服务数必须大于 n/2。先说一下结论,2n 和 2n-1 的容忍度是一样的,都是 n-1,大家可以先自己仔细想一想,这应该是一个很简单的数学问题了。
比如假如我们有 3 台,那么最大允许宕掉 1 台 ZooKeeper 服务器,如果我们有 4 台的的时候也同样只允许宕掉 1 台。
假如我们有 5 台,那么最大允许宕掉 2 台 ZooKeeper 服务器,如果我们有 6 台的的时候也同样只允许宕掉 2 台。
综上,何必增加那一个不必要的 ZooKeeper 呢?
ZAB 协议介绍
ZAB(ZooKeeper Atomic Broadcast 原子广播) 协议是为分布式协调服务 ZooKeeper 专门设计的一种支持崩溃恢复的原子广播协议。 在 ZooKeeper 中,主要依赖 ZAB 协议来实现分布式数据一致性,基于该协议,ZooKeeper 实现了一种主备模式的系统架构来保持集群中各个副本之间的数据一致性。
ZAB 协议两种基本的模式:崩溃恢复和消息广播
ZAB 协议包括两种基本的模式,分别是
- 崩溃恢复 :当整个服务框架在启动过程中,或是当 Leader 服务器出现网络中断、崩溃退出与重启等异常情况时,ZAB 协议就会进入恢复模式并选举产生新的Leader服务器。当选举产生了新的 Leader 服务器,同时集群中已经有过半的机器与该Leader服务器完成了状态同步之后,ZAB协议就会退出恢复模式。其中,所谓的状态同步是指数据同步,用来保证集群中存在过半的机器能够和Leader服务器的数据状态保持一致。
- 消息广播 :当集群中已经有过半的Follower服务器完成了和Leader服务器的状态同步,那么整个服务框架就可以进入消息广播模式了。 当一台同样遵守ZAB协议的服务器启动后加入到集群中时,如果此时集群中已经存在一个Leader服务器在负责进行消息广播,那么新加入的服务器就会自觉地进入数据恢复模式:找到Leader所在的服务器,并与其进行数据同步,然后一起参与到消息广播流程中去。
注意:镜像重启之后,vim /etc/hosts里面内容会丢失,需要写个脚本配置一下。
快速配置自动加载hosts
怎么做的原因:当你容器重启之后,你的 /etc/hosts还在,不用重新编写。。
在opt目录下创建一个hosts.temp,将hosts写入到hosts.temp
vim /opt/hosts.temp
test-jdk-01
127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 172.17.0.2 jdk1.8 jdk1 10.8.46.190 zookeeper-03-test 10.8.46.197 zookeeper-02-test 0.0.0.0 zookeeper-01-test
创建a.sh脚本
vim /etc/profile.d/a.sh
cat /opt/hosts.temp > /etc/hosts
授权
chmod +x /etc/profile.d/a.sh
这种是通过编写zookeeper脚本启动
test-zk-01/install.sh
#!/bin/bash
#设置容器相关变量
cname="test-zk-01"
logs="/opt/data/"${cname}
port1="2181"
port2="2888"
port3="3888"
#创建目录
echo -e "Create dir "${logs}
mkdir -p ${logs}
#启动容器
echo -e "Start "${cname}" Container"
docker run -d -p ${port1}:${port1} -p ${port2}:${port2} -p ${port3}:${port3} --name ${cname} --hostname ${cname} --privileged=true --restart=always -v ${logs}:/home/zookeeper 10.249.0.137:80/base/zookeeper:v20.06.10
test-zk-02/install.sh
#!/bin/bash
#设置容器相关变量
cname="test-zk-02"
logs="/opt/data/"${cname}
port1="2181"
port2="2888"
port3="3888"
#创建目录
echo -e "Create dir "${logs}
mkdir -p ${logs}
#启动容器
echo -e "Start "${cname}" Container"
docker run -d -p ${port1}:${port1} -p ${port2}:${port2} -p ${port3}:${port3} --name ${cname} --hostname ${cname} --privileged=true --restart=always -v ${logs}:/home/zookeeper 10.249.0.137:80/base/zookeeper:v20.06.10
test-zk-03/install.sh
#!/bin/bash
#设置容器相关变量
cname="test-zk-03"
logs="/opt/data/"${cname}
port1="2181"
port2="2888"
port3="3888"
#创建目录
echo -e "Create dir "${logs}
mkdir -p ${logs}
#启动容器
echo -e "Start "${cname}" Container"
docker run -d -p ${port1}:${port1} -p ${port2}:${port2} -p ${port3}:${port3} --name ${cname} --hostname ${cname} --privileged=true --restart=always -v ${logs}:/home/zookeeper 10.249.0.137:80/base/zookeeper:v20.06.10
八股文
Zookeeper集群节点数量为什么要是奇数个?
在容错能力相同的情况下,奇数台更节省资源。leader选举,要求 可用节点数量 > 总节点数量/2 。
举两个例子:
假如zookeeper集群1 ,有3个节点,3/2=1.5,需要2个节点是正常的。3个节点的zookeeper集群,允许有一个节点宕机。
假如zookeeper集群2,有4个节点,4/2=2 , 需要3个节点是正常的。4个节点的zookeeper集群,允许有一个节点宕机。
集群1与集群2都有 允许1个节点宕机 的容错能力,但是集群2比集群1多了1个节点。在相同容错能力的情况下,本着节约资源的原则,zookeeper集群的节点数在奇数个更好一些。