Hadoop系列(四)—— 人民法官 Zookeeper 详解

2023-10-29 09:20

本文主要是介绍Hadoop系列(四)—— 人民法官 Zookeeper 详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

ZooKeeper是Google的Chubby提供的一个开源的、分布式的框架,它是Hadoop集群的管理者,同时提供一致性协调服务,就像“人民法官”一样监视着集群中各个节点的状态根据节点提交的反馈进行下一步合理操作。最终实现将简单易用的接口和性能高效、功能稳定的系统提供给用户的功能。

Zookeeper主要负责存储和管理大家都关心的数据,一旦这些数据的状态发生变化,Zookeeper就会通知那些注册在Zookeeper上的服务。简单来讲就是**zookeeper=文件系统+通知机制**。

Zookeeper的数据结构

Zookeeper的数据结构与Unix文件系统很类似,整体上可以看作是一棵树,我们能够自由的增加、删除znode,在一个znode下增加、删除子znode,与Unix文件系统唯一不同的是Zookeeper的每个节点都可以存放数据,每个节点称作一个ZNode,默认存储1MB的数据, 可以通过配置修改, 通常不建议在ZNode上存储大量的数据。Znode的引用方式是路径的引用,每个ZNode都可以通过其路径唯一标识

在这里插入图片描述

四种类型的ZNode

  • 持久化目录节点(ERSISTENT):客户端与Zookeeper断开连接后,该节点依旧存在。

  • 持久化顺序编号目录节点(PERSISTENT_SEQUENTIAL):客户端与Zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号。

  • 临时目录节点(EPHEMERAL):客户端与Zookeeper断开连接后,该节点被删除。

  • 临时顺序编号目录节点(EPHEMERAL_SEQUENTIAL):客户端与Zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号。

说明:创建ZNode时设置顺序标识,ZNode名称后会附加一个值,顺序号是一个单调递增的计数器,由父节点维护。

具体如下:
在这里插入图片描述

stat结构体

stat 查看根目录的详细信息:

[zk: localhost:2181(CONNECTED) 0] stat /
cZxid = 0x0
ctime = Thu Jan 01 08:00:00 CST 1970
mZxid = 0x0
mtime = Thu Jan 01 08:00:00 CST 1970
pZxid = 0x0
cversion = -1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 1

如上所述,ZNode主要包含以下信息:

  • czxid-创建节点的事务 zxid:每次修改 ZooKeeper 状态都会收到一个 zxid 形式的时间戳,也就是 ZooKeeper 事务 ID。事务 ID 是 ZooKeeper 中所有修改总的次序。每个修改都有唯一的 zxid,如果 zxid1 小于 zxid2,那么 zxid1 在 zxid2 之前发生。

  • ctime :znode 被创建的毫秒数(从 1970 年开始)

  • mzxid:znode 最后更新的事务 zxid

  • mtime:znode 最后修改的毫秒数(从 1970 年开始)

  • pZxid:znode 最后更新的子节点 zxid

  • cversion:znode 子节点变化号,znode 子节点修改次数

  • dataversion:znode 数据变化号

  • aclVersion:znode 访问控制列表的变化号

  • ephemeralOwner:如果是临时节点,这个是 znode 拥有者的 session id。如果不是临时节点则是 0

  • dataLength:znode 的数据长度

  • numChildren:znode 子节点数量

Zookeeper的应用场景

Zookeeper的主要应用场景有统一命名服务,统一配置管理,统一集群管理,服务器节点动态上下线等。

统一命名服务

在zookeeper的文件系统里创建一个目录,即有唯一的path。在我们使用tborg无法确定上游程序的部署机器时即可与下游程序约定好path,通过path即能互相探索发现。

举个例子来说:在分布式环境中,经常需要对服务进行统一命名,假如有一个服务部署了两个副本,直接调用具体的服务肯定有些不合适,因为我们并不清楚哪个服务可以更快的处理我们的请求,这时候我们可以将这三个服务进行统一命名,然后其内部再去负载调用。这样就可以调用最优的那个服务了。
在这里插入图片描述

统一配置管理

程序总是需要配置的,如果程序分散部署在多台机器上,要逐个改变配置就变得困难。现在把这些配置全部放到zookeeper上去,保存在 Zookeeper 的某个目录节点中,然后所有相关应用程序对这个目录节点进行监听,一旦配置信息发生变化,每个应用程序就会收到 Zookeeper 的通知,然后从 Zookeeper 获取新的配置信息应用到系统中就好。

分布式环境下,配置文件的同步可以由Zookeeper来实现具体步骤如下:

  1. 将配置文件写入Zookeeper的一个ZNode

  2. 各个客户端服务监听这个ZNode

  3. 一旦ZNode发生改变,Zookeeper将通知各个客户端服务

在这里插入图片描述

统一集群管理

