分类: ZooKeeper

ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services.

  • Zookeeper全解析——Paxos作为灵魂

    原计划在介绍完ZK Client之后就着手ZK Server的介绍,但是发现ZK Server所包含的内容实在太多,并不是简简单单一篇Blog就能搞定的。于是决定从基础搞起比较好。

    那么ZK Server最基础的东西是什么呢?我想应该是Paxos了。所以本文会介绍Paxos以及它在ZK Server中对应的实现。

    先说Paxos,它是一个基于消息传递的一致性算法,Leslie Lamport在1990年提出,近几年被广泛应用于分布式计算中,Google的Chubby,Apache的Zookeeper都是基于它的理论来实现的,Paxos还被认为是到目前为止唯一的分布式一致性算法,其它的算法都是Paxos的改进或简化。有个问题要提一下,Paxos有一个前提:没有拜占庭将军问题。就是说Paxos只有在一个可信的计算环境中才能成立,这个环境是不会被入侵所破坏的。

    关于Paxos的具体描述可以在Wiki中找到:http://zh.wikipedia.org/zh-cn/Paxos算法。网上关于Paxos分析的文章也很多。这里希望用最简单的方式加以描述并建立起Paxos和ZK Server的对应关系。

    Paxos描述了这样一个场景,有一个叫做Paxos的小岛(Island)上面住了一批居民,岛上面所有的事情由一些特殊的人决定,他们叫做议员(Senator)。议员的总数(Senator Count)是确定的,不能更改。岛上每次环境事务的变更都需要通过一个提议(Proposal),每个提议都有一个编号(PID),这个编号是一直增长的,不能倒退。每个提议都需要超过半数((Senator Count)/2 +1)的议员同意才能生效。每个议员只会同意大于当前编号的提议,包括已生效的和未生效的。如果议员收到小于等于当前编号的提议,他会拒绝,并告知对方:你的提议已经有人提过了。这里的当前编号是每个议员在自己记事本上面记录的编号,他不断更新这个编号。整个议会不能保证所有议员记事本上的编号总是相同的。现在议会有一个目标:保证所有的议员对于提议都能达成一致的看法。

    好,现在议会开始运作,所有议员一开始记事本上面记录的编号都是0。有一个议员发了一个提议:将电费设定为1元/度。他首先看了一下记事本,嗯,当前提议编号是0,那么我的这个提议的编号就是1,于是他给所有议员发消息:1号提议,设定电费1元/度。其他议员收到消息以后查了一下记事本,哦,当前提议编号是0,这个提议可接受,于是他记录下这个提议并回复:我接受你的1号提议,同时他在记事本上记录:当前提议编号为1。发起提议的议员收到了超过半数的回复,立即给所有人发通知:1号提议生效!收到的议员会修改他的记事本,将1好提议由记录改成正式的法令,当有人问他电费为多少时,他会查看法令并告诉对方:1元/度。

    现在看冲突的解决:假设总共有三个议员S1-S3,S1和S2同时发起了一个提议:1号提议,设定电费。S1想设为1元/度, S2想设为2元/度。结果S3先收到了S1的提议,于是他做了和前面同样的操作。紧接着他又收到了S2的提议,结果他一查记事本,咦,这个提议的编号小于等于我的当前编号1,于是他拒绝了这个提议:对不起,这个提议先前提过了。于是S2的提议被拒绝,S1正式发布了提议: 1号提议生效。S2向S1或者S3打听并更新了1号法令的内容,然后他可以选择继续发起2号提议。

    好,我觉得Paxos的精华就这么多内容。现在让我们来对号入座,看看在ZK Server里面Paxos是如何得以贯彻实施的。

    小岛(Island)——ZK Server Cluster

    议员(Senator)——ZK Server

    提议(Proposal)——ZNode Change(Create/Delete/SetData…)

    提议编号(PID)——Zxid(ZooKeeper Transaction Id)

    正式法令——所有ZNode及其数据

    貌似关键的概念都能一一对应上,但是等一下,Paxos岛上的议员应该是人人平等的吧,而ZK Server好像有一个Leader的概念。没错,其实Leader的概念也应该属于Paxos范畴的。如果议员人人平等,在某种情况下会由于提议的冲突而产生一个“活锁”(所谓活锁我的理解是大家都没有死,都在动,但是一直解决不了冲突问题)。Paxos的作者Lamport在他的文章”The Part-Time Parliament“中阐述了这个问题并给出了解决方案——在所有议员中设立一个总统,只有总统有权发出提议,如果议员有自己的提议,必须发给总统并由总统来提出。好,我们又多了一个角色:总统。

    总统——ZK Server Leader

    又一个问题产生了,总统怎么选出来的?oh, my god! It’s a long story. 在淘宝核心系统团队的Blog上面有一篇文章是介绍如何选出总统的,有兴趣的可以去看看:http://rdc.taobao.com/blog/cs/?p=162

    现在我们假设总统已经选好了,下面看看ZK Server是怎么实施的。

    情况一:

    屁民甲(Client)到某个议员(ZK Server)那里询问(Get)某条法令的情况(ZNode的数据),议员毫不犹豫的拿出他的记事本(local storage),查阅法令并告诉他结果,同时声明:我的数据不一定是最新的。你想要最新的数据?没问题,等着,等我找总统Sync一下再告诉你。

    情况二:

    屁民乙(Client)到某个议员(ZK Server)那里要求政府归还欠他的一万元钱,议员让他在办公室等着,自己将问题反映给了总统,总统询问所有议员的意见,多数议员表示欠屁民的钱一定要还,于是总统发表声明,从国库中拿出一万元还债,国库总资产由100万变成99万。屁民乙拿到钱回去了(Client函数返回)。

    情况三:

    总统突然挂了,议员接二连三的发现联系不上总统,于是各自发表声明,推选新的总统,总统大选期间政府停业,拒绝屁民的请求。

    呵呵,到此为止吧,当然还有很多其他的情况,但这些情况总是能在Paxos的算法中找到原型并加以解决。这也正是我们认为Paxos是Zookeeper的灵魂的原因。当然ZK Server还有很多属于自己特性的东西:Session, Watcher,Version等等等等,需要我们花更多的时间去研究和学习。

    原文链接:https://www.douban.com/note/208430424/

  • 大数据学习初级入门教程(十一) —— Zookeeper 3.4.6 完全分布式集群的安装、配置、启动和测试

    从前面一系列的基础部署教程中,可以看到大数据集群的部署中,为了保证集群的高可用性,一般都会配置 Zookeeper,比如 Kafka 集群的搭建中,就添加了 Zookeeper 配置。所以这篇补充一下 Zookeeper 集群的搭建,简单写写 Zookeeper 3.x 的安装配置、启动和测试。

    一、所需环境

    参考《大数据学习初级入门教程(一) —— Hadoop 2.x 完全分布式集群的安装、启动和测试》中准备的资源环境,这里将不再细述。

    集群部署规划为:node19、node18 和 node11 为 leader(领导者节点)/follower(跟随者节点),node12 和 node13 为 observer(观察者节点)。

    二、上传部署包

    为了简单期间,包直接放在机器的 /home 目录下,上传后解压包即可,这里先直接操作  node19 机器。

    三、解压部署包

    # tar -zxvf zookeeper-3.4.6.tar.gz

    四、创建配置文件

    刚解压的部署包,可以看到路径 /home/zookeeper-3.4.6/conf 下没有 zoo.cfg 文件,但有一个 zoo_sample.cfg 文件,可以重命名该文件,直接修改配置。这里直接新建一个 zoo.cfg。

    # vi zoo.cfg

    内容详细如下:

    tickTime=2000
    dataDir=/opt/zookeeper/zookeeper-3.4.6
    clientPort=2181
    initLimit=5
    syncLimit=2
    server.19=node19:2888:3888
    server.18=node18:2888:3888
    server.11=node11:2888:3888
    server.12=node12:2888:3888:observer
    server.13=node13:2888:3888:observer

    备注:

    tickTime(心跳周期毫秒数)、dataDir(数据目录)、clientPort(供客户端连接的端口号)、initLimit(集群中的 follower 与 leader 之间的初始连接)、syncLimit(集群中的 follower 与 leader 之间的通信连接)、server.n=host:port1:port2

    server.n=host:port1:port2,数字 n 必须是 myid 中的值
    port1 为 leader 端口,作为 leader 时,供 follower 连接的端口
    port2 为 选举端口,选举 leader 时,供其它 follower 连接的端口

    五、创建目录及文件

    由于在上一步中,配置了 dataDir 的路径,所以需要提前在指定位置创建目录。

    # cd /opt

    # mkdir -p zookeeper/zookeeper-3.4.6

    # cd zookeeper/zookeeper-3.4.6

    # vi myid

    分别写入19、18、 11、12 和 13。注意这几个值,和上一步中的 server.n 中的 n 值要保持一致。

    六、部署其它机器节点

    # scp -r zookeeper-3.4.6/ root@node18:/home/
    # scp -r zookeeper-3.4.6/ root@node11:/home/
    # scp -r zookeeper-3.4.6/ root@node12:/home/
    # scp -r zookeeper-3.4.6/ root@node13:/home/

    七、配置机器环境变量

    # vi ~/.bash_profile 

    在原配置后面追加:

    export ZK_HOME=/home/zookeeper-3.4.6
    export PATH=$PATH:$ZK_HOME/bin

    执行命令 source ~/.bash_profile 使得配置立刻生效。

    八、启动集群

    使用下面命令,启动每个 zk 节点:

    # zkServer.sh start

    如果看到下面的日志信息,说明节点启动成功:

    JMX enabled by default
    Using config: /home/zookeeper-3.4.6/bin/../conf/zoo.cfg
    Starting zookeeper … STARTED

    使用下面命令,可以看看每个节点都是什么角色:

    # zkServer.sh status

    [root@node19 conf]# zkServer.sh status
    JMX enabled by default
    Using config: /home/zookeeper-3.4.6/bin/../conf/zoo.cfg
    Mode: leader

    [root@node18 ~]# zkServer.sh status
    JMX enabled by default
    Using config: /home/zookeeper-3.4.6/bin/../conf/zoo.cfg
    Mode: follower

    [root@node11 ~]# zkServer.sh status
    JMX enabled by default
    Using config: /home/zookeeper-3.4.6/bin/../conf/zoo.cfg
    Mode: follower

    [root@node12 ~]# zkServer.sh status
    JMX enabled by default
    Using config: /home/zookeeper-3.4.6/bin/../conf/zoo.cfg
    Mode: observer

    [root@node13 ~]# zkServer.sh status
    JMX enabled by default
    Using config: /home/zookeeper-3.4.6/bin/../conf/zoo.cfg
    Mode: observer

    九、查看集群进程

    输入 jps 可以查看 zk 的进程信息,输出如下:

    1624 QuorumPeerMain

    十、测试集群

    访问其内存数据库,是一个内存文件系统,输入以下命令访问:

    # zkCli.sh

    可以看到如下输出:

    ls 命令可以查看根目录:

    get 命令查看 zookeeper 目录:

    -h 命令 查看帮助:

    退出用 quit:

    十一、测试高可用

    如果 master 节点挂掉,则集群内部会通过选举,产生新的 master 节点,比如停掉 node19 的 zk 服务,在 node19 机器上执行停止服务命令:

    # zkServer.sh stop

    再次查看各个节点状态,信息如下:

    [root@node19 conf]# zkServer.sh status
    JMX enabled by default
    Using config: /home/zookeeper-3.4.6/bin/../conf/zoo.cfg
    Error contacting service. It is probably not running.

    [root@node18 ~]# zkServer.sh status
    JMX enabled by default
    Using config: /home/zookeeper-3.4.6/bin/../conf/zoo.cfg
    Mode: leader

    [root@node11 ~]# zkServer.sh status
    JMX enabled by default
    Using config: /home/zookeeper-3.4.6/bin/../conf/zoo.cfg
    Mode: follower

    [root@node12 ~]# zkServer.sh status
    JMX enabled by default
    Using config: /home/zookeeper-3.4.6/bin/../conf/zoo.cfg
    Mode: observer

    [root@node13 ~]# zkServer.sh status
    JMX enabled by default
    Using config: /home/zookeeper-3.4.6/bin/../conf/zoo.cfg
    Mode: observer

    可以看到 node18 被选举为 leader 节点。

    如果再次启动 node19 上的 zk 服务,可以看到 node19 上的状态为 follower:

    Starting zookeeper … STARTED
    [root@node19 conf]# zkServer.sh status
    JMX enabled by default
    Using config: /home/zookeeper-3.4.6/bin/../conf/zoo.cfg
    Mode: follower

    十二、停止集群

    依次停用各个机器上的 zk 服务即可,命令还是 zkServer.sh stop。

    到此,Zookeeper 集群的安装、配置、启停,以及简单的内存库访问等基本搞定,后续可以在搭建其它集群时,配置 zk,让其保证其它集群的高可用性。

    十三、集群脚本

    zk 集群启动脚本,不用每个节点去执行 zkServer.sh start:

    1. #!/bin/bash  
    2.    
    3. echo “Zookeeper 集群启动开始…”  
    4.    
    5. for host in node19 node18 node11 node12 node13  
    6. do  
    7.    
    8. echo “——————————–“  
    9. echo $host “节点 zookeeper 启动开始…”  
    10. ssh $host “source /root/.bash_profile; zkServer.sh start >/dev/null 2>&1 &”  
    11. echo $host “节点 zookeeper 启动结束.”  
    12.    
    13. done  
    14.    
    15. echo “Zookeeper 集群启动结束.”  

    zk 集群停止脚本,不用每个节点去执行 zkServer.sh stop:

    1. #!/bin/bash  
    2.    
    3. echo “Zookeeper 集群停止开始…”  
    4.    
    5. for host in node19 node18 node11 node12 node13  
    6. do  
    7.    
    8. echo “——————————–“  
    9. echo $host “节点 zookeeper 停止开始…”  
    10. ssh $host “source /root/.bash_profile; zkServer.sh stop >/dev/null 2>&1 &”  
    11. echo $host “节点 zookeeper 停止结束.”  
    12.    
    13. done  
    14.    
    15. echo “Zookeeper 集群停止结束.”  

    zk 集群查看节点状态脚本,不用每个节点去执行 zkServer.sh status:

    1. #!/bin/bash  
    2.    
    3. echo “Zookeeper 集群当前状态…”  
    4.    
    5. for host in node19 node18 node11 node12 node13  
    6. do  
    7.    
    8. echo “——————————–“  
    9. echo $host “节点 zookeeper 状态…”  
    10. ssh $host “source /root/.bash_profile; zkServer.sh status”  
    11.    
    12. done  

    原文链接:https://blog.csdn.net/tzhuwb/article/details/105510533

  • Zookeeper 启动后的日志文件 zookeeper.out 路径修改

    当你安装好 Zookeeper 集群后,迫不及待的用启动命令 zkServer.sh start 启动集群,用命令 zkServer.sh status 查看集群状态时,看到集群正常启动并运行,心里是不是美滋滋,不过当你查看安装目录时,可以看到在你运行启动命令的目录里,生成了 zookeeper.out 日志文件,心情一下就不爽了。

    那么问题来了,这个目录是否可以自定义设置呢?答案当然是可以的,需要修改两个文件。

    修改 ZK_HOME/conf/log4j.properties 文件:

    注释掉的是原有路径,下方修改了本地路径。当前前提是 logs 目录自己已经创建。

    本以为这样修改后,启动集群,日志就可以放到对应文件夹,可结果还是和修改前一样无变化,日志还是在运行启动命令的目录,所以还需要修改一个脚本配置。

    修改 ZK_HOME/bin/zkEnv.sh 文件:

    修改后再次启动集群,可以看到日志已经生成到了自定义文件目录,在运行启动命令的目录再没有日志文件生成。

    当然,修改上面的配置文件是在一个节点机器上修改的,修改后别忘了把文件同步到 Zookeeper 集群的其它节点机器上。