栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 前沿技术 > 大数据 > 大数据系统

Zookeeper整理

Zookeeper整理

文章目录

1. ZK 概述

1.1. ZK 数据结构1.2. ZK 特点1.3. ZK 应用场景

1.3.1. 统一命名服务1.3.2. 统一配置管理1.3.3. 统一的集群管理1.3.4. 服务器动态上下线1.3.4. 软负载均衡 2. ZK 组成

2.1. ZK 服务节点2.2. ZK 客户端2.3. ZK Znode节点2.4. 监听器

2.4.1. Watch 监听点2.4.2. 监听机制2.4.3. 监听注意事项 2.5. ZK 端口 3. ZK 选举机制

3.1. 首次启动3.2. 非首次启动 4. ZK 同步机制

4.1. 消息广播4.2. 奔溃恢复4.3. ZK客户端数据同步 5. ZK 与 客户端通信

5.1. 客户端对ZooKeeper的ServerList的轮询机制5.2. 客户端如何正确处理 连接断开(CONNECTIONLOSS) 和 会话过期(SESSIONEXPIRED) 两类连接异常?


1. ZK 概述

Zookeeper 是一个开源的分布式的,为分布式框架提供协调服务的 Apache 项目。

从结构上来看,Zookeeper是一个具有树型目录的数据存储服务,通常被用来用作分布式场景下的服务治理。

从设计模式角度来看,Zookeeper是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理分布式集群的元信息,然后接受观察者的注册,监控这些数据的状态发生变化,Zookeeper就将负责通知已经在Zookeeper上注册的那些观察者做出相应的反应。

1.1. ZK 数据结构

ZooKeeper 数据模型的结构与 Unix 文件系统很类似,整体上可以看作是一棵树,每个节点称做一个 ZNode。每一个 ZNode 默认存储 1MB 的数据,每个 ZNode 的唯一标识为路径。

1.2. ZK 特点
    Zookeeper:一个领导者(Leader),多个跟随者(Follower)组成的集群。数据更新原子性,一次数据更新要么成功,要么失败。全局数据一致:每个Server保存一份相同的数据副本,Client无论连接到哪个Server,数据都是一致的(最终一致,对实时性要求高的,需要先调用 sync( ),再调用 getData( ))。实时性,在一定时间范围内,Client能读到最新数据(对实时性要求高的,需要先调用 sync( ),再调用 getData( ))。容灾性:半数以上节点存活,Zookeeper集群就能正常服务,建议安装奇数台ZK服务器。更新请求顺序执行,来自同一个Client的更新请求按其发送顺序依次执行。
1.3. ZK 应用场景

​ ZK提供的服务:统一命名服务、统一配置管理、统一集群管理、服务器节点动态上下线、软负载均衡等。

1.3.1. 统一命名服务

在分布式环境下,经常需要对应用/服务进行统一命名,便于识别。例如:IP不容易记住,而域名容易记住,和 ngnix 不同,zookeeper 一般被用来做内部服务的命令,而 ngnix 主要为服务做反向代理,为外部请求提供转发服务。

1.3.2. 统一配置管理

    分布式环境下,配置文件同步非常常见,ZK还可以实现动态配置。

    配置管理可交由ZooKeeper实现。

      可将配置信息写入ZooKeeper上的一个Znode。各个客户端服务器监听这个Znode。一 旦Znode中的数据被修改,ZooKeeper将通知各个客户端服务器。
1.3.3. 统一的集群管理

    分布式环境中,实时掌握每个节点的状态是必要的,ZK 的好处在于可根据节点实时状态做出一些调整。

    ZooKeeper可以实现实时监控节点状态变化,步骤:

      可将集群节点信息写入ZooKeeper上的一个ZNode。Manager监听这个ZNode可获取它的实时状态变化。
1.3.4. 服务器动态上下线

    服务端节点启动时去注册信息,创建临时节点,并且与ZK维护一个长轮询。ZK客户端(一般是服务集群Manager)获取到当前在线服务器列表,并且注册监听。服务器节点下线,ZK长轮询无响应,临时节点删除。临时节点删除,ZK将服务器节点下线的消息,通知给ZK客户端,即服务集群Manager。ZK客户端,即服务集群Manager 会执行 ZK客户端回掉函数 process( ),停止该服务节点请求转发。