Zookeeper可以实现实时监控节点状态变化。所有服务节点约定在父目录GroupMembers下创建临时目录节点,然后监听父目录节点的子节点变化消息,当三个节点的服务有一个假如死机了,其他两个节点可立即收到消息,实现实时监控。将这三个节点写入Zookeeper的一个ZNode,每个节点都去监听这个ZNode,当ZNode发生变化时,这些节点可实时收到变化状态,这个节点ZNode通常为主机master。

新服务节点加入也是一样,所有其他节点收到通知:新节点目录加入。所有其他节点创建临时顺序编号目录节点,每次选取编号最小的机器作为master就好。

在这里插入图片描述

监听器的原理

在这里插入图片描述

  1. 创建一个Main()线程

  2. 在Main()线程中创建两个线程,一个负责网络连接通信(connect),一个负责监听(listener)

  3. 通过connect线程将注册的监听事件发送给Zookeeper

  4. 将注册的监听事件添加到Zookeeper的注册监听器列表中

  5. Zookeeper监听到有数据或路径发生变化时,把这条消息发送给Listener线程

  6. Listener线程内部调用process()方法

Zookeeper分布式锁

有了zookeeper的一致性文件系统,锁的问题变得容易。锁服务可以分为两类,一个是保持独占,另一个是控制时序。

对于第一类,我们将Zookeeper上的一个ZNode看作是一把锁,通过createznode的方式来实现。所有客户端都去创建 /distribute_lock 节点,最终成功创建的那个客户端也即拥有了这把锁。用完删除掉自己创建的distribute_lock 节点就释放出锁。

对于第二类, /distribute_lock 已经预先存在,所有客户端在它下面创建临时顺序编号目录节点,和选master一样,编号最小的获得锁,用完删除,依次方便。

Zookeeper队列管理

两种类型的队列:

1、同步队列,在约定目录下创建临时目录节点,监听节点数目是否是我们要求的数目。当一个队列的成员都聚齐时,这个队列才可用,否则一直等待所有成员到达。

2、队列按照 FIFO 方式进行入队和出队操作。 和分布式锁服务中的控制时序场景基本原理一致,入列有编号,出列按编号。

分布式与数据复制

Zookeeper作为一个集群提供一致的数据服务,自然,它要在所有机器间做数据复制。数据复制的好处:

1、容错:一个节点出错,不致于让整个系统停止工作,别的节点可以接管它的工作;

2、提高系统的扩展能力 :把负载分布到多个节点上,或者增加节点来提高系统的负载能力;

3、提高性能:让客户端本地访问就近的节点,提高用户访问速度。

从客户端读写访问的透明度来看,数据复制集群系统分下面两种:

1、写主(WriteMaster) :对数据的修改提交给指定的节点。读无此限制,可以读取任何一个节点。这种情况下客户端需要对读与写进行区别,俗称读写分离;

2、写任意(Write Any):对数据的修改可提交给任意的节点,跟读一样。这种情况下,客户端对集群节点的角色与变化透明。

对zookeeper来说,它采用的方式是写任意。通过增加机器,它的读吞吐能力和响应能力扩展性非常好,而写,随着机器的增多吞吐能力肯定下降(这也是它建立observer的原因),而响应能力则取决于具体实现方式,是延迟复制保持最终一致性,还是立即复制快速响应。

Zookeeper集群

Zookeeper集群虽然没有指定Master和Slave。但是,在Zookeeper工作时,会通过内部选举机制产生一个Leader节点,其他节点为Follower或者是Observer。

在这里插入图片描述

被声明为Observer的节点,不参与选举过程,也不参与写操作的”过半写成功“策略。

过半写成功策略:Leader节点接收到写请求后,这个Leader会将写请求广播给各个server,各个server会将该写请求加入待写队列,并向Leader发送成功信息,当Leader收到一半以上的成功消息后,说明该写操作可以执行。Leader会向各个server发送提交消息,各个server收到消息后开始写。

Follower和Observer只提供数据的读操作,当他们接收的写请求时,会将该请求转发给Leader节点。

集群中只要有半数以上的节点存活,Zookeeper集群就能正常服务。因此Zookeeper集群适合安装奇数台机器。

当leader崩溃或者leader失去大多数的follower,这时候zk进入恢复模式,恢复模式需要重新选举出一个新的leader,让所有的Server都恢复到一个正确的状态。Zk的选举算法有两种:一种是基于basic paxos实现的,另外一种是基于fast paxos算法实现的。系统默认的选举算法为fast paxos。

选举机制

Zookeeper集群是一主多从的模式,主为leader,从为follower,其中leader是通过选举得到。具体如下:

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

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

