ZooKeeper 集群部署
- 一、ZooKeeper 简介
- 1.1 什么是 ZooKeeper
- 1.2 ZooKeeper 特点
- 二 ZooKeeper 的架构和设计
- 4.1 ZooKeeper 数据模型
- 4.1.1 Znode 节点特性
- 三、ZooKeeper 的集群安装前准备工作
- 3.1 需要的准备工作
- 3.2 Linux 系统 3 个节点准备
- 3.2.1 克隆
- 3.2.2 配置另外两台服务器的静态IP
- 3.2.3 修改主机名
- 3.3 配置主机名与IP地址映射
- 3.4 配置时钟同步
- 3.5 集群 SSH 免密登录
- 3.5.1 为什么需要 SSH 免密登录
- 3.5.2 配置 节点免密登录
- 3.5.3 配置集群 SSH 免密登录
- 四、ZooKeeper 的集群安装
- 4.1 集群脚本开发
- 4.2 集群脚本配置
- 4.3 ZooKeeper 集群配置
- 4.3.1 ZooKeeper 下载
- 4.3.2 上传解压
- 4.3.3 配置 zookeeper 配置文件 zoo.cfg
- 4.3.4 创建各节点服务编号
- 4.4 启动 ZooKeeper 集群服务
- 五、在配置过程的一些问题总结
- 5.1 启动单个节点zookeeper正常,启动集群失败,并提示如下:
一、ZooKeeper 简介
1.1 什么是 ZooKeeper
- 定义:zookeeper一个分布式的开源的协调服务框架,服务于分布式应用。
-
它暴露了一系列的原语操作服务,因此分布式应用能够基于这些服务,构建出更高级别的服务,比如同步,配置管理,分组和命名服务。
-
zookeeper设计上易于编码,数据模型构建在我们熟悉的树形结构目录风格的文件系统中,
-
zookeeper运行在Java中,同时支持Java和C 语言
-
1.2 ZooKeeper 特点
- 最终一致性
- 客尸端末论连接到哪个 Server,展示给它的都是同一个视图,这是Zookeeper最重要的特点。
- 可靠性
- Zookeeper 具有简单、健壮、良好的性能。如果一条消息被一台服务器接收,那么它将被所有的服务器接收。
- 实时性
- Zookeeper 保证客户端将在一个时间间隔范围内,获得服务器的更新信息或者服务器失效的信息。但由于网络延时等原因
- zookeeper 不能保证两个客户端能同时得到刚更新的数据,如果需要最新数据,应该在读数据之前调用sync()接口。
- 等待无关(wait-free)
- 慢的或者失效的客户端不得干预快速的客户端的请求,这就使得每个客户端都能有效地等待。
- 原子性
- 对zookeeper的更新操作要么成功,要么失败,没有中间状态。
- 顺序性
- 它包括全局有序和偏序两种
- 全局有序是针对服务器端,例如,在一台服务器上,消息A在消息B前发布,那么所有服务器上的消息A都将在消息B前被发布。
- 偏序是针对客户端,例如,在同一个客户端中,消息B在消息A后发布,那么执行的顺序必将是先执行消息A然后在是消息B。所有的更新操作都有严格的偏序关系,更新操作都是串行执行的,这一点是保证ZooKeeper功能正确性的关键。
- 它包括全局有序和偏序两种
二 ZooKeeper 的架构和设计
Zookeeper 服务自身组成一个集群(2n+1个服务节点最多允许n个失效)。Zookeeper 服务有两个角色:一个是主节点(Leader),负责投票的发起和决议,更新系统状态;另一种是从节点(Follower),用于接收客户端请求并向客户端返回结果,在选主过程(即选择主节点的过程)中参与投票。主节点失效后,会在从节点中重新选举新的主节点。
4.1 ZooKeeper 数据模型
zookeeper的数据结构与linux文件系统很类似,与Linux中的文件系统路径不同,Zookeeper中的路径必须是绝对路径,而且每条路径只有唯一的一种表示方式(/app1/p_3)。
4.1.1 Znode 节点特性
-
临时节点
znode节点有两种:临时节点和持久节点。znode的类型在创建时就确定,之后不能修改当创建临时节点的客户端会话结束时,2ookeeper 会将该临时节点删除。而持久节点不依赖与客户端会话,只有当客户端明确要删除该持久节点时才会被真正删除。临时节点不可以有子节点,即使是短暂的子节点。 -
顺序节点
顺序节点是指名称中包含Zookeeper指定顺序号的znode。如果在创建znode的时候设置了顺序标识,那么该znode名称之后就会附加一个值,这个值是由一个单调递增的计数器所添加的,由父节点维护。 -
观察机制
客户端可以在znode上设置watcher,当节点状态发生改变时将会触发watcher所对应的操作当watcher被触发时,ZooKeeper将会向客户端发送且仅发送一条通知,因为watcher只能被触发一次,这样可以减少网络流量。为了能够多次收到通知,客户端需要重新注册所需的watcher
三、ZooKeeper 的集群安装前准备工作
3.1 需要的准备工作
- Linux 系统3 个节点准备
- 配置主机名与IP地址映射
- 配置时钟同步
- 集群SSH密码登录
- JDK安装
目标配置如下三台服务器:
服务器序号 | IP | 主机名称 |
---|---|---|
1 | 192.168.220.151 | hadoop1 |
2 | 192.168.220.152 | hadoop2 |
2 | 192.168.220.153 | hadoop3 |
3.2 Linux 系统 3 个节点准备
3.2.1 克隆
使用MVware 的克隆功能,克隆出另外两台 Hadoop 服务器
选择克隆完整版
3.2.2 配置另外两台服务器的静态IP
登录服务后,修改服务器网络配置:
[root@hadoop1 ~]# vim /etc/sysconfig/network-scripts/ifcfg-ens33
修改 IP 地址即可,其他不变
3.2.3 修改主机名
[root@hadoop1 ~]# vim /etc/hostname
第二台服务器主机名:hadoop2 ,第三台服务器主机名:hadoop3
3.3 配置主机名与IP地址映射
三台服务器都需要配置主机名与IP地址映射
[root@hadoop1 ~]# vim /etc/hosts
添加如下内容:
192.168.220.151 hadoop1
192.168.220.152 hadoop2
192.168.220.153 hadoop3
三台服务器可以通过主机名相互访问
3.4 配置时钟同步
Hadoop 集群对节点的时间同步要求比较高,要求各个节点的系统时间不能相差太多,否则会造成很多问题,比如,最常见的连接超时问题。所以需要集群节点的系统时间与互联网的时间保持同步,但是在实际生产环境中,集群中大部分节点是不能连接外网的,这时候可以在内网搭建一个自己的时钟服务器(比如 NTP 服务器),然后让 Hadoop 集群的各个节点与这时钟服务器的时间保持同步
此处我选择 hadoop1 作为时钟服务器(大家随意)
- 查看时间类型
[root@hadoop1 ~]# date
CST 为上海时间,如果是 HKT,表示香港时间,可以通过如下操作进行调整
[root@hadoop1 ~]# cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
注意:检测所有服务器的时间类型,保证都是上海时间
-
配置 NTP 服务器
-
检测 NTP 服务是否安装
# 检测是否安装 ntp
[root@hadoop1 ~]# rpm -qa | grep ntp
# 如果没有安装,进行安装
[root@hadoop1 ~]# yum install -y ntp
安装成功
- 修改配置文件 ntp.conf
[root@hadoop1 ~]# vim /etc/ntp.conf
#启用 restrict 限定该机器网段,192.168.220.151为当前节点的IP地址
restrict 192.168.220.151 mask 255.255.255.0 nomodify notrap
#注释掉 server 域名配置
#server 0.centos.pool.ntp.org iburst
#server 1.centos.pool.ntp org iburst
#server 2.centos.pool.ntp,org iburst
#server 3.centos.pool.ntp.org iburst
#添加如下两行配置,让本机和本地硬件时间同步
server 127.127.1.0
fudge 127.127.1.0 stratum 10
- 启动 ntp 服务器
执行 chkconfi&npdon 命令,可以保证每次机器启动时,NTP 服务都会自动启动,具体操作
如下所示。
[root@hadoop1 ~]# chkconfig ntpd on
查看ntpd 服务状态
# 查看ntpd 服务状态
[root@hadoop1 ~]# sudo systemctl status ntpd
# 如果ntpd 服务没有启动执行如下脚本
[root@hadoop1 ~]# sudo systemctl start ntpd
- 配置其他节点定时同步时间
hadoop2和 hadoop3 节点通过 Linux crontab 命令,可以定时同步 hadoop1 节点的系统时
间,具体操作如下所示。
[root@hadoop1 ~]# crontab -e
添加如下内容:
# 表示每过10分钟进行一次时钟同步
0-59/10 * * * * /usr/sbin/ntpdate hadoop1
查看 ntp 服务是否启用成功
[root@hadoop2 hadoop]# timedatectl
**备注**
:hadoop02 和 hadoop03 节点也需要使用 yum install -yn,命令安装 NTP 服务,才能使用 npdate 时间同步命令。
3.5 集群 SSH 免密登录
3.5.1 为什么需要 SSH 免密登录
SSH(Secure shell)是可以在应用程序中提供安全通信的一个协议,通过 SSH 可以安全地进行网络数据传输,它的主要原理就是利用非对称加密体系,对所有待传输的数据进行加密,保证数据在传输时不被恶意破坏、泄露或者篡改。
但是 Hadoop集群使用 SSH不是用来进行数据传输的,而是在 Hadoop集群启动和停止的时候,主节点需要通过 SSH 协议启动或停止从节点上面的进程。如果不配置SSH 免密登录,对 Hadoop 集群的正常使用没有任何影响,但是在启动和停止 Hadoop 集群的时候,需要输入每个从节点的密码。可以想象一下,当集群规模比较大的时候,比如达到成百上千节点的规模,如果每次都要分别输入集群节点的密码,这种方法肯定是不可职的,所以要对 Hadoop集群进行 sSH 免密登录的配置。
3.5.2 配置 节点免密登录
SSH 免密登录的功能跟用户密切相关,为哪个用户配置了SSH,那个用户就具有 SSH免密登录的功能,没有配置的用户则不具备该功能,这里选择为 hadegp用户配置 SSH免密登录。首先在控制台,使用su命令切换到 root用户的根目录,然后使用ssh-keygen -t rsa 命令(ssh.keysen是秘钥生成器,-t是一个参数,rsa 是一种加密算法)生成秘钥对(即公钥文件id .rsa.pub 和私钥文件 id.rsa)。
先配置 hadoop1 节点免密登录,然后其他两个节点按照相同的方法处理
# 删除.ssh文件
[root@hadoop1 ~]# rm -rf .ssh/*
# 生成密钥
[root@hadoop1 ~]# ssh-keygen -t rsa
# 拷贝公钥 id_rsa.pub 到 authrized_keys
[root@hadoop1 ~]# cp .ssh/id_rsa.pub .ssh/authorized_keys
# 给 .ssh/ 授权
[root@hadoop1 ~]# chmod 700 .ssh
[root@hadoop1 ~]# chmod 600 .ssh/*
`备注`:给 hadoop2 和 hadoop3 也按照上面的处理
3.5.3 配置集群 SSH 免密登录
- 为了实现集群节点之间SSH免密登录,我们还需要将hadoop2和 hadoop3的公钥id_ras.pub复制到 hadoop1中的 authorized keys 文件中,具体操作命令如下所示:
# 在 hadoop2 中将 id_ras.pub 内容拷贝到 hadoop1 的 authorized_keys
[root@hadoop2 ~]# cat ~/.ssh/id_rsa.pub | ssh root@hadoop1 'cat >> ~/.ssh/authorized_keys'
# 在 hadoop3 中将 id_ras.pub 内容拷贝到 hadoop1 的 authorized_keys
[root@hadoop3 ~]# cat ~/.ssh/id_rsa.pub | ssh root@hadoop1 'cat >> ~/.ssh/authorized_keys'
查看 hadoop1 的 authorized_keys
- 然后将hadoop1中的authorized keys文件分发到hadoop2和hadoop3节点,具体操作如下所示:
# hadoop1中的authorized_keys文件分发到hadoop2
[root@hadoop1 ~]# scp -r /root/.ssh/authorized_keys root@hadoop2:/root/.ssh/
# hadoop1中的authorized keys文件分发到hadoop3
[root@hadoop1 ~]# scp -r /root/.ssh/authorized_keys root@hadoop3:/root/.ssh/
查看 hadoop2或hadoop3 的 authorized_keys
四、ZooKeeper 的集群安装
4.1 集群脚本开发
集群脚本用于提升效率,一个脚本可以管理全部集群服务器,从而避免到每一台服务器上去执行脚本
一共涉及3个脚本:deploy.conf、deploy.sh、runRemoteCmd.sh,
deploy.conf:配置文档,用于规划集群,集群信息添加到此文件,统一进行管理
deploy.sh:分发脚本,用于在集群中 批量拷贝或推送文件
runRemoteCmd.sh:分发命令脚本,用于在集群中 批量执行命令
脚本内容分别如下
- deploy.conf
#规划集群角色
hadoop1,master,all,
hadoop2,slave,all,
hadoop3,slave,all,
- deploy.sh
#!/bin/bash
if [ $# -lt 3 ]
then
echo "Usage: ./deploy.sh srcFile(or Dir) descFile(or Dir) MachineTag"
echo "Usage: ./deploy.sh srcFile(or Dir) descFile(or Dir) MachineTag confFile"
exit
fi
src=$1
dest=$2
tag=$3
if [ 'a'$4'a' == 'aa' ]
then
# 此处写自己存放 deploy.conf 位置
confFile=/root/tools/deploy.conf
else
confFile=$4
fi
if [ -f $confFile ]
then
if [ -f $src ]
then
for server in `cat $confFile | grep -v '^#'|grep ','$tag','|awk -F',' '{print $1}'`
do
scp $src $server":"${dest}
done
elif [ -d $src ]
then
for server in `cat $confFile | grep -v '^#'|grep ','$tag','|awk -F',' '{print $1}'`
do
scp -r $src $server":"${dest}
done
else
echo "Error: No source file exist"
fi
else
echo "Error: Please assign config file or run deploy.sh command with deploy.conf in same directory"
fi
- runRemoteCmd.sh
#!/bin/bash
if [ $# -lt 2 ]
then
echo "Usage: ./runRemoteCmd.sh Command MachineTag"
echo "Usage: ./runRemoteCmd.sh Command MachineTag confFile"
exit
fi
cmd=$1
tag=$2
if [ 'a'$3'a' == 'aa' ]
then
# 此处写自己存放 deploy.conf 位置
confFile=/root/tools/deploy.conf
else
confFile=$3
fi
if [ -f $confFile ]
then
for server in `cat $confFile | grep -v '^#'|grep ','$tag','|awk -F',' '{print $1}'`
do
echo "*******************$server***********************"
ssh $server "source /etc/profile; $cmd"
done
else
echo "Error: Please assign config file or run deploy.sh command with deploy.conf in same directory"
fi
注意
:confFile按照你存放 deploy.conf 文件路径配置,其他基本可以不用调整
4.2 集群脚本配置
这里,我将以上脚本放到 hadoop1服务器,位置如下:
- 给 deploy.sh、runRemoteCmd.sh 分配执行权限
[root@hadoop1 tools]# chmod u+x deploy.sh runRemoteCmd.sh
- 将脚本配置到环境变量中,方便在任意路径可以使用
[root@hadoop1 tools]# vim /etc/profile
最下面添加如下内容:
# 添加hadoop集群管理 tools 脚本变量
PATH=/root/tools/:$PATH
- 记得更新缓存
[root@hadoop1 tools]# source /etc/profile
- 集群脚本测试
a. 先测试文件分发
# 随便创建一个 words.log 文本
[root@hadoop1 ~]# vim words.log
# 使用 deploy.sh 脚本分发 到 规划集群角色 为slave的节点中(我这也就是 hadoop2 hadoop3)
[root@hadoop1 ~]# deploy.sh words.log /root/ slave
查看 hadoop2 或 hadoop3 的 是否有words.log文件
b. 测试批量脚本执行
# 批量查看 hadoop1 hadoop2 hadoop3 运行的 java 进程
[root@hadoop1 hadoop]# runRemoteCmd.sh "jps" all
至此,是不是很方便
4.3 ZooKeeper 集群配置
4.3.1 ZooKeeper 下载
ZooKeeper下载地址:https://archive.apache.org/dist/zookeeper/
这里我使用的是 3.8.4
4.3.2 上传解压
使用xshell 上传到 /root 目录,解压到
# 解压到/root
[root@hadoop1 ~]# tar -zxvf /root/apache-zookeeper-3.8.4-bin.tar.gz
# 移动到 /usr/local 目录
[root@hadoop1 ~]# mv apache-zookeeper-3.8.4-bin /usr/local/zookeeper-3.8.4
# 给 zookeeper-3.8.4 创建软连接
[root@hadoop1 local]# ln -s zookeeper-3.8.4/ zookeeper
4.3.3 配置 zookeeper 配置文件 zoo.cfg
- 拷贝
# 进入配置文件目录
[root@hadoop1 conf ] cd /usr/local/zookeeper/conf
# 拷贝 模板 zoo_sample.cfg 为 zoo.cfg
[root@hadoop1 conf]# cp zoo_sample.cfg zoo.cfg
# 进入修改配置文件
[root@hadoop1 conf]# vim zoo.cfg
- 需要修改内容:
- 数据目录调整,需要提取创建
dataDir=/usr/local/data/zookeeper/zkdata - 日志目录调整,需要提取创建
dataLogDir=/usr/local/data/zookeeper/zkdatalog - 访问端口号
clientPort=2181 - server. 每个节点服务编号=服务器ip地址(或主机名):集群通信端口:选举端口
server.1=hadoop1:2888.3888
server.2=hadoop2:2888.3888
server.3=hadoop3:2888.3888
- 数据目录调整,需要提取创建
备注
:如果有四台zookeeper的话,由于非observer节点数必须为奇数个
- 所以如果有第四台的话,可以使用如下添加方式:
- server.4=xx.xx.xx.xx:2888:3888:observer
- id是自己定义的,0~255间,不必一次递增,自己定即可,id表示该节点所持有的投票编号id,必需保证全局唯一
- 不要在配置后面加注释#,这会导致cfg文件解析失败!从而导致zookeeper无法正常启动!
- 将 /usr/local/zookeeper-3.8.4 修改后的文件批量分发给 hadoop2 和 hadoop3
[root@hadoop1 local]# deploy.sh zookeeper-3.8.4 /usr/local/ slave
4.3.4 创建各节点服务编号
分别在 Zookeeper 集群各个节点,进入/usr/local/zookeeper/data/zkdata目录,创建文件 myid,然后分别输入服务编号,具体操作如下所示:
# hadoop1 节点
[root@hadoop1 zkdata]# touch /usr/local/zookeeper/data/zkdata/myid
[root@hadoop1 zkdata]# echo 1 > myid
# hadoop2 节点
[root@hadoop1 zkdata]# touch /usr/local/zookeeper/data/zkdata/myid
[root@hadoop1 zkdata]# echo 2 > myid
# hadoop3 节点
[root@hadoop1 zkdata]# touch /usr/local/zookeeper/data/zkdata/myid
[root@hadoop1 zkdata]# echo 3 > myid
4.4 启动 ZooKeeper 集群服务
在集群各个节点分别进入zookeeper安装目录,然后使用如下命令启动 Zookeeper 服务。
# 批量启动 ZooKeeper 集群服务
[root@hadoop1 zkdata]# runRemoteCmd.sh "/usr/local/zookeeper/bin/zkServer.sh start" all
# 批量查看 ZooKeeper 集群服务状态
[root@hadoop1 zookeeper]# runRemoteCmd.sh "/usr/local/zookeeper/bin/zkServer.sh status" all
五、在配置过程的一些问题总结
5.1 启动单个节点zookeeper正常,启动集群失败,并提示如下:
此报错提示,我也被卡住很久,网上找了各种办法都不行,后面发现把配置文件 zoo.cfg的 三个主机名分别更换位相应的IP地址,集群启动正常
然后就验证了配置没有问题,就是三台服务器之间的相互访问问题,然后使用命令 ssh hadpoopX (X 代表另外两条服务器编号) 分别到三台服务器相互访问,当出现提示,全部输入 yes ,让后再把 配置文件 zoo.cfg 改为对应主机名称就正常了
也就是刚配置好的服务器,要让他们之间互相允许访问