1.Zookeeper工作原理

1、在zookeeper的集群中,各个节点共有下面3种角色和4种状态:

角色:leader,follower,observer
状态:leading,following,observing,looking

Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议(ZooKeeper Atomic Broadcast protocol)。Zab协议有两种模式,它们分别是恢复模式(Recovery选主)和广播模式(Broadcast同步)。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和leader的状态同步以后,恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。

为了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid)来标识事务。所有的提议(proposal)都在被提出的时候加上了zxid。实现中zxid是一个64位的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch,标识当前属于那个leader的统治时期。低32位用于递增计数。

每个Server在工作过程中有4种状态:

LOOKING:当前Server不知道leader是谁,正在搜寻。

LEADING:当前Server即为选举出来的leader。

FOLLOWING:leader已经选举出来,当前Server与之同步。

OBSERVING:observer的行为在大多数情况下与follower完全一致,但是他们不参加选举和投票,而仅仅接受(observing)选举和投票的结果。

2.选举机制

  1. 半数机制:集群中半数以上机器存活,集群可用。所以Zookeeper适合安装奇数台服务器。
  2. 需要给每个zookeeper 1G左右的内存,如果可能的话,最好有独立的磁盘,因为独立磁盘可以确保zookeeper是高性能的。如果你的集群负载很重,不要把zookeeper和RegionServer运行在同一台机器上面,就像DataNodes和TaskTrackers一样。
  3. Zookeeper虽然在配置文件中并没有指定Master和Slave。但是,Zookeeper工作时,是有一个节点为Leader,其他则为Follower,Leader是通过内部的选举机制临时产生的。
  4. 以一个简单的例子来说明整个选举的过程。

假设有五台服务器组成的Zookeeper集群,它们的id从1-5,同时它们都是最新启动的,也就是没有历史数据,在存放数据量这一点上,都是一样的。假设这些服务器依序启动,来看看会发生什么,如图

查看zookeeper集群地址 zookeeper集群状态_服务器

  1. 服务器1启动,此时只有它一台服务器启动了,它发出去的报文没有任何响应,所以它的选举状态一直是LOOKING状态。
  2. 服务器2启动,它与最开始启动的服务器1进行通信,互相交换自己的选举结果,由于两者都没有历史数据,所以id值较大的服务器2胜出,但是由于没有达到超过半数以上的服务器都同意选举它(这个例子中的半数以上是3),所以服务器1、2还是继续保持LOOKING状态。
  3. 服务器3启动,根据前面的理论分析,服务器3成为服务器1、2、3中的老大,而与上面不同的是,此时有三台服务器选举了它,所以它成为了这次选举的Leader。
  4. 服务器4启动,根据前面的分析,理论上服务器4应该是服务器1、2、3、4中最大的,但是由于前面已经有半数以上的服务器选举了服务器3,所以它只能接收当小弟的命了。
  5. 服务器5启动,同4一样当小弟。

3.集群搭建

3.1集群规划

机器编号

Ip 地址

端口

apache-zookeeper-01

127.0.0.1

2181

apache-zookeeper-02

127.0.0.1

2182

apache-zookeeper-03

127.0.0.1

2183

3.2下载zookeeper

https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/

 

3.3创建ServerID标识

除了修改zoo.cfg配置文件外,zookeeper集群模式下还要配置一个myid文件,这个文件需要放在dataDir目录下。

除了修改zoo.cfg配置文件外,zookeeper集群模式下还要配置一个myid文件,这个文件需要放在dataDir目录下。

这个文件里面有一个数据就是A的值(该A就是zoo.cfg文件中server.A=B:C:D中的A),在zoo.cfg文件中配置的dataDir路径中创建myid文件。

#在apache-zookeeper-01上面创建myid文件,并设置值为1,同时与zoo.cfg文件里面的server.1保持一致,如下:

vi ../apache-zookeeper-01/data/myid  设置值为1

vi ../apache-zookeeper-02/data/myid  设置值为2

vi ../apache-zookeeper-03/data/myid  设置值为3

 

3.4分别修改zoo.cfg文件

#number of milliseconds of each tick

tickTime=2000

# 配置leader节点和follower节点启动并且完成数据同步的时间

initLimit=10

# leader节点和follower节点心跳检测的最大延迟时间

syncLimit=5

# 存储快照的目录

dataDir=/Users/xiongpeng/Library/zk-cluster/apache-zookeeper-01/data

#存储日志的目录
dataLogDir=/Users/xiongpeng/Library/zk-cluster/apache-zookeeper-01/logs

# 对外暴露的端口

clientPort=2181


#第几个服务器(1,2,3来自数据目录的一个myid文件,该文件里面保存着当前集群的标识(1,2,3))
#后面的ip代表将绑定那个ip地址 第一个端口:代表在集群内部,数据复制的接口 第二个端口:选举端口
server.1=127.0.0.1:2111:3111
server.2=127.0.0.1:2222:3222
server.3=127.0.0.1:2333:3333
#number of milliseconds of each tick

tickTime=2000

# 配置leader节点和follower节点启动并且完成数据同步的时间

initLimit=10

# leader节点和follower节点心跳检测的最大延迟时间

syncLimit=5

# 存储快照的目录

dataDir=/Users/xiongpeng/Library/zk-cluster/apache-zookeeper-02/data

