目录
一,ZooKeeper简介
1,什么是Zookeeper
2,基本特性
二,ZooKeeper原理
1,系统架构
1.1 角色分工
1.2 设计思想
1.3 为什么要引入Observer(ZK 3.3.0)?
2,数据模型
2.1 Znode
2.2 Znode Tree
2.3 会话session
2.4 Znode节点类型
2.5 Znode版本
2.6 Znode属性
3,数据读写
3.1 ZAB协议
3.2 数据写入
3.3 数据恢复
3.4 数据读取
4,Leader选举
4.1 服务器四种状态
4.2 启动期间leader选举
4.3 运行期间leader选举
5,Watcher机制
5.1 简介
5.2 工作机制
5.3 Watcher特性
三,Zookeeper应用场景
1,分布式锁
1.1 方式一
1.2 方式二
2,统一命名
3,配置管理
4,集群管理
文章内容来自:南京大学 / 星环科技课程,大数据理论与实践课程Ⅰ
一,ZooKeeper简介
1,什么是Zookeeper
高可用、高容错和高性能的分布式协调系统。
将复杂易错的分布式一致性服务封装起来,形成高效可靠的原语集,并提供简单易用的访问接口
为大型分布式系统提供关键、共性、高效和可靠的协调服务。
- 数据发布订阅
- 分布式锁
- 统一命名
- 配置管理
- 集群管理(Master选举、节点上下线动态监测)
大数据开源技术体系的基础组件,无可替代。开源免费、简单易用、高可用、高容错、高性能。被HDFS、YARN、Kafka和HBase等技术高度依赖
2,基本特性
最终一致性:保证数据在各节点的副本最终能够达到一致状态,这是ZK最重要的功能;
有限实时性:不能保证一定能读到最新数据,要想实时获取最新数据,应先调用sync()进行强制同步;
原子性:集群所有服务器或者都成功执行了某一事务,或者都没有,不存在第三种情况;
顺序性:从同一客户端发起的事务请求,最终会严格按照其发起顺序应用到ZK中;
可靠性:服务端一旦成功执行了事务,则该事务所引起的数据变更会被一直保留;
单一视图:无论客户端连接到哪一台服务器,所看到的数据模型都是一致的;
二,ZooKeeper原理
1,系统架构
1.1 角色分工
四种角色:Leader、Follower、Observer和Client。
1.2 设计思想
Leader和Follwer遵循“Quorum仲裁机制(过半策略)”,参与事务处理和Leader选举的投票。
若Leader+Follwer的数量为m,则Quorum = m/2 + 1,只有投票数>=Quorum,事务和选举才判定成功。
Leader+Follwer的数量最好是奇数(2n+1),在不影响事务处理的前提下,最多可容忍n台宕机
例如:对于节点数为5和6的两个集群
①二者都最多容忍2台宕机,所以容灾能力相同(quorum5=3,quorum6=4,5-3=6-4=2台);
②前者的Quorum数为3,后者为4,前者更小,事务处理和选举的效率更高
1.3 为什么要引入Observer(ZK 3.3.0)?
1,在不影响写性能的前提下,提升读操作的性能和吞吐量
- Follower数量越多,写操作的性能越差,吞吐量越小(因为Follower需要参与Quorum仲裁机制)
- Observer不参与事务处理,数量再多也不影响集群的写性能
- Observer不参与选主和事务处理,即使宕机也不影响集群的可用性
2,提升集群的可扩展性,以及大规模访问的承载能力
3,跨中心部署Observer ,为本地读请求提供快速响应
- Leader和Follower部署在一个中心,很大程度上降低了网络延时对写性能的影响
- 由于Observer要转发写请求和同步Leader状态,所以跨中心部署并不能彻底消除网络延时
- 例如:阿里开源的跨机房同步系统Otter
2,数据模型
2.1 Znode
ZK的最小数据单元
节点有数据存储功能(非数据库),大小不能超过1M
节点中的数据应尽可能小,数据过大会导致ZK性能明显下降
如果确实要存储较大的数据,可将其放在数据库中,而存储地址放在Znode中。以HBase为例,元数据放在RegionServer中,元数据的寻址入口放在ZK中。
2.2 Znode Tree
Znode通过挂载子节点而形成的一个树状层次化命名空间,结构类似于Linux文件系统,但没有目录和文件,只有节点和子节点
绝对路径(非相对路径)作为节点名称,用于唯一标识节点(主节点挂掉,其余节点竞争创建znode,由于命名唯一,且只有一个节点可以创建成功,所以可以用来选主)
根节点为“/”,非根节点为不能以“/”结尾
2.3 会话session
客户端为实现Znode读写操作而与ZK服务器建立的TCP长连接,即会话
在SessionTimeout时间内,客户端会通过心跳检测(Ping)或发送读写请求来激活和保持会话。同样,服务器要是一直未收到客户端消息,就会判定超时并关闭会话
在某一会话中,客户端请求以FIFO方式顺序执行
2.4 Znode节点类型
1,持久节点(PERSISTENT)
- 节点默认类型,生命周期不依赖于客户端会话,只有客户端执行删除操作时,节点才会消失
- 可以拥有子节点,也可以是叶节点
2,临时节点(EPHEMERAL)
- 生命周期依赖于客户端会话,当会话结束时,节点会自动删除(也可手动删除)
- 不能拥有子节点,只能是叶节点
3,顺序节点(SEQUENTIAL)
- 带顺序编号的持久或临时节点
- 创建顺序节点时,在路径后面会自动添加一个10位的节点编号(计数器),如 <path1>0000000001, <path2>0000000002, ,该编号在同一父节点下是唯一的
4,持久顺序节点(PERSISTENT_SEQUENTIAL)
5,临时顺序节点(EPHEMERAL_SEQUENTIAL)
2.5 Znode版本
Znode版本是形如0,1,2,…,N的单调递增数字,不是形如v1.2.1的软件版本
1,dataVersion(数据版本)
- 当对Znode中的数据进行更新操作时,dataVersion自增1(即使数据值未发生变化)
2,cVersion(子节点版本)
- 当Znode的子节点有变化时,cVersion自增1
3,aclVersion(ACL版本)
- 当Znode的ACL(Access Control List, 访问控制列表)发生变更时,aclVersion自增1
4,利用版本确保分布式事务操作的原子性
- 悲观锁:事务A执行期间,数据全程加锁,其他事务只能等待;适用于数据更新并发度较高的场景
- 乐观锁:事务A提交更新请求前,先检查数据是否被其他事务修改过(通过比较版本进行写入校验),如修改过,则相关事务必须回滚;适用于数据更新并发度不高的场景
2.6 Znode属性
3,数据读写
3.1 ZAB协议
Zookeeper Atomic Broadcast,ZK原子广播协议。
基于该协议,ZK实现了Master/Slave架构下集群各节点副本数据的最终一致性。
包括两种模式:正常运行时的消息广播模式、Leader故障时的崩溃恢复模式。
3.2 数据写入
SID:服务器ID。用来唯一标识一台ZooKeeper集群中的机器,每台机器不能重复,和myid一致。
ZXID:事务ID。ZXID是一个事务ID,用来标识一次服务器状态的变更。在某一时刻,集群中的每台机器的ZXID值不一定完全一致,这和ZooKeeper服务器对于客户端“更新请求”的处理逻辑有关。
Epoch:每个Leader任期的代号。没有Leader时同一轮投票过程中的逻辑时钟值是相同的。每投完一次票这个数据就会增加
1,Follwer接收客户端写请求,并将其转发给Leader
2,Leader接收写请求,为其分配一个全局唯一的事务ID,Zxid(64位/单调递增)
3,Leader生成一个形如(Zxid, data)的事务提案Proposal(data是事务体),并将其放入各Follower对应的FIFO(顺序性)队列中(通过TCP协议实现),再按照FIFO策略把Proposal广播出去
4,Follower接收Proposal后,先以事务日志的形式落盘,再向Leader发送ack
5,当Leader接收到超过半数的ack之后(包括Leader自己),会向Follower发送commit命令,要求提交事务,同时自己在本地commit
6,Follower收到commit命令后提交事务,同时向客户端反馈结果
3.3 数据恢复
(1)当Leader无法提供服务时,快速选举出一个新Leader
- 原则:在所有参选Follower中,新Leader拥有Zxid最大的已提交事务
- 确保数据最新:拥有最新的事务数据
- 确保性能最优:软硬件条件最好、数据处理能力最强
(2)Follower与新Leader同步数据
- 原则:对于某个事务,如果至少一个Follwer接收到Proposal并最终执行了commit,那么该事务数据就应该被永久保留
- 例如:如果Leader把某个Proposal广播给所有Follwer之后宕机,数据该怎么处理?数据应该丢弃,因为该条数据并没有commit,不需要(没这个义务)进行保留。
3.4 数据读取
客户端直接从Follower或Observer读取数据
如果要确保读到最新数据,应该先调用sync()进行强制同步
4,Leader选举
4.1 服务器四种状态
LOOKING:寻找Leader状态,表示当前集群没有Leader,需要进行选举
LEADING:领导者状态,当前角色为Leader
FOLLOWING:跟随者状态,Leader选举已完成,当前角色为Follower
OBSERVING:观察者状态,当前角色为Observer,不参与选举和写事务
4.2 启动期间leader选举
参考@尚硅谷教育【源码级图文详解Zookeeper选举机制_大数据培训】
1,服务器1启动,发起一次选举。服务器1投自己一票。此时服务器1票数一票,不够半数以上(3票),选举无法完成,服务器1状态保持为LOOKING;
2,服务器2启动,再发起一次选举。服务器1和2分别投自己一票并交换选票信息:此时服务器1发现服务器2的myid(SID)比自己目前投票推举的(服务器1)大,更改选票为推举服务器2。此时服务器1票数0票,服务器2票数2票,没有半数以上结果,选举无法完成,服务器1,2状态保持LOOKING
3,服务器3启动,发起一次选举。此时服务器1和2都会更改选票为服务器3。此次投票结果:服务器1为0票,服务器2为0票,服务器3为3票。此时服务器3的票数已经超过半数,服务器3当选Leader。服务器1,2更改状态为FOLLOWING,服务器3更改状态为LEADING;
4,服务器4启动,发起一次选举。此时服务器1,2,3已经不是LOOKING状态,不会更改选票信息。交换选票信息结果:服务器3为3票,服务器4为1票。此时服务器4服从多数,更改选票信息为服务器3,并更改状态为FOLLOWING;
5,服务器5启动,同4一样当小弟。
4.3 运行期间leader选举
当ZooKeeper集群中的一台服务器出现以下两种情况之一时,就会开始进入Leader选举:
- 服务器初始化启动。
- 服务器运行期间无法和Leader保持连接。
而当一台机器进入Leader选举流程时,当前集群也可能会处于以下两种状态:
- 集群中本来就已经存在一个Leader:当机器试图去选举Leader时,会被告知当前服务器的Leader信息,对于该机器来说,仅仅需要和Leader机器建立连接,并进行状态同步即可。
- 集群中确实不存在Leader:按照EPOCH-》事务ID-》服务器ID的优先级顺序进行判定选举
5,Watcher机制
5.1 简介
以下部分内容参考@Jayicee【Zookeeper中的Watcher机制到底是啥?】
watcher机制是观察者模式在分布式场景下的实现,是zookeeper一个非常核心的机制,zookeeper提供的发布/订阅,监听节点变化(如节点的删除,内容的变化,或者子节点状态的变化)等核心功能都是基于watcher机制来是是实现的。
watcher机制涉及状态的监听,而这一状态其实包含了两种:
- 客户端与服务端之间的连接状态(通知状态KeeperState)
- 节点的状态(事件类型EventType)
5.2 工作机制
1,注册Watcher监听器:客户端向ZK的某个Znode注册一个Watcher监听器
2,存储Watcher对象:客户端把Watcher对象存储到本地的WatchManager中
3,处理Watcher事件:当服务端的指定事件触发了Watcher,会向客户端发送事件通知
4,回调Watcher对象:客户端根据通知状态和事件类型回调WatchManager中的Watcher对象,执行相应的业务逻辑
5.3 Watcher特性
三,Zookeeper应用场景
1,分布式锁
1.1 方式一
1,依据
- 多个客户端同时创建同一个Znode节点(节点路径名唯一),只有一个客户端能够成功
- Watcher机制
2,步骤
- 多个客户端同时在ZK上竞争创建临时节点“/Lock”(简称Lock节点,临时节点和session捆绑,session过期会自动删除,避免死锁) ,创建成功的客户端获得锁,并执行事务
- 其他客户端注册Watcher监听器,监听Lock节点
- 事务完成后,获得锁的客户端会删除Lock节点,释放锁,同时触发Watcher,通知其他客户端
- 其他客户端再次竞争创建Lock节点
3,缺点
- 产生羊群效应,即当锁被释放后,如果抢占锁资源的竞争
- 客户端太多,势必会影响性能
1.2 方式二
1,依据
- 临时顺序节点
- Watcher机制
2,步骤
- 客户端在永久节点“/Lock”下创建临时顺序子节点,第一个客户端创建的子节点为“/Lock/Lock- 0”,第二个为“/Lock/Lock-1”,以此类推
- 客户端获取Lock节点的子节点列表,判断其创建的子节点的序号是否最小,如果是则获得锁,否则就监听序号排在其前一位的子节点
- 锁释放后,对应的子节点被删除,该节点序号后一位的子节点得到通知,重复步骤②直至获得锁
2,统一命名
服务统一命名
- 类似于JNDI(JNDI,The Java Naming and Directory Interface,Java命名和目录接口。是一组在Java应用中访问命名和目录服务的API。命名服务将名称和对象联系起来,使得我们可以用名称访问对象。目录服务是一种命名服务,在这种服务里,对象不但有名称,还有属性),记录域名与IP之间的对应关系,域名作为访问入口
- 按照Znode Tree层次结构组织服务名称
- 将服务的地址、目录和提供者等信息存入Znode,通过服务名称来获取相关信息
全局唯一ID
- UUID虽然可以保证分布式环境下的编号唯一,但缺点是无序、存储空间大和查询效率低
- 利用Znode顺序节点,可以实现分布式环境下的编号生成器(ID生成器)
3,配置管理
分布式环境下的配置信息同步
- 集群中所有节点的配置信息需保持一致
- 配置信息修改后,应快速同步到其他节点上
利用Znode和Watcher实现统一配置管理
- 将配置信息写入Znode
- 各节点监听Znode,一旦Znode的数据被修改,将通知各节点进行更新
4,集群管理
实时掌握分布式系统中各节点的状态是集群管理的前提和基础
利用Znode和Watcher实现集群管理
1,将节点的状态信息写入Znode,利用Watcher监听Znode,以获取节点的实时状态变化
2,节点上下线动态监测
- 新节点启动后,先在ZK中创建临时顺序Znode,这时会触发父节点上的监听器,并通知集群管理节点Master有新节点上线
- 节点发生故障,失去与ZK的心跳连接,它创建的临时顺序Znode被自动删除,这时会触发父节点上的监听器,并通知Master节点下线
3,Master选举(ZooKeeper提供的选举机制,和ZooKeeper本身的选举机制不同)
- 如果Master节点宕机,失去与ZK的心跳连接,那么它创建的临时Znode被自动删除,这时会触发该节点的Watcher,并通知所有Standby节点去竞争创建临时Znode
- 成功创建临时Znode的Standby节点成为新的Master
- 其他Standby节点在该Znode上注册监听器,等待下一次选举