第一章.zookeeper概述
一.zookeeper 简介
zookeeper 是一个开源的分布式应用程序协调服务器,是 Hadoop 的重要组件。
zooKeeper 是一个分布式的,开放源码的分布式应用程序协调服务器,是 Google 的Chubby 一个开源的实现,是 Hadoop 和 Hbase 的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、集群管理等。ZooKeeper的目标就是封装复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。
二.ZK 基本概念
对于 Zookeeper 的学习,首先需要了解一些基本概念。
1.三类角色
为了避免 Zookeeper 的单点问题,zk 也是以集群的形式出现的。zk 集群中的角色主要有以下三类:
1).Leader:zk 集群写请求的唯一处理者,并负责进行投票的发起和决议,更新系统状态。Leader 是很民主的,并不是说其在接收到写请求后马上就修改其中保存的数据,而是首先根据写请求提出一个提议,在大多数 zkServer 均同意时才会做出修改。
2).Follower:接收客户端请求,处理读请求,并向客户端返回结果;将写请求转给 Leader;在选主(选 Leader)过程中参与投票。
3).Observer:可以理解为无选主投票权的 Flollower,其主要是为了协助 Follower 处理更多的读请求。如果 Zookeeper 集群的读请求负载很高,或者客户端非常非常多,多到跨机房,则可以设置一些 Observer 服务器,以提高读取的吞吐量。
Leader是写请求的唯一处理者,原因是:写请求关乎数据的一致性,由Leader写,然后广播给其他子节点。
2.三种模式
Zookeeper 的核心是广播,这个机制保证了各个 zkServer 间数据的同步,即数据的一致性。实现这个机制的协议叫做 ZAB 协议,即 Zookeeper Atomic Broadcast,ookeeper 原子广播协议。ZAB 协议有三种模式:恢复模式、同步模式和广播模式。
1).恢复模式:在服务重启过程中,或在 Leader 崩溃后,就进入了恢复模式,要恢复到 zk集群正常的工作状态。
2).同步模式:在所有的 zkServer 启动完毕,或 Leader 崩溃后又被选举出来时,就进入了同步模式,各个 Follower 需要马上将 Leader 中的数据同步到自己的主机中。当大多数zkServer 完成了与 Leader 的状态同步以后,恢复模式就结束了。所以,同步模式包含在恢复模式过程中。
3).广播模式:当 Leader 的提议被大多数 zkServer 同意后,Leader 会修改自身数据,然后会将修改后的数据广播给其它 Follower。
第二章.zookeeper 的安装与集群搭建
一.安装单机zookeeper
对于系统安全性、实时性要求不是很高的系统,为了节约成本,使用单机 Zookeeper 作为协调服务器也是可以的。
1.准备工作
1).克隆并配置主机
克隆一台干净的主机,并修改配置。
a.修改主机名:/etc/hostname
b.修改网络配置:/etc/sysconfig/network-scripts/ifcfg-ens33
2).下载zookeeper安装包
在http://zookeeper.apache.org官网下载。
2.上传安装包
将下载的 Zookeeper 安装包上传到10.255.34.74机器的/data/app 目录。
3.安装配置 zk
1).解压安装包
2).创建软链接
3).复制配置文件
复制zookeeper 安装目录下的 conf 目录中的 zoo_sample.cfg 文件,并命名为 zoo.cfg。
4).修改配置文件
a.tickTime:zk 使用的基本时间单位为 tick,该属性设置一个 tick 的时间长度,单位毫秒。
b.initLimit:Follower 初始化同步的超时时限,单位为 tickTime 的倍数。集群启动或新 Leader选举完成后,Follower 需要从 Leader 同步数据,如果需要同步的数据量较大,则可能超时。一旦超时,同步失效。
c.syncLimit:Follower 更新同步的超时时限,单位为 tickTime 的倍数。后续同步与初始化同步的不同点在于,初始化同步的数据量要大于后续同步的,后续同步的数据量一般是较小的。所以,对于 initLimit 是否超时,更多是取决于网络质量。如果超时,Leader 就认为该 Follower 落后太多需要放弃。如果网络为高延迟环境,可适当增加该值,但不宜
增加太大,否则会掩盖某些故障。
d.dataDir:ZKServer 的内存中维护着一个内存数据库,像域名服务 zk 中的服务映射表就存放在该内存数据库中。该路径为内存数据库快照文件 snapshot 的存储路径。默认给
出的路径在/tmp 中,提示也指出,不要将快照存储路径设置到/tmp 中。
e.clientPort:客户端连接 zkServer 的端口号,每台 ZKServer 允许设置为不同的值。默认配置文件设定的是 2181。
5).新建数据存放目录
6).注册 bin 目录
由于我们要使用的命令都在 ZK 安装目录下的 bin 目录中,所以在/etc/profile 文件中将该 bin 目录注册到系统环境变量 PATH 中。
7).重新加载 profile 文件
4.操作 zk
1).开启 zk
2).查看状态
3).重启 zk
zkServer.sh restart
4).停止 zk
二.搭建zookeeper集群
对于单机zookeeper,存在单点故障问题,系统的安全性降低。Zookeeper 在生产场景中一般是以集群的形式出现的。
下面要搭建一个由三台 zk 构成的 zk 集群。
1.克隆并配置第一台主机
1).克隆并配置主机(在我这不是本地虚拟机,无需这一步操作)
克隆前面单机 Zookeeper 主机后,要修改如下配置文件:
a.修改主机名:/etc/hostname
b.修改网络配置:/etc/sysconfig/network-scripts/ifcfg-ens33
2).修改 hosts(在我这不是本地虚拟机,无需这一步操作)
修改本地域名文件 /etc/hosts。
3).修改 zoo.cfg
在 zoo.cfg 文件中添加 zk 集群节点列表。
说明:
a.等号左边的“server.数字”,表示要设置第几个 zkServer 节点。数字一般从 1 开始计数,依次加 1。
b.等号右边的第一段,表示该 zkServer 节点的主机,可以是主机名,也可以是主机 IP
c.等号右边的第二段,表示连接端口号。即其它 zkServer 与当前主机连接的端口号。每台主机的连接端口号可以任意设置,且可不一样。
d.等号右边的第三段,表示选举端口号。若当前的 Leader 宕机,各个 Follower 需要选举新的 Leader,这些 Follower 之间为了选举而相互联系,就使用该端口号。每台主机的选举端口号可以任意设置,且可不一样。
4).删除无效数据
zk 的运行会在/usr/data/zookeeper 目录中生成一些文件与目录,这些文件和目录与当前的 zkServer 具有绑定关系。由于 zkos1 主机复制于原单机 Zookeeper,所以会将其/usr/data/zookeeper 目录中生成文件与目录一起复制来,这些数据对于 zkos1 来说就是无效数据,可以先将基删除。
5).创建 myid 文件
在/usr/data/zookeeper 目录中创建表示当前主机编号的 myid 文件。该主机编号要与zoo.cfg 文件中设置的编号一致。
2.复制并配置其它主机
复制并配置其它主机的方式是相同的,然后创建myid(myid 的值与 zoo.cfg 中指定的主机编号相同)。
3.zk 集群操作
1).启动 zk 集群
使用 zkServer.sh start 命令,逐个启动每一个zookeeper 节点主机,即启动每一个zookeeper Server。
启动第一台zk服务
启动第二台zk服务
启动第三台zk服务
2).查看 zk 节点状态
使用 zkServer.sh status 命令可查看 zk 集群中各个节点的状态:是 Leader,还是 Follower。
至于为什么是第二台zk服务是leader,后面Leader选举发生的时机中的服务器启动时的章节有详细的分析。
3).重启 zk 集群
zk服务器依次执行zkServer.sh restart命令。
4).停止 zk 集群
zk服务器依次执行zkServer.sh stop命令。
5).Leader 重新选举
将当前的 Leader 主机停机,模拟 Leader 宕机的情况。
在这里,停止第二台leader的服务。
再次查看未停机的 zkServer,发现其中有一台已由原来的 Follower 变为了 Leader。
在这里,第三台变leader,第一台还是follower。
第3章.Leader的选举机制
一.基本概念
1.myid
这是 zk 集群中服务器的唯一标识,称为 myid。例如,有三个 zk 服务器,那么编号分别是 1,2,3。
2.zxid
zxid 为 Long 类型,其中高 32 位表示 epoch,低 32 位表示 xid。即 zxid 由两部分构成:epoch 与 xid。
每个 Leader 都会具有一个不同的 epoch 值,表示一个时期、时代。新的 Leader 产生,则会更新所有 zkServer 的 zxid 中的 epoch。
而 xid 则为 zk 的事务 id,每一个写操作都是一个事务,都会有一个 xid。每一个写操作都需要由 Leader 发起一个提议,由所有 Follower 表决是否同意本次写操作。
3.逻辑时钟
逻辑时钟,Logicalclock,是一个整型数,该概念在选举时称为 logicalclock,而在 zxid 中则为 epoch 的值。即 epoch 与 logicalclock 是同一个值,在不同情况下的不同名称。
4.选举状态
a.LOOKING,选举状态(查找 Leader 的状态)。
b.FOLLOWING,随从状态,同步 leader 状态。处于该状态的服务器称为 Follower。
c.OBSERVING,观察状态,同步 leader 状态。处于该状态的服务器称为 Observer。
d.LEADING,领导者状态。处于该状态的服务器称为 Leader。
二.选举算法的简单描述
各个服务器都要投票进行 Leader 的选举,大家投票的标准是:epoch 大者投之;epoch相等,则 xid 大者投之;xid 相等,则 myid 大者投之;最终,得票最多者当选。其实,简单来说就是 zxid(epoch, xid)大者投之,否则 myid 大者投之。
对于“myid 大者投之”这条规则好理解,就是人为指定的一种标准,但为什么要有“epoch大者投之”与“xid 大者投之”的标准呢?
因为 epoch 其实表示的是发起 Leader 选举的时间顺序,越靠后发起的选举,epoch 的值越大。若 epochA 大于 epochB,则说明 epochB 的选举已经过时,有可能 epochB 时代选举出分布式协调服务器 Zookeeper的 Leader 已经宕机,现在又要发起新的选举了。所以,epoch 大者就是最近的选举,应遵从最近选举的结果。
那么,为什么 xid 大者要投之呢?xid 即事务 id,每一个写请求都会对应一个 xid。其投票中的 xid 大,则说明其具有最新的写操作信息,那么,其就应作为 Leader,让其它 Server来同步该写操作。
三.Leader选举发生的时机
在以下两种情况下会发生 Leader 选举。
1.服务器启动时
现在以三台服务器为例来分析选举过程。这 3 台服务器的 myid 编号分别是 1、2、3,然后按编号依次启动,它们的选择举过程为:
服务器 1 启动,给自己投票,然后发布自己的投票结果(myid,zxid),由于其它机器还没有启动所以它收不到反馈信息,服务器 1 的状态一直属于 Looking,即属于非服务状态。
服务器 2 启动,给自己投票,然后发布自己的投票结果(myid,zxid),其 zxid 与服务器 1的相同,在与服务器 1 交换结果后,由于服务器 2 的 myid 大,所以服务器 2 胜出,此时服务器 2 获取到的投票数为 2,大于半数 1,所以服务器 2 成为 Leader,服务器 1 成为小弟。
服务器 3 启动,同样给自己投票,同时与之前启动的服务器 1,2 交换信息,尽管服务器3 的 myid 大,但之前服务器 2 已经胜出,所以服务器 3 只能成为小弟。
2.原Leader宕机后
在zookeeper 运行期间,Leader 与非 Leader 服务器(Follower 与 Observer)各司其职,即便当有非 Leader 服务器宕机或新加入,此时也不会影响 Leader,但是一旦 Leader 服务器宕机,那么整个集群将暂停对外服务,进入新一轮 Leader 选举,其过程和启动时期的 Leader选举过程基本一致。
假设正在运行的有 Server1、Server2、Server3 三台服务器,当前 Leader 是 Server2,若某一时刻 Leader 挂了,此时便开始 Leader 选举。
首先这些活着的 Server 会修改状态为 LOOKING,进入选举状态。需要注意,在运行期间,每个服务器上的 ZXID 可能是不同的。此时投票,zxid 大者会作为新的 Leader。
四.源码解读
由于zookeeper 是使用 Ant 进行构建的,所以若想将 Zookeeper 的源码导入到Eclipse或Idea中进行源码分析,需要首先安装 Ant 工具,然后再执行 ant eclipse 命令,会生成 Eclipse工程,然后再导入到 Eclipse 或 Idea 中。
由于我们这里仅仅对选举算法的源码进行分析,所以就不再安装 Ant 了,直接打开源码中的对应类进行分析。
需要注意,对源码的阅读主要包含两方面。一个是对重要类、重要成员变量、重要方法的注释的阅读;一个是对重要方法的业务逻辑的阅读。