#存储日志的目录
dataLogDir=/Users/xiongpeng/Library/zk-cluster/apache-zookeeper-02/logs

# 对外暴露的端口

clientPort=2182


#第几个服务器(1,2,3来自数据目录的一个myid文件,该文件里面保存着当前集群的标识(1,2,3))
#后面的ip代表将绑定那个ip地址 第一个端口:代表在集群内部,数据复制的接口 第二个端口:选举端口
server.1=127.0.0.1:2111:3111
server.2=127.0.0.1:2222:3222
server.3=127.0.0.1:2333:3333
#number of milliseconds of each tick

tickTime=2000

# 配置leader节点和follower节点启动并且完成数据同步的时间

initLimit=10

# leader节点和follower节点心跳检测的最大延迟时间

syncLimit=5

# 存储快照的目录

dataDir=/Users/xiongpeng/Library/zk-cluster/apache-zookeeper-03/data

#存储日志的目录
dataLogDir=/Users/xiongpeng/Library/zk-cluster/apache-zookeeper-03/logs

# 对外暴露的端口

clientPort=2183


#第几个服务器(1,2,3来自数据目录的一个myid文件,该文件里面保存着当前集群的标识(1,2,3))
#后面的ip代表将绑定那个ip地址 第一个端口:代表在集群内部,数据复制的接口 第二个端口:选举端口
server.1=127.0.0.1:2111:3111
server.2=127.0.0.1:2222:3222
server.3=127.0.0.1:2333:3333

 

3.5启动集群

启动apache-zookeeper-01

192:xiongpeng$ ./apache-zookeeper-01/bin/zkServer.sh start
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /Users/xiongpeng/Library/zk-cluster/apache-zookeeper-01/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED

启动后查看状态

192:bin xiongpeng$ ./zkServer.sh status
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /Users/xiongpeng/Library/zk-cluster/apache-zookeeper-01/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost.
Error contacting service. It is probably not running.

发现没有启动,因为启动节点没有过半数。

继续重复上述步骤,启动apache-zookeeper-02,apache-zookeeper-03。

启动完成之后查看每个节点的状态

192:bin xiongpeng$ ./zkServer.sh status
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /Users/xiongpeng/Library/zk-cluster/apache-zookeeper-02/bin/../conf/zoo.cfg
Client port found: 2182. Client address: localhost.
Mode: leader
192:bin xiongpeng$ ./zkServer.sh status
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /Users/xiongpeng/Library/zk-cluster/apache-zookeeper-03/bin/../conf/zoo.cfg
Client port found: 2183. Client address: localhost.
Mode: follower
192:bin xiongpeng$ ./zkServer.sh status
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /Users/xiongpeng/Library/zk-cluster/apache-zookeeper-01/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost.
Mode: follower

#从上面可以看出,zk1,zk3两台服务器zookeeper的状态是follow模式,zk2这台服务器zookeeper的状态是leader模式。

3.6Zookeeper集群连接

Zookeeper集群搭建完毕之后,可以通过客户端脚本连接到zookeeper集群上面,对客户端来说,zookeeper集群是一个整体,连接到zookeeper集群实际上感觉在独享整个集群的服务。

在apache-zookeeper-02中创建节点,写入数据

[zk: 127.0.0.1:2182(CONNECTED) 0] create -e /firstNode "first"
Created /firstNode
[zk: 127.0.0.1:2182(CONNECTED) 1] set /firstNode test

在apache-zookeeper-01中查看该节点数据是否同步

[zk: 127.0.0.1:2181(CONNECTED) 1] get /firstNode
test

 

注意:zookeeper节点是奇数 

        ①、容错率

  首先从容错率来说明:(需要保证集群能够有半数进行投票)

  2台服务器,至少2台正常运行才行(2的半数为1,半数以上最少为2),正常运行1台服务器都不允许挂掉,但是相对于 单节点服务器,2台服务器还有两个单点故障,所以直接排除了。

  3台服务器,至少2台正常运行才行(3的半数为1.5,半数以上最少为2),正常运行可以允许1台服务器挂掉

  4台服务器,至少3台正常运行才行(4的半数为2,半数以上最少为3),正常运行可以允许1台服务器挂掉

  5台服务器,至少3台正常运行才行(5的半数为2.5,半数以上最少为3),正常运行可以允许2台服务器挂掉

  ②、防脑裂

  脑裂集群的脑裂通常是发生在节点之间通信不可达的情况下,集群会分裂成不同的小集群,小集群各自选出自己的leader节点,导致原有的集群出现多个leader节点的情况,这就是脑裂。

  3台服务器,投票选举半数为1.5,一台服务裂开,和另外两台服务器无法通行,这时候2台服务器的集群(2票大于半数1.5票),所以可以选举出leader,而 1 台服务器的集群无法选举。

  4台服务器,投票选举半数为2,可以分成 1,3两个集群或者2,2两个集群,对于 1,3集群,3集群可以选举;对于2,2集群,则不能选择,造成没有leader节点。

  5台服务器,投票选举半数为2.5,可以分成1,4两个集群,或者2,3两集群,这两个集群分别都只能选举一个集群,满足zookeeper集群搭建数目。

  以上分析,我们从容错率以及防止脑裂两方面说明了3台服务器是搭建集群的最少数目,4台发生脑裂时会造成没有leader节点的错误。