文章目录
1 zookeeper基础
1.1 基本了解
zookeeper
是一个类似hdfs
的树形文件结构,zookeeper
可以用来保证数据在(zk
)集群之间的数据的事务性一致- 分布、开源的应用程序协调服务,它是集群的管理者,监视着集群中各个节点的状态,根据节点的反馈进行下一步合理操作。最终,将简单易用的接口和性能高效、功能稳定的系统提供给用户。
- 主要解决分布式应用经常遇到的
数据管理问题
,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。 Zookeeper
作为Hadoop
项目中的一个子项目,是Hadoop
集群管理的一个必不可少的模块,它主要用来控制集群中的数据,如它管理Hadoop
集群中的NameNode
,还有Hbase
中Master Election、Server
之间状态同步等
1.2 角色与功能
1.2.1 角色
1.2.1.1 三种角色
- 领导者(
leader
),负责进行投票的发起和决议,更新系统状态 - 学习者(
learner
),包括跟随者(follower
)和观察者(observer
)
follower
用于接受客户端请求
并想客户端返回结果,在选主过程中参与投票
Observer
可以接受客户端连接,将写请求转发给leader
,但observer
不参加投票过程,只同步leader
的状态
observer
的目的是为了扩展系统
,提高读取速度
- 客户端(
client
)请求发起方:
1.2.1.2 为什么引入Observer
Zookeeper
需保证高可用和强一致性,为了支持更多的客户端,需要增加更多Server
;
Server
增多,投票阶段延迟增大,影响性能;权衡伸缩性
和高吞吐率
,引入Observer
Observer
不参与投票;Observers
接受客户端的连接,并将写请求转发给leader
节点;- 加入更多
Observer
节点,提高伸缩性,同时不影响吞吐率
1.2.2 角色的功能
Leader
主要功能:恢复数据、维持与Follower
的心跳;接收Follower
请求并判断Follower
的请求消息类型
Leader
的消息类型主要有PING
消息、REQUEST
消息、ACK
消息、REVALIDATE
消息,根据不同的消息类型,进行不同的处理。Follower
主要功能:向Leader
发送请求(PING
消息、REQUEST
消息、ACK
消息、REVALIDATE
消息);接收Leader
消息并进行处理;接收Client
的请求,如果为写请求,发送给Leader
进行投票;返回Client
结果
不同的消息类型:
PING
消息是指Leader
的心跳信息;PROPOSAL
消息:Leader
发起的提案,要求Follower
投票;COMMIT
消息:服务器端最新一次提案的信息;REQUEST
消息是Follower
发送的提议信息,包括写请求
及同步请求
ACK
消息是Follower
的对提议的回复,超过半数的Follower
通过,则commit
该提议REVALIDATE
消息是用来延长SESSION
有效时间。UPTODATE
消息:表明同步完成;SYNC
消息:返回SYNC
结果到客户端,这个消息最初由客户端发起,用来强制得到最新的更新。
1.3 zookeeper提供了什么
1.3.1 文件系统
Zookeeper
提供一个多层级的节点命名空间(节点称为znode
)。
与文件系统不同的是,这些节点都可以设置关联的数据
,而文件系统中只有文件节点
可以存放数据而目录节点不行。
Zookeeper
为了保证高吞吐
和低延迟
,在内存中维护了这个树状的目录结构,这种特性使得Zookeeper
不能用于存放大量的数据,每个节点的存放数据上限为1M
Znode
分为四种类型:
PERSISTENT
持久化目录节点。(客户端与zookeeper
断开连接后,该节点依旧存在)。PERSISTENT_SEQUENTIAL
-持久化顺序编号目录节点。(客户端与zookeeper
断开连接后,该节点依旧存在,只是Zookeeper
给该节点名称进行顺序编号)EPHEMERAL
-临时目录节点(客户端与zookeeper
断开连接后,该节点被删除)EPHEMERAL_SEQUENTIAL
-临时顺序编号目录节点。(客户端与zookeeper
断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号)
1.3.2 通知机制
client
端会对某个znode
建立一个watcher
事件,当该znode
发生变化时,这些client
会收到zk
的通知,然后client
可以根据znode
变化来做出业务上的改变等
1.4 Zookeeper的核心及原理
1.4.1 zookeeper特性
一致性
:client
不论连接到哪个Server
,展示给它都是同一个视图,这是zookeeper
最重要的性能。可靠性
:具有简单、健壮、良好的性能,如果消息m被到一台服务器接受,那么它将被所有的服务器接受。实时性
:Zookeeper
保证客户端将在一个时间间隔范围内获得服务器的更新信息,或者服务器失效的信息。但由于网络延时等原因,Zookeeper
不能保证两个客户端能同时得到刚更新的数据,如果需要最新数据,应该在读数据之前调用sync()
接口。等待无关
(wait-free
):慢的或者失效的client
不得干预快速的client
的请求,使得每个clien
t都能有效的等待。原子性
:更新只能成功或者失败,没有中间状态。顺序性
:包括全局有序
和偏序
两种:全局有序是指如果在一台服务器上消息a在消息b
前发布,则在所有Server
上消息a
都将在消息b前被发布;偏序是指如果一个消息b
在消息a
后被同一个发送者发布,a
必将排在b
前面。
1.4.2 zookeeper原理
Zookeeper
的核心是原子广播,这个机制保证了各个Server
之间的同步。实现这个机制的协议叫做Zab
协议。
Zab
协议有两种模式,它们分别是恢复模式(选主)
和广播模式(同步)
:
- 当服务启动或者在领导者崩溃后,
Zab
就进入了恢复模式,当领导者被选举出来,且大多数Server
完成了和leader
的状态同步以后,恢复模式就结束了。状态同步保证了leader
和Server
具有相同的系统状态。 消息广播模式
:在ZooKeeper
中所有的事务请求都由一个主服务器也就是Leader
来处理,其他服务器为Follower
,Leader
将客户端的事务请求转换为事务Proposal
,并且将Proposal
分发给集群中其他所有的Follower
,然后Leader
等待Follwer
反馈,当有过半数(>=N/2+1
)的Follower
反馈信息后,Leader
将再次向集群内Follower
广播Commit
信息,Commit
为将之前的Proposal
提交。
广播模式需要保证proposal
被按顺序处理,为了保证事务的顺序一致性,zookeeper
采用了递增的事务id
号(zxid
)来标识事务。所有的提议(proposal
)都在被提出的时候加上了zxid
。zxid
是一个64
位的数字,它高32
位是epoch
用来标识leader
关系是否改变,每次一个leader
被选出来,它都会有一个新的epoch
,标识当前属于那个leader
的统治时期。低32
位用于递增计数
。
一旦leader
已经和多数的follower
进行了状态同步
后,他就可以开始广播消息
了,即进入广播状态。这时候当一个server
加入zookeeper
服务中,它会在恢复模式
下启动,发现leader
,并和leader
进行状态同步。待到同步结束,它也参与消息广播。Zookeepe
r服务一直维持在Broadcast
状态,直到leader
崩溃了或者leader
失去了大部分的followers
支持。
每个Server
在工作过程中有三种状态:
LOOKING
:当前Server
不知道leader
是谁,正在搜寻。LEADING
:当前Server
即为选举出来的leader
FOLLOWING
:leader
已经选举出来,当前Server
与之同步
1.5 zookeeper流程
1.5.1 数据流程
- 在
Client
向Follwer
发出一个写的请求 Follwer
把请求发送给Leader
Leader
接收到以后开始发起投票并通知Follwer
进行投票Follwer
把投票结果发送给Leader
Leader
将结果汇总后如果需要写入,则开始写入同时把写入操作通知给Follwer
,然后commit
;Follwer
把请求结果返回给Client
1.5.2 选主流程以及算法
1.5.2.1 选举leader
当leader
崩溃或者leader
失去大多数的follower
,这时候zk
进入恢复模式,恢复模式需要重新选举出一个新的leader
,让所有的server
都恢复到一个正确的状态。
每个Server
启动以后都询问其它的Server
它要投票给谁。
对于其他server
的询问,server
每次根据自己的状态都回复自己推荐的leader
的id
和上一次处理事务的zxid
(系统启动时每个server
都会推荐自己)
收到所有Server
回复以后,就计算出zxid
最大的哪个Server
,并将这个Server
相关信息设置成下一次要投票的Server
计算这过程中获得票数最多的的sever
为获胜者,如果获胜者的票数超过半数,则改server
被选为leader
。否则,继续这个过程,直到leader
被选举出来,leader
就会开始等待server
连接
Follower
连接leader
,将最大的zxid
发送给leader
,Leader
根据follower
的zxid
确定同步点
完成同步后通知follower
已经成为uptodate
状态
Follower
收到uptodate
消息后,又可以重新接受client
的请求进行服务了
1.5.2.2 选举算法
Zk
的选举算法有两种:一种是基于basic paxos
实现的,另外一种是基于fast paxos
算法实现的。系统默认的选举算法为fast paxos
。
1.5.2.2.1 Basic paxos
Basic paxos
:当前Server
发起选举的线程,向所有Server
发起询问,选举线程收到所有回复,计算zxid
最大Server
,并推荐此为leader
,若此提议获得n/2+1
票通过,此为leader
,否则重复上述流程,直到leader
选出。
1.5.2.2.2 Fast paxos
Fast paxos
:某Server
首先向所有Server
提议自己要成为leader
,当其它Server
收到提议以后,解决epoch
和 zxid
的冲突,并接受对方的提议,然后向对方发送接受提议完成的消息,重复这个流程,最后一定能选举出Leader
。(即提议方解决其他所有epoch
和zxid
的冲突,即为leader
)
1.6 ZooKeeper的Watcher机制
ZooKeeper
的 Watcher
机制主要包括客户端线程
、客户端 WatchManager
和 ZooKeeper 服务器
三部分。
ZooKeeper
:部署在远程主机上的ZooKeeper
集群,当然,也可能是单机的。Client
:分布在各处的 ZooKeeper 的 jar 包程序,被引用在各个独立应用程序中。WatchManager
:一个接口,用于管理各个监听器,只有一个方法materialize()
,返回一个Watcher
的set
。
客户端在向 ZooKeepe
r 服务器注册 Watcher
的同时,会将Watcher
对象存储在客户端的 WatchManager
中。当ZooKeeper
服务器触发 Watcher
事件后,会向客户端发送通知,客户端线程从WatchManager
的实现类中取出对应的 Watcher
对象来执行回调逻辑。
Watcher
特性总结
- 一次性
无论是服务端还是客户端,一旦一个Watcher
被触发,ZooKeeper
都会将其从相应的存储中移除。因此,在Watcher
的使用上,需要反复注册。这样的设计有效地减轻了服务端的压力。 - 客户端串行执行
客户端Watcher
回调的过程是一个串行同步的过程,这为我们保证了顺序,同时,需要注意的一点是,一定不能因为一个Watcher
的处理逻辑影响了整个客户端的Watcher
回调,所以,觉得客户端Watcher
的实现类要另开一个线程进行处理业务逻辑,以便给其他的Watcher
调用让出时间。 - 轻量
WatcherEvent
是ZooKeeper
整个Watcher
通知机制的最小通知单元,这个数据结构中只包含三部分内容:通知状态、事件类型和节点路径。也就是说,Watcher
通知非常简单,只会告诉客户端发生了事件,而不会说明事件的具体内容。例如针对NodeDataChanged
事件,ZooKeeper
的Watcher
只会通知客户端指定数据节点的数据内容发生了变更,而对于原始数据以及变更后的新数据都无法从这个事件中直接获取到,而是需要客户端主动重新去获取数据——这也是ZooKeeper
的Watcher
机制的一个非常重要的特性
2 zookeeper的作用
2.1 命名服务
在zookeeper
的文件系统里创建一个目录,即有唯一的path
。在我们使用tborg
无法确定上游程序的部署机器时即可与下游程序约定好path
,通过path
即能互相探索发现。
2.2 配置管理
把应用配置放置zookeeper
上去,保存在 Zookeeper
的某个目录节点中,然后所有相关应用程序对这个目录节点进行监听,一旦配置信息发生变化,每个应用程序就会收到 Zookeeper
的通知,然后从Zookeeper
获取新的配置信息应用到系统中就好。
2.3集群管理
节点(机器)增删及Master
选取。
2.3.1 节点增删
所有机器约定在父目录GroupMembers
下创建临时目录节点,然后监听父目录节点的子节点变化消息。一旦有机器挂掉,该机器与zookeeper
的连接断开,其所创建的临时目录节点被删除,所有其他机器都收到通知:某个兄弟目录被删除,于是,所有人都知道:它挂了。新机器加入 也是类似,所有机器收到通知:新兄弟目录加入,highcount
又有了。
2.3.1 Master节点选取
所有机器创建临时顺序编号目录节点,每次选取编号最小的机器作为master
就好。
如果有多个master
,每次只能有一个master
负责主要的工作,其他的master
作为备份,同时对负责工作的master
进行监听,一旦负责工作的master
挂掉了,其他的master
就会收到监听的事件,从而去抢夺负责工作的权利,其他没有争夺到负责主要工作的master
转而去监听负责工作的新master
,简而言之:一人干,多人看
2.4 分布式锁
基于zookeeper
一致性文件系统,实现锁服务。锁服务分为保存独占
及时序控制
两类。
2.4.1 保存独占
将zookeeper
上的一个znode
看作是一把锁,通过createznode
的方式来实现。
所有客户端都去创建 /distribute_lock
节点,最终成功创建的那个客户端也即拥有了这把锁。
用完删除自己创建的distribute_lock
节点就释放锁。
2.4.2 时序控制
基于/distribute_lock
锁,所有客户端在它下面创建临时顺序编号目录节点,和选master
一样,编号最小的获得锁,用完删除,依次方便。
2.5 队列管理
分同步队列
,FIFO队列
(入队与出队)
2.5.1 同步队列
当一个队列的成员都聚齐时,这个队列才可用,否则一直等待所有成员到达。在约定目录下创建临时目录节点,监听节点数目是否是我们要求的数目
2.5.2 FIFO队列
FIFO
队列(入队与出队)和分布式锁服务中的控制时序场景基本原理一致,入列有编号,出列按编号。
2.6 分布式与数据复制
Zookeeper
作为一个集群提供一致的数据服务,必然在所有机器间做数据复制。
数据复制好处:
容错
:一个节点出错,不致于让整个系统停止工作,别的节点可以接管它的工作。提高系统的扩展能力
:把负载分布到多个节点上,或者增加节点来提高系统的负载能力;性能提升
:让客户端本地访问就近节点,提高用户访问速度。
3 数据一致性与paxos 算法
3.1 数据集群
数据集群系统分:
- 写主(
writeMaster
),对数据的修改提交给指定的节点。读无此限制,可以读取任何一个节点。这种情况下客户端需要对读与写进行区别,俗称读写分离; - 写任意(对数据的修改可提交给任意的节点,跟读一样。这种情况下,客户端对集群节点的角色与变化透明)对
zookeeper
来说,它采用的方式是写任意。通过增加机器,它的读吞吐能力和响应能力扩展性非常好,而写,随着机器的增多吞吐能力肯定下降(这也是它建立observer
的原因),而响应能力则取决于具体实现方式,是延迟复制保持最终一致性,还是立即复制快速响应。
3.2 原则
在一个分布式数据库系统中,如果各节点的初始状态一致,每个节点都执行相同的操作序列,那么他们最后能得到一个一致的状态。Paxos算法解决:保证每个节点执行相同的操作序列。
Paxos
算法通过投票来对写操作
进行全局编号,同一时刻,只有一个写操作被批准,同时并发的写操作要去争取选票,只有获得过半数
选票的写操作才会被 批准(所以永远只会有一个写操作得到批准),其他的写操作竞争失败只好再发起一轮投票,就这样,在日复一日年复一年的投票中,所有写操作都被严格编号排序。编号严格递增,当一个节点接受了一个编号为100
的写操作,之后又接受到编号为99
的写操作(因为网络延迟等很多不可预见原因),它马上能意识到自己数据不一致了,自动停止对外服务并重启同步过程。任何一个节点挂掉都不会影响整个集群的数据一致性(总2n+1
台,除非挂掉大于n
台)。