1.3.4. 软负载均衡

在Zookeeper中记录每台服务器的访问数,让访问数最少的服务器去处理最新的客户端请求。

2. ZK 组成 2.1. ZK 服务节点

提供ZK服务

2.2. ZK 客户端

与 ZK 集群通信,注册或者接受 ZK 监听事件,会产生两个线程,一个负责网络连接通信(connet),一个负责监听(listener)。

2.3. ZK Znode节点

    持久节点(Persistent):

    客户端和服务器端断开连接后,创建的节点不删除,实时性较低,但是可以创建子节点,临时节点无法做到,如保存整个集群信息的节点为持久节点。

    持久化顺序编号目录节点( Persistent_sequential):

    客户端与Zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号。

    临时节点(Ephemeral):

    客户端和服务器端断连后,创建的节点自己删除,特点是实时性较高,常被用于服务集群节点注册。

    临时顺序编号目录节点

    客户端与 Zookeeper 断开连接后 ,该节点被删除 , 只是Zookeeper给该节点名称进行顺序编号。常被用于 Zoookeeper 实现分布式锁:需要获取锁的节点都注册一个 临时顺序编号目录节点,排名第一的获得锁,好处在于临时顺序可排序,自己删除避免死锁,比如框架 Curator。

    Znode 可以有版本,即一个Znode可以保存多份状态。

2.4. 监听器 2.4.1. Watch 监听点

一个Watch事件是一个一次性的触发器,当被设置了Watch的数据发生了改变的时候,则服务器将这个改变发送给设置了Watch的客户端,以便通知它们。

Watch之所以不是永久性监控,是因为如果服务端变动频繁,而监听的客户端很多情况下,每次变动都要通知到所有的客户端,这太消耗性能了。

在实际应用中,很多情况下,我们的客户端不需要知道服务端的每一次变动,只要最新的数据即可。

2.4.2. 监听机制

客户端注册监听它关心的目录节点,当目录节点发生变化(数据改变、节点删除、子目录节点增加删除)时,ZooKeeper 会通知客户端。监听机制保证 ZooKeeper 保存的任何的数据的任何改变都能快速的响应到监听了该节点的应用程序。具体流程如下:

    Zookeeper客户端会创建两个线程,一个负责网络连接通信(connet),一个负责监听(listener)。通过connect线程将注册的监听事件发送给Zookeeper。在Zookeeper的注册监听器列表中将注册的 客户端地址 以及 监听事件添加到列表中 。Zookeeper监听到有数据或路径变化,会将这个消息发送给 ZK 客户端listener线程。listener线程内部调用了回调函数 process( ) 方法。
2.4.3. 监听注意事项
    Watches通知是一次性的,欲实现长期监控,必须重复注册监听点。发生connnectionLoss之后,只要在session_timeout之内再次连接上, 那么这个连接注册的watches依然在。节点数据的版本变化会触发NodeDataChanged,注意,这里特意说明了是版本变化。存在这样的情况。只要成功执行了setData()方法,无论内容是否和之前一致,都会触发NodeDataChanged。对某个节点注册了watch,当节点被删除,那么注册在这个节点上的watches都会被移除,无法再监听。同一个zk客户端对某一个节点注册相同的watch,只会收到一次通知。Watcher对象只会保存在客户端,不会传递到服务端。如果节点更新频率过高,高到上一次监听事件触发完,下一个监听点还没注册就已经更新,则无法监听到节点更新。算是个缺点。
2.5. ZK 端口
    2181:ZK 对外提供服务的端口。2888:Follower与Leader交换信息的端口。3888:执行选举时服务器相互通信的端口。
3. ZK 选举机制

