在了解Zookeeper之前,首先需要了解在分布式系统(distributed system)中的基本定理:CAP定理 定义:CAP定理指的是在一个分布式系统中,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可兼得。CAP定理的命名就是这三个指标的首字母。
Partition tolerance 指的是在分布式系统中,由于不同的服务器之间可能无法通讯,所以需要一定的容错机制,默认情况下认为 Partition tolerance总是成立。
Consistency 指的是在分布式系统中,不同的服务器上所存储的数据需要一致,可以理解成当服务器A执行操作数据的指令后,服务器B上也要应用同样的操作以保证其所提供的数据同A中的一致。
Availability 指的是分布式系统中,每当服务端收到客户端的请求,服务端都必须给出回应。
为什么说这三者不能同时满足呢,其主要原因在于Consistency 和 Availability不可能同时成立。 假如要保证分布式系统的高数据一致性,则服务端之间一定要在同步后才能开放给客户端进行新的读写操作。即通过加锁同步操作使其可以被看成是一个原子的操作,而在锁定期间,服务端是无法提供服务的,这样服务端是无法做到高可用的,也就违背了Availability。 假如要保证分布式系统的高可用性,则服务端必须无时无刻给客户端提供服务。而服务端间数据同步的操作由于受到网络等因素的影响,无法实时的进行同步数据,假如服务器A上的数据进行了修改而尚未同步到服务器B上,所以此时服务器B所提供的数据就不是最新的,因而违反了Consistency 。
ZooKeeper是一个分布式的、开放源码的分布式协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。由于Hadoop生态系统中很多项目都依赖于zookeeper,如Pig,Hive等, 似乎很像一个动物园管理员,于是取名为Zookeeper。 Zookeeper官网地址为http://zookeeper.apache.org/。
Zookeeper的每个ZNode上都会存储数据,对应到每个ZNode,Zookeeper都会为其维护一个叫做Stat的数据结构,Stat中记录的内容如下:
Watcher(事件监听器)是 Zookeeper提供的一种 发布/订阅的机制。Zookeeper允许用户在指定节点上注册一些 Watcher,并且在一些特定事件触发的时候,Zookeeper服务端会将事件通知给订阅的客户端。该机制是 Zookeeper实现分布式协调的重要特性。
zookeeper会为每个客户端分配一个session,类似于web服务器一样,用来标识客户端的身份。
在Zookeeper中,node的ACL是没有继承关系的。ACL表现形式:scheme:id:permissions。
ZAB 是 ZooKeeper Atomic Broadcast (ZooKeeper 原子广播协议)的缩写,它是特别为 ZooKeeper 设计的崩溃可恢复的原子消息广播算法。ZooKeeper 使用 Leader来接收并处理所有事务请求,并采用 ZAB 协议,将服务器数据的状态变更以事务 Proposal 的形式广播到所有的 Follower 服务器上去。这种主备模型架构保证了同一时刻集群中只有一个服务器广播服务器的状态变更,因此能够很好的保证事物的完整性和顺序性。 Zab协议有两种模式,它们分别是恢复模式(recovery)和广播模式(broadcast)。当服务启动或者在leader崩溃后,Zab就进入了恢复模式,当leader被选举出来,且大多数follower完成了和leader的状态同步以后, 恢复模式就结束了,ZAB开始进入广播模式。
当Leader崩溃或者Leader失去大多数的Follower时,Zookeeper处于恢复模式,在恢复模式下需要重新选举出一个新的Leader,让所有的 Server都恢复到一个正确的状态。Zookeeper的选举算法有两种:一种是基于basic paxos实现的,另外一种是基于fast paxos算法实现的。系统默认的选举算法为fast paxos。
Basic paxos:当前Server发起选举的线程,向所有Server发起询问,选举线程收到所有回复,计算zxid最大Server,并推荐此为Leader,若此提议获得n/2+1票通过(过半同意),此为Leader,否则重复上述流程,直到Leader选出。
Fast paxos:某Server首先向所有Server提议自己要成为Leader,当其它Server收到提议以后,解决epoch和 zxid的冲突,并接受对方的提议,然后向对方发送接受提议完成的消息,重复这个流程,最后一定能选举出Leader。(即提议方解决其他所有epoch和 zxid的冲突,即为Leader)。
当集群重新选举出Leader后,所有的Follower需要和Leader同步数据,确保集群数据的一致性。
当数据同步完成后,集群开始从恢复模式进入广播模式,开始接受客户端的事物请求。 当只有Leader或少数机器批准执行某个任务时,则极端情况下Leader和这些少量机器挂掉,则无法保证新Leader知道之前已经批准该任务,这样就违反了数据可靠性。所以Leader在批准一个任务之前应该保证集群里大部分的机器知道这个提案,这样即使Leader挂掉,选举出来的新Leader也会从其他Follower处获取这个提案。而如果Leader要求所有Follower都同意才执行提案也不行,此时若有一个机器挂掉,Leader就无法继续工作,这样的话整个集群相当于单节点,无法保证可靠性。
1.安装jdk,并且配置jdk的环境变量
2.去官网下载zookeeper的安装包,上传到linux集群环境下 http://zookeeper.apache.org/
3.解压安装包 tar -zxvf zookeeper-X.X.X.tar.gz
4.进入conf目录,复制zoo-sample.cfg为zoo.cfg,zoo.cfg及为Zookeeper的默认配置文件,我们通过修改zoo.cfg即可配置zookeeper
修改dataDir路径 指定zookeeper将数据保存在哪个目录下,如果不修改,默认在/tmp下,由于该目录下数据可能会被linux自动清理,所以一定要修改该路径
修改服务器列表 单机模式:在zoo.cfg中只配置一个server.id就是单机模式了 伪分布式:在zoo.cfg中配置多个server.id,其中ip都是当前机器,而端口各不相同,这就是伪集群模式 完全分布式:多台机器上各自配置server.id
server.1=xxx.xxx.xxx.xxx:2888:3888
server.2=xxx.xxx.xxx.xxx:2888:3888
server.3=xxx.xxx.xxx.xxx:2888:3888
在dataDir路径下生成myid文件 在dataDir目录下cat一个叫myid的文件,写入你所分配给当前机器的server.id
5.Zookeeper操作指令
和Redis,Mysql等服务类似,访问Zookeeper安装路径下的bin/zkServer.sh
即可完成对服务端的启动,停止等操作,具体参数可通过bin/zkServer.sh --help
查询,以下是常用指令
bin/zkServer.sh start #启动zookeeper服务
bin/zkServer.sh stop #停止zookeeper服务
bin/zkServer.sh restart #重启zookeeper服务
bin/zkServer.sh status #查看服务器状态
注意!搭建在多台服务器上的Zookeeper都需要启动,如果不想一台一台的启动,可以通过编写批量启动的shell脚本通过ssh的方式实现对Zookeeper集群的管理。或者安装CDH等Hadoop 发行版实现对Zookeeper集群的管理
连接zookeeper客户端 bin/zkCli.sh [-server ip:port]
列出节点: ls path [watch]
创建节点: create [-s] [-e] path data acl
获取节点: get path [watch]
更新操作: set path data [version]
删除操作: delete path [version]
批量执行:
zkCli.sh -server localhost:2181 <<EOF
ls /
get /
quit
EOF
分析snapshot文件:
#!/bin/sh
function help(){
echo "-----------------"
echo "HELP: $0 SnapshotFile"
echo "-----------------"
exit 1
}
if [ $# -ne 1 ]
then
help
fi
file=$1
if [ ! -f $file ]
then
echo "ERROR: $file not found"
exit 1
fi
zkDir=/usr/local/zookeeper
JAVA_OPTS="$JAVA_OPTS -Djava.ext.dirs=$zkDir:$zkDir/lib"
java $JAVA_OPTS org.apache.zookeeper.server.SnapshotFormatter "$file"
#!/bin/sh
function help(){
echo "-----------------"
echo "HELP: $0 LogFile"
echo "-----------------"
exit 1
}
if [ $# -ne 1 ]
then
help
fi
LogFile=$1
if [ ! -f $LogFile ]
then
echo "ERROR: $LogFile not found"
exit 1
fi
zkDir=/usr/local/zookeeper
JAVA_OPTS="$JAVA_OPTS -Djava.ext.dirs=$zkDir:$zkDir/lib"
java $JAVA_OPTS org.apache.zookeeper.server.LogFormatter "$LogFile"