一、zookeeper概述
ZooKeeper概念: Zookeeper是一个分布式协调服务的开源框架。本质上是一个分布式的小文件存储系统
ZooKeeper作用: 主要用来解决分布式集群中应用系统的一致性问题。
ZooKeeper结构: 采用树形层次结构,ZooKeeper树中的每个节点被称为—Znode。且树中的每个节点可以拥有子节点
二、zookepper集群安装部署
使用之前创建的hadoop用户完成操作
2.1.上传zookepper压缩包解压
zookeeper-3.4.6.tar.gz解压,注意:上传文件位置为 /export/server目录
node1:
登录后复制
cd /export/server
tar -xf /export/server/zookeeper-3.4.6.tar.gz
mv zookeeper-3.4.6 zookeeper
2.2.添加环境变量
把/export/server同步到其他所有(node1、node2)的机器上,针对其他的两台机器也要进行环境变量配置。
登录后复制
[root@node1 ~] # scp -r /export/server/zookeeper root@node2:/export/server/
[root@node1 ~] # scp -r /export/server/zookeeper root@node3:/export/server/
node1/node2/node3均需要配置环境变量:
登录后复制
echo 'export ZOOKEEPER_HOME=/export/server/zookeeper' >> /etc/profile
echo 'export PATH=$PATH:$ZOOKEEPER_HOME/bin' >> /etc/profile
source /etc/profile
如果配置完成后,查看环境变量是否配置成功
登录后复制
echo $PATH
2.3.创建数据目录并配置myid编号
node1:
登录后复制
mkdir -p /export/data/zkdata
echo 1 > /export/data/zkdata/myid
node2:
登录后复制
mkdir -p /export/data/zkdata
echo 2 > /export/data/zkdata/myid
node3:
登录后复制
mkdir -p /export/data/zkdata
echo 3 > /export/data/zkdata/myid
下面设置完成后需要让hadoop用户有/export/data/目录的权限,所以node1、node2、node3分别设置:
登录后复制
chmod -R 777 /export/data/
2.4.修改配置文件
注意:在Linux操作系统中,几乎所有软件都有配置
node1/node2/node3均需要如下设置:
登录后复制
mv /export/server/zookeeper/conf/zoo_sample.cfg /export/server/zookeeper/conf/zoo.cfg
sed -i "s#^dataDir.*#dataDir=/export/data/zkdata#" /export/server/zookeeper/conf/zoo.cfg
# 配置2n+1个节点
echo 'server.1=node1:2888:3888' >> /export/server/zookeeper/conf/zoo.cfg
echo 'server.2=node2:2888:3888' >> /export/server/zookeeper/conf/zoo.cfg
echo 'server.3=node3:2888:3888' >> /export/server/zookeeper/conf/zoo.cfg
说明:
- 在zookeeper集群中所有节点都会开启3888端口,3888端口用来leader发生故障时,投票选举出新的leader。
- 所有节点都会与其它节点的3888端口建立TCP连接
- 但只有leader才会开启2888端口,其它节点都会与leader2888端口建立TCP连接, 其主要功能是接收其它follwoer和observer节点发送过来的写事务并执行。
- 另外要注意:Zookeeper客户端连接端口为2181,客户端只有通过2181才能连接到Zookeeper集群。
2.5.zookeeper服务操作
在启动之前需要在node1、node2和node3的zookeeper/bin目录有权限
登录后复制
chmod -R 777 /export/server/zookeeper/bin
注意启动时需要三台机器都执行启动服务
登录后复制
# 启动
zkServer.sh start
# 停止
zkServer.sh stop
# 查看状态
zkServer.sh status
node1/node2/node3:
登录后复制
zkServer.sh start
2.6.查看运行的java服务
登录后复制
jps
...
10622 QuorumPeerMain => Zookeeper进程名称
查看节点状态,到底是leader领导者角色,还是follower追随者角色
登录后复制
zkServer.sh status
2.7.zookeeper中角色和应用
zookeeper分布式协调服务角色分别为:
- leader: 管理者 ,负责管理follower,处理所有的事务请求(数据的保存,修改,删除)
- follower: 追随者,负责选举(选举leader)和数据的同步及获取
- observer: 观察者,负责数据的同步及获取(需要在配置文件中指定才能生效)
zookeeper应用: 搭建hadoop高可用环境时,至少需要两个hadoop服务(NameNode和ResourceManager),一主一备,主服务对外提供业务功能,备用服务等待主服务不可用时,启用备用服务器对外提供业务功能
2.8.zookeeper集群选举
选举要求: 过半原则,所以搭建集群一般奇数,只要某个node节点票数过半立刻成为leader
假设一共有5台服务器 (2n+1)用于搭建ZK服务器的集群,需要记住的知识点:
- myid代表服务器编号,每一个台服务器的myid编号都是唯一的
- zxid代表全局事务编号,每次对服务器进行增、删、改操作时,此编号都会进行+1操作,所以将来我们可以通过zxid编号来区分数据的同步情况 (新l旧)。例如:某台服务器的zxid = 6,另外一台服务器的zxid = 7,则代表zxid=7这台服务器同步的数据相对于另外一台zxid=6服务器,数据要更新,所以将来选举时,优先推荐zxid=7的服务器,注意:如果zk集群时新搭建的,则zxid默认都0
如何实现ZK选举机制,选出Leader领导者
⑴.集群第一次启动
第一种情况:首次启动,目前集群中没有产生过leader领导者
- 由于所有服务器都是按顺序启动的,所以先启动第1台服务器,然后开始第一轮投票,但是由于只有一个节点,只能自己投票给自已,然后进行广播告诉其他服务器自己的票数,但是由于只有1台机器<zk集群节点数的一半 (没有过半),则第1轮投票失败。等待第2台机器启动进行第2轮投票,则此服务器状态为looking状态。
- 第2台服务器启动,则整个集群中一共有两个节点,首先,各个节点针对自己进行投票,然后进行广播操作。在广播过程中发现,第1个节点的myid编号<第2个节点的myid编号,则按大小排序,第1个节点会把自己的1张票投给myid=2的节点,则此时myid=2的节点拥有2张票,然后对外进行广播。但是由于目前票数<Zk集群节点数的一半,则第2轮投票失败。等待第3台机器启动继续进行第3轮投票,则此时myid=1和myid=2的机器也处于looking状态
- 当第3台服务器启动,则整个zk集群一共三个节点,首先,自已给自己投票,然后进行厂播操作。但是厂播后发现,集群中myid=3的节点拥有的编号最大,所以前2台机器把投票都投递给myid=3的节点,由于票数超过了zk集群节点数的一半,则选举成功,myid=3的节点,成为整个集群的leader,其他两台服务器状态,更改为following。角色也立即更换为follower。
- 当第4台机器启动时,也会投票给自己,然后进行广播,但是广播过程中,发现集群已经有一个leader角色,则自己只能充当follower,其他机器类似。
⑵.leader宕机后启动
第二种情况:已经产生过leader领导的集群,重新进行选举
- 如果是某台服务器网络故障或者网络波动,导致无法与Leader进行通信,则发起新一轮投票,首先投票给自己,然后进行广播,但是在广播过程中已经发现集群中已经存在leader的情况,则重新同步即可。
- 如果集群中的Leader的确因为岩机等情况,导致集群中没有Leader角色了。此时要重新选举,除了参考myid编号以外,还要参考zxid事务ID编号。在选举过程中,如果zxid不同,则哪个大,选择哪个成为Leader。如果zxid值相同,则哪个服务器的myid编号最大,则优先成为Leader
⑶.常见问题说明
问题1:如果原来那个Leader服务器重新启动了,是争抢这个Leader还是只能充当Follower
登录后复制
答:只能充当Follower角色
问题2:Observer不参与投票,所以不算在2n + 1的里面
问题2:2n + 1是如何确定的?
登录后复制
答:主要是根据zoo.cfg配置文件决定的!!!
三、zookeeper客户端操作
3.1.连接服务
方式1:直接连接本地:
登录后复制
[root@node1 ~]# zkCli.sh
方式2:连接其他节点:
登录后复制
[root@node1 ~]# zkCli.sh -server 节点地址
3.2.zookeeper常见shell命令
⑴.查看所有shell命令: help
⑵.创建节点
语法:
登录后复制
create [-s] [-e] 节点绝对路径 节点数据: 创建数据节点
注意:
- -s代表序列化节点
- -e代表临时节点
①.创建父节点:使用create命令创建父节点,例如:
登录后复制
create /hadoop data
这将在根目录下创建一个名为hadoop的节点,并设置其数据为"data"。
②.创建子节点:使用create命令创建子节点,指定父节点路径和子节点名称,例如:
登录后复制
create /hadoop/node1 data
这将在hadoop节点下创建一个名为node1的子节点,并设置其数据为"data"。
⑶.delete删除节点
语法:
登录后复制
delete 节点绝对路径 [version]: 删除一级节点
注意: 此方式如果有子节点是不能删除的
⑷.rmr删除节点
rmr 节点绝对路径: 删多层除节点(如果有子节点也可以删除)
⑸.set用于设置/修改节点数据
设置 /修改节点数据,语法:
登录后复制
set 节点绝对路径 data [version]
示例:
登录后复制
set /hadoop hello
说明:将节点
/hadoop
的数据设置为
hello
。
⑹.获取节点数据
获取数据语法:
登录后复制
get 节点绝对路径 [watch]
注意: watch是监听
⑺.查看节点信息
ls 节点绝对路径 : 查看节点信息 举例: 查看根路径下节点 ls /
ls2 节点绝对路径 : 查看节点详情信息
⑻.查看操作历史
history: 查看操作历史
⑼.退出
quit: 退出
四、zookeeper节点
4.1.节点特性
ZooKeeper的数据模型,在结构上和标准文件系统的非常相似,都是采用树形层次结构,和文件系统的目录树一样,ZooKeeper树中的每个节点可以拥有子节点。但也有不同之处:
- Znode兼具文件和目录两种特点: Znode没有文件和目录之分,Znode既有像文件一样存储数据,也能像目录一样作为路径标识的一部分
- Znode具有原子性操作: 读操作将获取与节点相关的所有数据,写操作也将替换掉节点的所有数据
- Znode存储数据大小有限制: 每个Znode的数据大小至多1M,当时常规使用中应该远小于此值
- Znode通过路径引用: 路径必须是绝对的,因此他们必须由斜杠字符来开头。除此以外,他们必须是唯一的,也就是说每一个路径只有一个表示,因此这些路径不能改变。 默认有/zookeeper节点用以保存关键的管理信息。
4.2.zookeeper节点类型
zookeeper节点分为:永久普通节点、临时普通节点、永久序列化节点、临时序列化节点
4.2.1.永久节点 和 临时节点
Znode有两种,分别为 永久节点 和 临时节点 。节点的类型在创建时即被确定,并且不能改变。
①.永久节点:该节点的生命周期不依赖于会话,并且只有在客户端显示执行删除操作的时候,他们才能被删除。
注意: 永久节点可以拥有子节点
登录后复制
创建永久节点: create /节点名 节点值
②.临时节点:该节点的生命周期依赖于创建它们的会话。一旦会话结束,临时节点将被自动删除,也可手动删除。
注意: 临时节点不允许拥有子节点。
登录后复制
创建临时节点: create -e /节点名 节点值
4.2.2.序列化节点
序列化节点: Znode还有一个序列化的特性,就是如果创建的时候加 -s 指定的话,该Znode的名字后面会自动追加一个不断增加的序列号。
序列化节点特点: 它的序列号对于此节点的父节点来说是唯一的,这样便会记录每个子节点创建的先后顺序。它的格式为/设定节点名+10位数字,没有数值的数位用0补充,例如’/node0000000001'。
③.创建永久序列化节点:
登录后复制
create -s /节点名 节点值
④.创建临时序列化节点:
登录后复制
create -e -s /节点名 节点值
4.3.zookeeper节点属性
每个znode都包含了一系列的属性,通过命令get /节点名,可以获得节点的属性
对于zookeeper来说,每次的变化都会产生一个唯一的事务id,zxid(ZooKeeper Transaction Id)。通过zxid,可以确定更新操作的先后顺序。例如,如果zxid1小于zxid2,说明zxid1操作先于zxid2发生,zxid对于整个zookeeper都是唯一的,即使操作的是不同的znode。
- cZxid :Znode创建的事务id。
- ctime :Znode创建时的时间戳.
- mZxid :Znode被修改的事务id,即每次对当前znode的修改都会更新mZxid。
- mtime :Znode最新一次更新发生时的时间戳.
- pZxid :Znode的子节点列表变更的事务ID,添加子节点或删除子节点就会影响子节点列表
- cversion :子节点进行变更的版本号。添加子节点或删除子节点就会影响子节点版本号
- dataVersion:数据版本号,每次对节点进行set操作,dataVersion的值都会增加1(即使设置的是相同的数据),可有效避免了数据更新时出现的先后顺序问题。
- aclVersion : 权限变化列表版本 access control list Version
- ephemeralOwner : 字面翻译临时节点拥有者,持久节点值为0x0,非持久节点不为0(会话ID)
- dataLength : Znode数据长度
- numChildren: 当前Znode子节点数量(不包括子子节点)
4.5.zookeeper特性
zookeeper特性说明如下:
- 全局数据一致: 集群中每个服务器保存一份相同的数据副本,client无论连接到哪个服务器,展示的数据都是一致的,这是最重要的特征;
- 可靠性: 如果消息被其中一台服务器接受,那么将被所有的服务器接受。
- 顺序性: 包括全局有序和偏序两种:全局有序是指如果在一台服务器上消息a在消息b前发布,则在所有Server上消息a都将在消息b前被发布;偏序是指如果一个消息b在消息a后被同一个发送者发布,a必将排在b前面。
- 数据更新原子性: 一次数据更新要么成功(半数以上节点成功),要么失败,不存在中间状态;
- 实时性: Zookeeper保证客户端将在一个时间间隔范围内获得服务器的更新信息,或者服务器失效的信息。
五、watch监听机制
ZooKeeper中的Watch(监听)机制是一种客户端与ZooKeeper服务器之间的一种通信机制,用于实现事件驱动的通知机制。当客户端向ZooKeeper注册了某个节点的Watch监听器后,如果该节点发生了变化(比如数据内容变化、节点被删除等),ZooKeeper服务器会通知对应的客户端,客户端可以收到通知后执行相应的逻辑处理。
ZooKeeper中,引入了Watcher机制来实现数据发布/订阅功能,一个典型的发布/订阅模型系统定义了一种一对多的订阅关系,能让多个订阅者同时监听某一个主题对象,当这个主题对象自身状态变化时,会通知所有订阅者,使他们能够做出相应的处理。
ZooKeeper允许客户端向服务端注册一个Watcher监听,当服务端的一些事件触发了这个Watcher,那么就会向指定客户端发送一个事件通知来实现分布式的通知功能。
5.1.watch监听机制过程:
- 客户端向服务端注册Watcher
- 服务端事件发生触发Watcher
- 客户端回调Watcher得到触发事件情况
5.2.Watch监听机制注册格式:
语法:
登录后复制
get /节点绝对路径 watch
5.3.Watch监听机制特点:
- 先注册再触发: Zookeeper中的watch机制,必须客户端先去服务端注册监听,这样事件发送才会触发监听,通知给客户端
- 一次性触发: 事件发生触发监听,一个watcher event就会被发送到设置监听的客户端,这种效果是一次性的,后续再次发生同样的事件,不会再次触发。
- 异步发送: watcher的通知事件从服务端发送到客户端是异步的。
- 通知内容: 通知状态(keeperState),事件类型(EventType)和节点路径(path)
5.4.示例
node1上创建临时节点
登录后复制
[zk: localhost:2181(CONNECTED) 0] create -e /master 111111
Created /master
node2上设置监听
登录后复制
[zk: localhost:2181(CONNECTED) 3] get /master watch
111111
cZxid = 0x10000003c
ctime = Mon Sep 23 10:22:32 CST 2024
mZxid = 0x10000003c
mtime = Mon Sep 23 10:22:32 CST 2024
pZxid = 0x10000003c
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x1921c88e5a30000
dataLength = 6
numChildren = 0
node1退出
登录后复制
[zk: localhost:2181(CONNECTED) 1] quit
Quitting...
2024-09-23 10:25:56,553 [myid:] - INFO [main:ZooKeeper@684] - Session: 0x1921c88e5a30000 closed
2024-09-23 10:25:56,553 [myid:] - INFO [main-EventThread:ClientCnxn$EventThread@512] - EventThread shut down
node2查看消息
这条消息表示在ZooKeeper中发生了一个WatchedEvent事件,具体信息如下:
- state: SyncConnected:表示客户端与ZooKeeper服务器已建立同步连接。这是ZooKeeper客户端连接状态的一种,表明客户端已成功连接到ZooKeeper服务器。
- type: NodeDeleted:表示节点被删除的事件类型。在这种情况下,WatchedEvent通知是由于监视的节点(路径为
/master
)被删除而触发的。 - path: /master:表示触发WatchedEvent的节点路径是
/master
,即监视的节点路径为/master
。
综合起来,这条消息的含义是:客户端与ZooKeeper服务器建立了同步连接,同时监视的节点
/master
被删除了,因此触发了一个节点删除的WatchedEvent事件。当客户端收到这样的WatchedEvent通知时,可以根据需要执行相应的逻辑处理,比如重新设置节点、更新状态等操作。
在ZooKeeper中,WatchedEvent事件的state和type字段可以具有不同的取值,表示不同的状态和事件类型。以下是它们可能的取值和含义说明:
state字段可能的取值:
- SyncConnected:客户端与ZooKeeper服务器建立了同步连接。
- Disconnected:客户端与ZooKeeper服务器的连接断开。
- Expired:会话超时,客户端会话过期。
- AuthFailed:认证失败,客户端认证失败。
type字段可能的取值:
- NodeCreated:节点被创建。
- NodeDeleted:节点被删除。
- NodeDataChanged:节点数据内容发生变化。
- NodeChildrenChanged:子节点列表发生变化。
- DataWatchRemoved:数据Watch被移除。
- ChildWatchRemoved:子节点Watch被移除。
这些状态和事件类型的组合可以描述不同的场景和操作,帮助客户端根据WatchedEvent事件的具体内容来进行相应的处理和逻辑操作。在实际应用中,根据不同的state和type值,客户端可以编写相应的逻辑来处理节点状态变化和WatchedEvent通知。
六、zookeeper典型应用
6.1. 数据发布/订阅
数据发布/订阅系统,就是发布者将数据发布到ZooKeeper的一个节点上,提供订阅者进行数据订阅,从而实现动态更新数据的目的,实现配置信息的集中式管理和数据的动态更新。
主要用到知识点: 监听机制
6.2.提供集群选举
在分布式环境下,不管是主从架构集群,还是主备架构集群,要求在服务的时候有且有一个正常的对外提供服务,我们称之为master。
当master出现故障之后,需要重新选举出的新的master。保证服务的连续可用性。zookeeper可以提供这样的功能服务。
主要用到知识点: znode唯一性、临时节点短暂性、监听机制。
选举概述:
- 选举要求: 过半原则,所以搭建集群一般奇数,只要某个node节点票数过半立刻成为leader
- 集群第一次启动: 启动follower每次投票后,他们会相互同步投票情况,如果票数相同,谁的myid大,谁就当选leader,一旦确定了leader,后面来的默认就是follower,即使它的myid大,leader也不会改变(除非leader宕机了)
- leader宕机后启动: 每一个leader当老大的时候,都会产生新纪元epoch,且每次操作完节点数据都会更新事务id(高32位_低32位) ,当leader宕机后,剩下的follower就会综合考虑几个因素选出最新的leader,先比较最后一次更新数据事务id(高32位_低32位),谁的事务id最大,谁就当选leader,如果更新数据的事务id都相同的情况下,就需要再次考虑myid,谁的myid大,谁就当选leader
七、zookeeper实现hadoop高可用集群(主备切换)
7.1.zookeeper实现hadoop高可用集群思路
JournalNode和ZKFC是Hadoop高可用集群中两个关键组件,它们的作用和功能如下:
实现Hadoop高可用集群的关键组件:
- JournalNode:
- 作用:JournalNode用于存储NameNode的编辑日志,确保元数据的一致性和持久性。
- 功能:多个NameNode可以共享一个JournalNode集群,将编辑日志写入JournalNode,以实现元数据的同步和持久化。
- 实现原理:通过JournalNode,不同的NameNode可以共享同一份编辑日志,当主NameNode发生故障时,备用NameNode可以通过读取JournalNode中的编辑日志来恢复元数据状态,实现快速故障转移。
- ZKFC(ZooKeeper Failover Controller):
- 作用:ZKFC用于监控和管理NameNode的高可用性。
- 功能:ZKFC通过与ZooKeeper集成,监控主NameNode的状态,并在主NameNode发生故障时协调进行自动故障转移。
- 实现原理:ZKFC会定期检查主NameNode的健康状态,一旦发现主NameNode不可用,ZKFC会触发故障转移过程,协调备用NameNode接管主NameNode的角色,确保HDFS的高可用性。
实现Hadoop高可用集群的流程:
- 配置JournalNode:在Hadoop集群中配置JournalNode,让多个NameNode共享同一个JournalNode集群,实现元数据的同步和持久化。
- 配置ZKFC:配置ZKFC监控主NameNode的状态,当主NameNode发生故障时,ZKFC会自动触发故障转移过程。
- 故障转移:当主NameNode发生故障时,ZKFC会协调备用NameNode接管主NameNode的角色,继续提供服务,保证HDFS的高可用性。
通过JournalNode和ZKFC的配合,Hadoop集群可以实现高可用性,确保在主NameNode发生故障时能够快速切换到备用NameNode,保障数据的安全和服务的持续性。
7.2.高可用集群搭建
7.2.1.安装软件
node1/node2/node3:
登录后复制
yum install psmisc -y # 可以杀死所有相关进程,还可以使用kill all命令
7.2.2.修改配置文件(重点)
在修改之前先停止服务,在node1执行即可:
登录后复制
stop-all.sh
以下配置只需要在node1上完成,完成后拷贝到node2/node3:
登录后复制
cd /export/server/hadoop-3.3.4/etc/hadoop
⑴.修改hadoop-env.sh
登录后复制
# 在文件最后添加下面两行
export HDFS_JOURNALNODE_USER=hadoop
export HDFS_ZKFC_USER=hadoop
⑵.修改core-site.xml
登录后复制
<configuration>
<!-- HA集群名称,该值要和hdfs-site.xml中的配置保持一致 -->
<property>
<name>fs.defaultFS</name>
<value>hdfs://cluster1</value>
</property>
<!-- hadoop本地磁盘存放数据的公共目录 -->
<property>
<name>hadoop.tmp.dir</name>
<value>/export/data/ha-hadoop</value>
</property>
<!-- ZooKeeper集群的地址和端口-->
<property>
<name>ha.zookeeper.quorum</name>
<value>node1:2181,node2:2181,node3:2181</value>
</property>
<!-- 允许hadoop用户代理的主机和用户组 -->
<property>
<name>hadoop.proxyuser.hadoop.hosts</name>
<value>*</value> <!-- 允许所有主机,也可以指定某些主机 -->
</property>
<property>
<name>hadoop.proxyuser.hadoop.groups</name>
<value>hadoop</value> <!-- 如果hadoop用户属于这个组,确保组名正确 -->
</property>
</configuration>
⑶.修改hdfs-site.xml
登录后复制
<configuration>
<!-- HDFS HA Configuration -->
<!-- dfs.nameservices 定义HDFS集群的名称,在配置HA时需要指定该名称。 -->
<property>
<name>dfs.nameservices</name>
<value>cluster1</value>
</property>
<!-- dfs.ha.namenodes.cluster1 指定该集群(cluster1)的两个NameNode。多个NameNode以逗号分隔,这里为 nn1 和 nn2。 -->
<property>
<name>dfs.ha.namenodes.cluster1</name>
<value>nn1,nn2</value>
</property>
<!-- dfs.namenode.rpc-address.cluster1.nn1 设置第一个NameNode的RPC地址。RPC地址用于客户端与NameNode通信。 -->
<property>
<name>dfs.namenode.rpc-address.cluster1.nn1</name>
<value>node1:8020</value>
</property>
<!-- dfs.namenode.http-address.cluster1.nn1 设置第一个NameNode的HTTP地址,用于通过HTTP协议访问NameNode Web UI。 -->
<property>
<name>dfs.namenode.http-address.cluster1.nn1</name>
<value>node1:9870</value>
</property>
<!-- dfs.namenode.rpc-address.cluster1.nn2 设置第二个NameNode的RPC地址。 -->
<property>
<name>dfs.namenode.rpc-address.cluster1.nn2</name>
<value>node2:8020</value>
</property>
<!-- dfs.namenode.http-address.cluster1.nn2 设置第二个NameNode的HTTP地址。 -->
<property>
<name>dfs.namenode.http-address.cluster1.nn2</name>
<value>node2:9870</value>
</property>
<!-- dfs.namenode.shared.edits.dir 指定两个NameNode的共享存储目录,用于保存元数据的编辑日志。使用JournalNode作为共享存储。格式为 qjournal://journalnode地址/集群名。 -->
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://node1:8485;node2:8485;node3:8485/cluster1</value>
</property>
<!-- dfs.journalnode.edits.dir 设置JournalNode保存编辑日志的本地目录。 -->
<property>
<name>dfs.journalnode.edits.dir</name>
<value>/export/data/journaldata</value>
</property>
<!-- dfs.ha.automatic-failover.enabled 启用自动故障转移(failover)功能。若设置为 true,当一个NameNode失效时,系统会自动切换到另一个NameNode。 -->
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
<!-- dfs.client.failover.proxy.provider.cluster1 指定集群的客户端故障转移代理提供者,用于在HA配置下处理客户端请求的故障转移。 -->
<property>
<name>dfs.client.failover.proxy.provider.cluster1</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
<!-- dfs.ha.fencing.methods 指定fencing方法,当某个NameNode失效后,系统会将其隔离(fencing),防止它再访问HDFS。这里使用 sshfence 方法。 -->
<property>
<name>dfs.ha.fencing.methods</name>
<value>sshfence</value>
</property>
<!-- dfs.ha.fencing.ssh.private-key-files 指定用于执行SSH fencing的私钥文件路径。该私钥允许通过SSH连接到失效的NameNode并执行隔离操作。 -->
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/root/.ssh/id_rsa</value>
</property>
<!-- dfs.ha.fencing.ssh.connect-timeout 指定通过SSH连接时的超时时间(以毫秒为单位)。在规定时间内无法连接到失效的NameNode将导致fencing失败。 -->
<property>
<name>dfs.ha.fencing.ssh.connect-timeout</name>
<value>30000</value>
</property>
</configuration>
主要功能概述:
- HA配置:该文件配置了HDFS的高可用(HA)功能,通过配置两个NameNode(nn1, nn2)和JournalNode,实现自动故障转移。
- 共享存储:两个NameNode通过JournalNode共享编辑日志,确保故障发生时另一NameNode可以接管服务。
- 自动故障转移:启用了自动failover功能,当一个NameNode失效时,系统会自动切换至另一个。
- Fencing机制:配置了SSH fencing,通过SSH隔离失效的NameNode,确保不会造成数据不一致。
⑷.修改yarn-site.xml
通过启用 YARN 高可用模式来确保集群的可靠性,配置了两个 ResourceManager(rm1
和 rm2
)的相关地址,同时启用了 Timeline 服务和日志聚合功能,用于跟踪作业历史和管理日志。在高可用的 YARN 集群环境中,这些设置确保了 ResourceManager 的自动切换和节点间的协调。
登录后复制
<configuration>
<!-- 启用 YARN 高可用特性 -->
<property>
<name>yarn.resourcemanager.ha.enabled</name>
<value>true</value>
<description>启用 ResourceManager 高可用模式</description>
</property>
<!-- 定义集群 ID -->
<property>
<name>yarn.resourcemanager.cluster-id</name>
<value>yrc</value>
<description>集群标识符,用于识别 YARN 集群</description>
</property>
<!-- 定义 ResourceManager HA 中的所有 RM 节点 -->
<property>
<name>yarn.resourcemanager.ha.rm-ids</name>
<value>rm1,rm2</value>
<description>定义两个 ResourceManager 节点的 ID,分别为 rm1 和 rm2</description>
</property>
<!-- 定义 rm1 的主机名 -->
<property>
<name>yarn.resourcemanager.hostname.rm1</name>
<value>node1</value>
<description>rm1 对应的主机名为 node1</description>
</property>
<!-- 定义 rm2 的主机名 -->
<property>
<name>yarn.resourcemanager.hostname.rm2</name>
<value>node2</value>
<description>rm2 对应的主机名为 node2</description>
</property>
<!-- 定义 Zookeeper 集群的地址,用于 ResourceManager 之间的协调 -->
<property>
<name>yarn.resourcemanager.zk-address</name>
<value>node1:2181,node2:2181,node3:2181</value>
<description>为 ResourceManager 高可用配置 Zookeeper 集群地址,用于协调 RM 切换</description>
</property>
<!-- 定义 NodeManager 服务类型 -->
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
<description>定义 NodeManager 辅助服务为 mapreduce shuffle</description>
</property>
<!-- ResourceManager rm1 的地址配置 -->
<property>
<name>yarn.resourcemanager.address.rm1</name>
<value>node1:8032</value>
<description>rm1 的通信地址,端口为 8032</description>
</property>
<!-- ResourceManager rm1 的调度器地址 -->
<property>
<name>yarn.resourcemanager.scheduler.address.rm1</name>
<value>node1:8030</value>
<description>rm1 的调度器地址,端口为 8030</description>
</property>
<!-- ResourceManager rm1 的 Web UI 地址 -->
<property>
<name>yarn.resourcemanager.webapp.address.rm1</name>
<value>node1:8088</value>
<description>rm1 的 Web UI 地址,端口为 8088</description>
</property>
<!-- ResourceManager rm1 的资源追踪器地址 -->
<property>
<name>yarn.resourcemanager.resource-tracker.address.rm1</name>
<value>node1:8031</value>
<description>rm1 的资源追踪器地址,端口为 8031</description>
</property>
<!-- ResourceManager rm1 的管理员服务地址 -->
<property>
<name>yarn.resourcemanager.admin.address.rm1</name>
<value>node1:8033</value>
<description>rm1 的管理员服务地址,端口为 8033</description>
</property>
<!-- ResourceManager rm2 的地址配置 -->
<property>
<name>yarn.resourcemanager.address.rm2</name>
<value>node2:8032</value>
<description>rm2 的通信地址,端口为 8032</description>
</property>
<!-- ResourceManager rm2 的调度器地址 -->
<property>
<name>yarn.resourcemanager.scheduler.address.rm2</name>
<value>node2:8030</value>
<description>rm2 的调度器地址,端口为 8030</description>
</property>
<!-- ResourceManager rm2 的 Web UI 地址 -->
<property>
<name>yarn.resourcemanager.webapp.address.rm2</name>
<value>node2:8088</value>
<description>rm2 的 Web UI 地址,端口为 8088</description>
</property>
<!-- ResourceManager rm2 的资源追踪器地址 -->
<property>
<name>yarn.resourcemanager.resource-tracker.address.rm2</name>
<value>node2:8031</value>
<description>rm2 的资源追踪器地址,端口为 8031</description>
</property>
<!-- ResourceManager rm2 的管理员服务地址 -->
<property>
<name>yarn.resourcemanager.admin.address.rm2</name>
<value>node2:8033</value>
<description>rm2 的管理员服务地址,端口为 8033</description>
</property>
<!-- 启用 YARN 的 Timeline 服务 -->
<property>
<name>yarn.timeline-service.enabled</name>
<value>true</value>
<description>启用 YARN Timeline 服务,用于记录和查询历史信息</description>
</property>
<!-- Timeline 服务的通信地址 -->
<property>
<name>yarn.timeline-service.address</name>
<value>node1:10200</value>
<description>Timeline 服务的通信地址,端口为 10200</description>
</property>
<!-- Timeline 服务的 Web UI 地址 -->
<property>
<name>yarn.timeline-service.webapp.address</name>
<value>node1:8188</value>
<description>Timeline 服务的 Web UI 地址,端口为 8188</description>
</property>
<!-- 启用日志聚合功能,用于高可用环境下的日志管理 -->
<property>
<name>yarn.log-aggregation-enable</name>
<value>true</value>
<description>启用日志聚合,便于在 HA 设置中集中管理日志</description>
</property>
<!-- 日志服务器地址,用于查看作业历史和日志 -->
<property>
<name>yarn.log.server.url</name>
<value>http://node1:19888/jobhistory/logs</value>
<description>日志服务器 URL,用于通过 Web 界面查看作业历史和日志</description>
</property>
</configuration>
配置解读:
- 高可用:该配置启用了YARN的高可用机制,通过配置多个ResourceManager(rm1, rm2),实现自动故障切换(HA)。当一个ResourceManager失效时,另一个会接管工作。
- Zookeeper协调:YARN通过Zookeeper集群(节点node1, node2, node3)来进行ResourceManager的状态协调,确保不会出现多个ResourceManager同时工作的问题。
- ResourceManager网络配置:分别为两个ResourceManager配置了不同的网络端口,用于客户端通信、调度服务、Web UI等功能。
- NodeManager服务:NodeManager会启用MapReduce的shuffle服务,支持分布式MapReduce计算任务的处理。
⑸.修改mapred-site.xml
主要内容如下:
- 历史服务器的通讯端口、Web端口已设为
node1:10020``````19888
。 - 历史信息的 HDFS 记录路径以及临时路径已设定为
/data/mr-history/tmp``````/data/mr-history/done
。 - MapReduce 环境变量设定为
HADOOP_HOME
,确保正确加载相应环境配置。
登录后复制
<configuration>
<!-- 设置MapReduce的运行框架为YARN -->
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
<description>MapReduce的运行框架设置为YARN</description>
</property>
<!-- 历史服务器通讯端口 -->
<property>
<name>mapreduce.jobhistory.address</name>
<value>node1:10020</value>
<description>历史服务器通讯端口为node1:10020</description>
</property>
<!-- 历史服务器web端口 -->
<property>
<name>mapreduce.jobhistory.webapp.address</name>
<value>node1:19888</value>
<description>历史服务器web端口为node1的19888</description>
</property>
<!-- 历史信息在HDFS的记录临时路径 -->
<property>
<name>mapreduce.jobhistory.intermediate-done-dir</name>
<value>/data/mr-history/tmp</value>
<description>历史信息在HDFS的记录临时路径</description>
</property>
<!-- 历史信息在HDFS的记录路径 -->
<property>
<name>mapreduce.jobhistory.done-dir</name>
<value>/data/mr-history/done</value>
<description>历史信息在HDFS的记录路径</description>
</property>
<!-- MapReduce Application Master的环境变量设置 -->
<property>
<name>yarn.app.mapreduce.am.env</name>
<value>HADOOP_MAPRED_HOME=$HADOOP_HOME</value>
<description>MapReduce HOME设置为HADOOP_HOME</description>
</property>
<!-- Map任务的环境变量设置 -->
<property>
<name>mapreduce.map.env</name>
<value>HADOOP_MAPRED_HOME=$HADOOP_HOME</value>
<description>Map任务的环境变量设置为HADOOP_HOME</description>
</property>
<!-- Reduce任务的环境变量设置 -->
<property>
<name>mapreduce.reduce.env</name>
<value>HADOOP_MAPRED_HOME=$HADOOP_HOME</value>
<description>Reduce任务的环境变量设置为HADOOP_HOME</description>
</property>
</configuration>
⑹.拷贝配置文件
注意: 将hadoop配置信息拷贝到node2和node3
登录后复制
cd /export/server/hadoop-3.3.4/etc
scp -r hadoop node2:$PWD
scp -r hadoop node3:$PWD
7.2.3.启动(注意顺序以及启动机器)
⑴.启动zk
zkServer.sh start(配置了环境变量,直接启动,没有配置则进入Zookeeper的bin目录,手工启动),node1/node2/node3按照顺序均需启动:
登录后复制
cd /export/server/zookeeper
bin/zkServer.sh start
⑵.启动journalnode(node1/node2/node3)
登录后复制
hdfs --daemon start journalnode
注意:journalnode启动完毕后,一定要等待8485端口被java进程所占用然后在执行下方操作!!!
登录后复制
netstat -naltp |grep 8485
⑶.初始化namenode 注意:node1上执行
登录后复制
hdfs namenode -format
⑷.将数据文件拷贝到node2相同目录(node2上也有namenode节点)
登录后复制
cd /export/data
scp -r ha-hadoop node2:$PWD
⑸.初始化zkfc 注意在node1上执行
登录后复制
hdfs zkfc -formatZK
⑹.启动服务
登录后复制
#在node1/node2/node3按照顺序关闭journalnode
hdfs --daemon stop journalnode
# 启动所有服务只需要node1上执行
start-all.sh
# 在node1启动历史服务器
$HADOOP_HOME/bin/mapred --daemon start historyserver
⑺.测试
执行求圆周率的方法:
登录后复制
hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.4.jar pi 3 10000
执行后效果如下:
7.2.4.常见问题
① 如果node2中namenode角色没有启动
答:手工启动:
登录后复制
hdfs --daemon start namenode
注意:如果手工启动有异常,一定要进入logs目录,查看错误原因
② Web界面无法上传文件
答:修改权限即可:
登录后复制
hadoop fs -chmod -R 777 /
③ node1:9870或者node2:9870某台机器无法阅读文件列表
答:不是错误,是因为当前你可能处于了standby备机,切换到另一个节点即可。因为对外提供服务器时,只有一个namenode处于工作状态。
版权归原作者 egzosn 所有, 如有侵权,请联系我们删除。