概念:

    SID:服务器ID。用来唯一标识一台ZooKeeper集群中的机器,每台机器不能重复,和myid一致。ZXID:事务ID。ZXID是一个事务ID,用来标识一次服务器状态的变更。在某一时刻,集群中的每台机器的ZXID值不一定完全一致,这和ZooKeeper服务器对于客户端“更新请求”的处理逻辑有关。Epoch:每个Leader任期的代号。没有Leader时同一轮投票过程中的逻辑时钟值是相同的。每投完一次票这个数据就会增加。
3.1. 首次启动

    服务器1启 动,发起一次选举。服务器1投自己一票。此时服务器1票数一票,不够半数以上(3票),选举无法完成,服务器1状态保持为LOOKING。

    服务器2启动,再发起一次选举。服务器1和2分别投自己一票并交换选票信息:此时服务器1发现服务器2的myid比自己目前投票推举的(服务器1) 大,更改选票为推举服务器2。此时服务器2票数2票,没有半数以上结果,选举无法完成,服务器1,2状态保持LOOKING。

    服务器3启动,发起一次选举。此时服务器1和2都会更改选票为服务器3,此时服务器3为3票。此时服务器3的票数已经超过半数,服务器3当选Leader。服务器1,2更改状态为FOLLOWING,服务器3更改状态为LEADING。

    服务器4启动,发起一次选举。此时服务器1,2,3已经不是LOOKING状态,不会更改选票信息。交换选票信息结果:服务器3为3票,服务器4为 1票。此时服务器4服从多数,更改选票信息为服务器3,并更改状态为FOLLOWING。

    服务器5启动,同4一样当小弟。

总结:

当集群半数以上节点启动时,刚超半数启动的那个节点启动完成后,集群会产生 leader,并且为此时 SID 最大的节点。

3.2. 非首次启动

当运行时的ZK集群,现役 Leader 宕机下线,导致集群无法正常工作,此时也需要进行新的 Leader 选举,以提供正常服务,提供集群容灾性。