(3)服务器 3 启动,发起一次选举。此时服务器 1 和 2 都会更改选票为服务器 3。此次投票结果:服务器 1 为 0 票,服务器 2 为 0 票,服务器 3 为 3 票(这只是本次的投票结果,算上之前的2步结果:服务器 1 为 2 票,服务器 2 为 2 票,服务器 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 一样当小弟。

此外,Zookeeper集群有如下特点:

  • Zookeeper:一个领导者(leader),多个跟随者(follower)组成的集群
  • Leader负责进行投票的发起和决议,更新系统状态
  • Follower用于接收客户请求并向客户端返回结果,在选举Leader过程中参与投票
  • 集群中只要有半数以上节点存活,Zookeeper集群就能正常服务,所以Zookeeper适合安装奇数台服务器
  • 全局数据一致:每个server保存一份相同的数据副本,client无论连接到哪个server,数据都是一致的
  • 更新请求顺序进行,来自同一个client的更新请求按其发送顺序依次执行
  • 数据更新原子性,一次数据更新要么成功,要么失败
  • 实时性,在一定时间范围内,client能读到最新数据

参考文章

Paxos 一致性算法

Zookeeper 原理

这篇关于Hadoop系列(四)—— 人民法官 Zookeeper 详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/299700

相关文章

Python使用Tenacity一行代码实现自动重试详解

《Python使用Tenacity一行代码实现自动重试详解》tenacity是一个专为Python设计的通用重试库,它的核心理念就是用简单、清晰的方式,为任何可能失败的操作添加重试能力,下面我们就来看... 目录一切始于一个简单的 API 调用Tenacity 入门:一行代码实现优雅重试精细控制:让重试按我

Python标准库之数据压缩和存档的应用详解

《Python标准库之数据压缩和存档的应用详解》在数据处理与存储领域,压缩和存档是提升效率的关键技术,Python标准库提供了一套完整的工具链,下面小编就来和大家简单介绍一下吧... 目录一、核心模块架构与设计哲学二、关键模块深度解析1.tarfile:专业级归档工具2.zipfile:跨平台归档首选3.

idea的终端(Terminal)cmd的命令换成linux的命令详解

《idea的终端(Terminal)cmd的命令换成linux的命令详解》本文介绍IDEA配置Git的步骤:安装Git、修改终端设置并重启IDEA,强调顺序,作为个人经验分享,希望提供参考并支持脚本之... 目录一编程、设置前二、前置条件三、android设置四、设置后总结一、php设置前二、前置条件

python中列表应用和扩展性实用详解

《python中列表应用和扩展性实用详解》文章介绍了Python列表的核心特性:有序数据集合,用[]定义,元素类型可不同,支持迭代、循环、切片,可执行增删改查、排序、推导式及嵌套操作,是常用的数据处理... 目录1、列表定义2、格式3、列表是可迭代对象4、列表的常见操作总结1、列表定义是处理一组有序项目的

python使用try函数详解

《python使用try函数详解》Pythontry语句用于异常处理,支持捕获特定/多种异常、else/final子句确保资源释放,结合with语句自动清理,可自定义异常及嵌套结构,灵活应对错误场景... 目录try 函数的基本语法捕获特定异常捕获多个异常使用 else 子句使用 finally 子句捕获所

C++11范围for初始化列表auto decltype详解

《C++11范围for初始化列表autodecltype详解》C++11引入auto类型推导、decltype类型推断、统一列表初始化、范围for循环及智能指针,提升代码简洁性、类型安全与资源管理效... 目录C++11新特性1. 自动类型推导auto1.1 基本语法2. decltype3. 列表初始化3

SQL Server 中的 WITH (NOLOCK) 示例详解

《SQLServer中的WITH(NOLOCK)示例详解》SQLServer中的WITH(NOLOCK)是一种表提示,等同于READUNCOMMITTED隔离级别,允许查询在不获取共享锁的情... 目录SQL Server 中的 WITH (NOLOCK) 详解一、WITH (NOLOCK) 的本质二、工作

springboot自定义注解RateLimiter限流注解技术文档详解

《springboot自定义注解RateLimiter限流注解技术文档详解》文章介绍了限流技术的概念、作用及实现方式,通过SpringAOP拦截方法、缓存存储计数器,结合注解、枚举、异常类等核心组件,... 目录什么是限流系统架构核心组件详解1. 限流注解 (@RateLimiter)2. 限流类型枚举 (

Java Thread中join方法使用举例详解

《JavaThread中join方法使用举例详解》JavaThread中join()方法主要是让调用改方法的thread完成run方法里面的东西后,在执行join()方法后面的代码,这篇文章主要介绍... 目录前言1.join()方法的定义和作用2.join()方法的三个重载版本3.join()方法的工作原

Spring AI使用tool Calling和MCP的示例详解

《SpringAI使用toolCalling和MCP的示例详解》SpringAI1.0.0.M6引入ToolCalling与MCP协议,提升AI与工具交互的扩展性与标准化,支持信息检索、行动执行等... 目录深入探索 Spring AI聊天接口示例Function CallingMCPSTDIOSSE结束语