目录
1 什么是ZooKeeper
ZooKeeper直译就是动物园管理员, 它是用来管Hadoop(大象)、Hive(蜜蜂)、Pig(小猪)等的管理员(这些都是Apache软件基金组织旗下大数据方面的技术框架), Apache Hbase和Apache Solr的分布式集群都用到了ZooKeeper.
(1) 百度百科中的说明:
ZooKeeper是一个高可用、分布式的程序协调服务, 是Google的Chubby一个开源的实现, 是Hadoop和Hbase的重要组件.
它是一个为分布式应用提供一致性服务的软件, 提供的功能包括: 配置维护、域名服务、分布式同步、组服务等.
ZooKeeper的目标就是封装好复杂易出错的关键服务, 将简单易用的接口和性能高效、功能稳定的系统提供给用户.
(2) ZooKeeper的基本运转流程:
① 选举Leader;
② 同步数据;
③ 选举Leader过程中算法有很多, 但要达到的选举标准是一致的;
④ Leader要具有最高的执行ID, 类似root权限;
⑤ 集群中大多数的机器得到响应并接受选出的Leader.
2 ZooKeeper的功能
2.1 配置管理
项目开发中大多会涉及到各种配置信息, 比如JDBC的连接信息等. 一般将这些信息配置到特定的文件中, 在代码中引入相关配置文件即可.
—— 这是单服务器应用中常用的做法. 当应用很大、配置文件很多, 尤其是在分布式项目中, 多台服务器的配置需要保持一致, 而如果配置信息会被频繁地修改, 这个时候还使用配置文件就不是个好主意了.
—— 你总不能手动逐个修改吧? 不仅重复性劳动太多, 而且出错的可能性更大, 后期维护成本太大.
这种情况下往往需要寻找一种集中管理配置的方法 —— 在这个集中的地方修改了配置, 所有对该配置有依赖的服务都可以获得变更.
需要考虑的是, 由于多台服务器上的项目都依赖了这个配置, 为了应用的可靠运行, 需要这个集中提供配置服务的应用具备非常高的可靠性.
基于上述分析, 我们可以通过集群来提供配置服务, 保证系统的可靠性. 此时遗留的问题是, 如何保证配置在集群中的一致性呢?
为了提供这种一致性, 前辈们提出了一致性协议, 实现此协议的服务就有ZooKeeper —— 它使用Zab这种一致性协议来保证一致性.
应用场景:
○ HBase中, 客户端就是连接一个ZooKeeper, 它获得HBase集群的必要配置信息, 然后才可以进一步操作.
○ 开源消息队列Kafka中, 使用ZooKeeper来维护broker的信息.
○ Alibaba开源的SOA框架Dubbo中广泛使用ZooKeeper管理配置信息, 实现服务治理.
2.2 命名服务
场景: 为了通过网络访问一个系统, 我们需要知道对方的IP地址, 但由于IP地址是一串数字, 难以记忆, 对用户并不友好. 这时人们想出通过域名来访问指定的IP地址.
但计算机并不能识别域名. 为了解决这一问题, 设计者们提出了在每台电脑中都存储一份"域名到IP地址的映射"的方案. 问题又来了, 如果域名对应的IP地址发生了变化, 又该如何映射呢?
前辈们又设计了DNS(Domain Name System, 域名系统). 我们只需要先访问一个所有机器都知道的(known)的节点, DNS通过该节点告诉我们当前访问的域名对应的IP地址是什么. 也就是DNS提供统一的访问接口.
在应用开发中也会存在这类问题, 特别是应用中存在大量服务时, 如果我们将服务的地址保存在本地, 其他用户是不好获取这些地址并访问的. 但是如果我们为用户提供统一的入口, 在本地对各种用户请求作相应的映射处理, 就可以解决此类问题.
2.3 分布式锁
ZooKeeper是一个分布式协调服务, 我们可以利用ZooKeeper来协调多个分布式进程之间的活动.
比如在一个分布式环境中, 为提高系统的可靠性, 集群中的每台服务器都部署了相同的服务.
这些相同的服务都要执行相同的任务, 为了保证数据的一致性, 集群之间就要互相协调, 常规的编程方案解决协调问题是非常复杂繁琐的.
通常的做法是: 使用分布式锁, 在某个时刻只有一个服务在工作, 当这台服务出了问题锁就立即释放, 并 fail over
到其他服务. 这种设计被称作叫Leader Election (leader选举). 比如HBase的Master就采用了这种机制.
注意: 分布式锁与进程锁是有区别的, 使用时要更加谨慎.
2.4 集群管理
在分布式集群应用中, 存在诸如软硬件故障、断电、网络等问题, 存在节点出入现象, 即新节点加入集群, 老节点退出集群. 出现这些情况时, 集群中其他节点要能感知到这种变化, 然后根据这种变化做出对应的决策.
应用场景:
○ 在分布式存储系统中, 有一个中央控制节点负责存储的分配, 有新的存储节点加入进来时, 需要根据集群状态来动态分配存储节点, 这需要实时感知集群的状态.
○ 在分布式SOA架构中, 服务由某一集群提供, 当消费者访问某个服务时, 需要采用某种机制发现集群中有哪些节点可以提供该服务(这也称之为服务发现, 比如Alibaba开源的SOA框架Dubbo就采用了ZooKeeper作为服务发现的底层机制).
○ 开源的消息队列Kafka中, 通过ZooKeeper对Consumer的上下线进行管理.
3 部署ZooKeeper集群
3.1 下载并解压安装包
下载ZooKeeper-3.4.10.tar.gz压缩包,具体复制压缩包至虚拟机流程参照链接:https://www.cnblogs.com/LCharles/p/11244701.html
1 # 下载后, 上传至特定目录, 这里上传至/data/zookeeper下: 2 mkdir -p /data/zookeeper && cd /data/zookeeper 3 # 解压ZooKeeper安装包: 4 tar -zxf zookeeper-3.4.10.tar.gz
3.2 创建data和datalog目录
1 # 进入ZooKeeper安装目录 2 cd zookeeper-3.4.10 3 4 # data为ZooKeeper数据存放目录, datalog为ZooKeeper日志存放目录 5 # 若不指定datalog, 默认与数据存放目录一致 6 mkdir data datalog 7 8 # 赋予当前用户写权限 9 chmod 644 data datalog
3.3 创建myid文件
在data目录下创建myid文件, 文件中只包含一行内容: 该节点对应的server.id的id编号. 如server.1节点中myid文件的内容为1.
1 #创建data文件夹 2 mkdir /data/zookeeper/zookeeper-3.4.10/data 3 #创建myid文件 4 touch /data/zookeeper/zookeeper-3.4.10/data/myid 5 6 # 将编号写入到myid文件中 7 echo 1 > /data/zookeeper/zookeeper-3.4.10/data/myid 8 9 # 查看写入是否成功 10 cat /data/zookeeper/zookeeper-3.4.10/data/myid
3.4 修改配置文件zoo.cfg
(1) 修改过程如下:
1 cd /data/zookeeper/zookeeper-3.4.10/conf 2 3 # 拷贝文件, 重命名为zoo.cfg 4 cp zoo_sample.cfg zoo.cfg 5 6 # 修改zoo.cfg文件: 7 vim zoo.cfg 8 9 # 添加如下内容: 10 dataDir=/data/zookeeper/data 11 dataLogDir=/data/zookeeper/datalog 12 server.1=zookeeper0.com:2888:3888 13 server.2=zookeeper1.com:2888:3888 14 server.3=zookeeper2.com:2888:3888
如下是我的hostname和IP情况:
1 zookeeper0.com:192.168.13.131 2 zookeeper1.com:192.168.13.129 3 zookeeper2.com:192.168.13.130
(2) 配置完成的zoo.cfg文件如下:
1 # 基本事件单元(毫秒), 用来控制心跳和超时. 2 tickTime=2000 3 4 # 集群中有多台Server, 其中一台为Leader, 其余Server为Follower.
# initLimit参数指定Follower连接并同步到Leader的初始化心跳时间(即最长通信时间), 以tickTime的倍数表示, 超过该时间则连接失败. 5 initLimit=5 6 7 # Leader与Follower之间发送消息时, 请求和应答的最大时间, 是tickTime的倍数.
# 如果Follower在设置的时间内不能与Leader建立通信, 此Follower将被丢弃. 8 syncLimit=2 9 10 # 存放ZooKeeper运行时数据的目录, 需要提前建立. 11 dataDir=/data/zookeeper/data 12 13 # log目录, 如果没有设置该参数, 默认使用dataDir的目录, 需要提前建立. 14 # 应当谨慎选择日志目录, 使用专用的日志存储设备能很大程度提高系统的性能. 15 dataLogDir=/data/zookeeper/datalog 16 17 # 监听client连接的端口号. 18 clientPort=2181 19 20 # 设置连接到ZooKeeper的客户端的最大数量(限制并发连接的数量, 它通过IP来区分不同的客户端).
# 此配置选项可以用来阻止某些类别的Dos攻击, 将它设置为0或不设置将会取消对并发连接的限制. 21 maxClientCnxns=0 22 23 # 最小的会话超时时间, 默认为 2 * tickTme 时间 24 minSessionTimeout=4000 25 26 # 最大的会话超时时间默认情况下为 20 倍的会话超时时间 27 maxSessionTimeout=10000 28 29 # 集群中各个节点的信息(server.id=ip:port1:port2) 30 server.1=zookeeper0.com:2888:3888 31 server.2=zookeeper1.com:2888:3888 32 server.3=zookeeper2.com:2888:3888
(3) 关于 server.id=host:port1:port2
的说明:
id 是每个ZooKeeper节点的编号, 保存在dataDir目录下的myid文件中;
zoo1~zoo3表示各个ZooKeeper节点的hostname或IP地址, 映射关系在系统文件
/etc/hosts
中设置;port1指定该Server与集群中的Leader通信所使用的端口;
port2指定集群选举Leader时所用的端口.
(4) 常见错误说明:
○ clientPort 不能与port1、port2相同, 否则集群将启动不了.
○ 若采用伪分布式配置方式(即在一台服务器上模拟配置集群), 则各个Server的port1与port2不能相同.
○ 如果采用伪分布式配置方式, dataDir与dataLogDir也需要作不同的配置.
3.5 部署其他节点上的服务
我有使用scp命令进行虚拟机间的复制操作,而是使用上面的方法。实际就是按照3.1-3.4的步骤重新配置一遍各个节点。
# 拷贝ZooKeeper文件夹到其他服务器(zoo2和zoo3) --- 需要确保相应的路径/data/zookeeper存在: scp -r /data/zookeeper zookeeper1.com:/data/ scp -r /data/zookeeper zookeeper2.com:/data/ # 分别在zoo2和zoo3服务器上修改ZooKeeper的myid: echo 2 > /data/zookeeper/zookeeper-3.4.10/data/myid echo 3 > /data/zookeeper/zookeeper-3.4.10/data/myid #分别设置监听client的端口号 [root@zookeeper1 bin]# vim /data/zookeeper/zookeeper-3.4.10/conf/zoo.cfg clientPort=2182 [root@zookeeper2 bin]# vim /data/zookeeper/zookeeper-3.4.10/conf/zoo.cfg clientPort=2183
同时修改各个节点的zoo.cfg配置文件
1 [admin@zookeeper1 ~]$ cd /data/zookeeper-3.4.10/conf 2 [root@zookeeper1 conf]# cp zoo_sample.cfg zoo.cfg 3 [root@zookeeper1 conf]# vim zoo.cfg
4 启动ZooKeeper集群
4.1 关闭防火墙
ZooKeeper客户端使用2181端口号, 为了能对外正常使用Zookeeper, 需要开放2181端口号,各端口号需要不一样 或者关闭防火墙:
(1) CentOS 7之前系统的命令:
1 # 查看防火墙状态: 2 service iptable status 3 4 # 临时关闭防火墙: 5 service iptables stop 6 7 # 永久关闭防火墙(禁止开机启动): 8 chkconfig iptables off
(2) CentOS 7开始使用systemctl
来管理服务和程序, 包括service
和chkconfig
:
1 # 查看防火墙状态: 2 systemctl status firewalld.service 3 4 # 临时关闭防火墙: 5 systemctl stop firewalld.service 6 7 # 永久关闭防火墙(禁止开机启动): 8 systemctl disable firewalld.service
4.2 启动ZooKeeper集群
(1) 启动步骤:
# 依次进入三台服务器, 执行下述命令: [root@zookeeper1 conf]# cd /data/zookeeper/zookeeper-3.4.10/bin [root@zookeeper1 bin]# ./zkServer.sh start # 查看ZooKeeper运行状态: [root@zookeeper1 bin]# ./zkServer.sh status
(2) 常见错误: 在查看ZooKeeper的状态时, 可能会发现控制台抛出错误:
1 [root@zookeeper0 bin]# ./zkServer.sh status 2 ZooKeeper JMX enabled by default 3 Using config: /data/zookeeper/zookeeper-3.4.10/bin/../conf/zoo.cfg 4 Error contacting service. It is probably not running.
-
错误原因: 这里部署的是集群, 其他服务器尚未启动, 当前节点在根据zoo.cfg中配置的服务列表发起选举Leader的请求, 由于无法与集群中的其他节点进行通信, 所以抛出错误.
-
错误解决: 在启动第二台ZooKeeper服务后, Leader将被选出, 错误就会消失. 因为在ZooKeeper集群中, 如果有2n+1台服务器, 它允许n台服务挂掉而不影响服务.
- 错误原因:可能是ssh连接未建立,可以ping通相应节点ip,但是由于我是vmware tools复制的压缩包,而不是scp命令连接各节点复制压缩包(scp命令会建立ssh连接)
- 错误解决:使用scp复制/data/zookeeper
- 错误原因:监听client连接的端口号冲突
- 错误解决:在zoo.cfg中设置各节点clientport为不同端口号
(3)运行后情况
zookeeper0为follower
zookeeper1位leader
zookeeper2为follwer
4.3 ZooKeeper的常用命令
1 # 启动服务: 2 sh zkServer.sh start 3 4 # 查看服务状态: 5 sh zkServer.sh status 6 7 # 停止服务: 8 sh zkServer.sh stop 9 10 # 重启服务: 11 sh zkServer.sh restart