集群中本来就已存在Leader。
对于第一种已经存在Leader的情况,机器试图去选举Leader时,会被告知当前服务器的Leader信息,对于该机器来说,仅仅需要和Leader机器建立连接,并进行状态同步即可。集群中确实不存在 Leader。

    EPOCH大的直接胜出。

    优先选择任期次数最多的节点,任期次数越多说明他的稳定性越好。

    EPOCH相同,事务ZXID大的胜出。

    事务ZXID越大的节点,越可能拥有旧 Leader 宕机前最后一次事务操作的数据。详见 [ZK同步机制](#4. ZK 同步机制)。如果上次事务未完成,新任 Leader 可以继续处理。

    事务id相同,服务器id大的胜出

    都相同,那么可以随机挑选一个节点,默认挑选服务器SID大的节点,与首次同步保持一致。

4. ZK 同步机制

在 Zookeeper 中,主要依赖 ZAB 原子广播协议来实现分布式数据一致性。

ZAB 原子协议协议分为两部分:消息广播 和 崩溃恢复。

4.1. 消息广播

ZAB原子广播协议的消息广播阶段,其实是使用类似 2PC 两阶段提交的方式保证 客户端写请求 的事务性。

    Client 的所有写请求都发送给 Leader,即使最开始找到的是某个 Follower 节点,还是会转发给 Leader。Leader 收到写请求转发后,先为写请求 提交事务提议,这也是第一阶段提交。Leader 将写请求转发给所有Follower,每个 Follower 处理完写请求后,向 Leader 提交完成的ACK反馈。Leader 收到 过半的Follower的Commit的ACK反馈后,为本次写请求 提交Commit信息,即第二阶段提交。完成第二阶段提交的写请求,认为写请求成功。但是过半反馈成功不代表全部,所有仍然存在短暂的数据不一致。如果对数据一致性要求高的场景,可以先调用 sync( )手动同步,再获取数据 getData()。Leader 讲写请求完成的消息,发送给 Client 或者 转发者Follower,完成消息广播。

ZK为了保证写请求数据一致,采用的ZAB原子广播协议,有2PC两阶段提交特性,并且如果写失败还要进行回滚,这对性能的消耗是很大的,而且ZK集群越大,需要同步的节点就越多,性能消耗越大,可能就成为性能瓶颈。

为了突破ZAB原子广播协议导致的写请求性能瓶颈,ZK集群出现新角色 Obsever。

Observer 就是一个 观察者角色服务器,它的作用和 Follower 几乎别无二致,都是对 Client 提供 读请求的服务器,所以 Follower 加 Observer 合称 Learner。不同点在于 Observer 不参与原子广播即事务操作以及选举,而是只在事务完成后同步数据。Observer 就可以在 Leader 和 Follower 参与事务的时候,对外提供读请求,提高性能。

4.2. 奔溃恢复

在正常情况消息广播情况下能运行良好,但是一旦 Leader 服务器崩溃,或者由于网络原理导致 Leader 服务器失去了与过半 Follower 的通信,那么就会进入崩溃恢复模式,需要选举出一个新的 Leader 服务器。在这个过程中可能会出现两种数据不一致性的隐患,需要 ZAB 协议的特性进行避免。

    Leader 服务器将消息 commit 发出后,立即崩溃Leader 服务器刚提出 提议proposal 即广播后,立即崩溃

ZAB 协议的恢复模式使用了以下策略:

    选举 zxid 最大的节点作为新的 leader,这是为了保证拥有上一次事务的日志记录。新 leader 将事务日志中尚未提交的消息进行处理。
4.3. ZK客户端数据同步

由于当集群中有过半的Follower 服务器更新数据成功后,Leader 就 Commit 这次更新数据的事务,所以会存在一个ZK客户端写完,另外一个客户端读的时候,读取到的是旧数据(正好是还没写完的ZK节点)。如果对实时性要求很高的场景,可以手动同步 sync(),再 获取数据 getData()。

5. ZK 与 客户端通信 5.1. 客户端对ZooKeeper的ServerList的轮询机制

客户端的创建可以使用多参构造器 new ZooKeeper(String connectString, int sessionTimeout, Watcher watcher),其中 connectString 可以设置ZK的serverList,如192.168.1.1:2181,192.168.1.2:2181。

这样设置的 serverList,ZK客户端通过随机机制选取ZK服务节点,也可以通过重复节点来达到类似加权的效果,如 192.168.1.1:2181,192.168.1.1:2181,192.168.1.2:2181。

但是,这样会有风险,即 192.168.1.1:2181 掉线时候,ZK客户端可能多次尝试连接到掉线的服务节点,那么耗尽本次 SessionTime,即发生 SessionTimeOut 导致无法连接的概率也会升高。

5.2. 客户端如何正确处理 连接断开(CONNECTIONLOSS) 和 会话过期(SESSIONEXPIRED) 两类连接异常?

在ZooKeeper中,服务器和客户端之间维持的是一个长连接,在 SESSION_TIMEOUT 时间内,服务器会确定客户端是否正常连接(客户端会定时向服务器发送heart_beat),服务器重置下次SESSION_TIMEOUT时间。因此,在正常情况下,Session一直有效,并且zk集群所有机器上都保存这个Session信息。在出现问题的情况下,客户端与服务器之间连接断了(客户端所连接的那台zk机器挂了,或是其它原因的网络闪断),这个时候客户端会主动在地址列表(初始化的时候传入构造方法的那个参数connectString)中选择新的地址进行连接。

以上即为服务器与客户端之间维持长连接的过程,在这个过程中,用户可能会看到两类异常 CONNECTIONLOSS(连接断开) 和SESSIONEXPIRED(Session 过期)。

发生 ConNECTIONLOSS 后,此时用户不需要关心我的会话是否可用,应用所要做的就是等待客户端自动连接上新的zk机器,一旦成功连接上新的zk机器后,确认之前的操作是否执行成功了。

如果超过Session有效期,ZK会将当前 Session 的所有信息,包括临时节点和注册的监视点Watcher全部删除掉,那么下次ZK客户端拿着就SessionId给ZK服务端,就会触发expired事件,并抛出异常。这时候需要重新创建ZK客户端,重新与ZK服务端建立连接。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/751361.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号