主要内容:
搭建Zookeeper高可用集群、搭建分布式消息队列kafka、搭建高可用hadoop集群
一、Zookeeper 介绍
Zookeeper是一个开源分布式应用程序协调服务,主要用于解决分布式集群中应用系统的一致性问题。它能提供类似文件系统的目录节点树方式的数据存储,主要用途是维护和监控所存数据的状态变化,以实现对集群的管理。而Zookeeper 集群通常由多个 Zookeeper 服务器组成,以提供高可用性和数据一致性。
Zookeeper应用场景:
- ① 集群分布式共享锁;
- ② 集群统一命名服务;
- ③ 分布式协调服务;
- ④ 队列管理
1、Zookeeper 关键字
1)ZooKeeper Ensemble:
- Zookeeper 集群通常称为 Ensemble。一个 Ensemble 至少需要三台服务器,以确保在单台服务器故障时仍能正常工作。
2)Leader 和 Follower:
- 在 Ensemble 中,服务器分为 Leader 和 Follower。Leader 负责处理所有写请求,并将更改同步到 Followers。读请求可以由任何服务器处理。
3)Quorum:
- 为了达成一致性,Zookeeper 使用 Quorum 机制。Quorum 是指 Ensemble 中大多数服务器(超过一半)的同意。例如,一个三台服务器的 Ensemble 需要两台服务器的同意。
4)ZNode:
- Zookeeper 的数据存储在树形结构中,每个节点称为 ZNode。ZNode 可以是持久性的或临时性的。
2、Zookeeper 角色与选举
1)Leader:
职责:
- 处理所有写请求。
- 将写请求的更改同步到所有 Followers。
- 管理集群的协调和同步。
特点:
- 只有一个 Leader,负责所有写操作。
- Leader 故障时,会触发新的 Leader 选举。
2)Follower:
职责:
- 处理读请求。
- 参与 Leader 选举过程。
- 接收并应用 Leader 同步的写操作。
特点:
- 可以有多个 Followers。
- 在 Leader 故障时,参与新的 Leader 选举。
3)Observer(可选):
职责:
- 处理读请求。
- 不参与 Leader 选举和写操作的投票。
特点:
- 用于扩展读性能,但不影响写操作的 Quorum。
- 不参与 Leader 选举和写操作的投票。
选举 Leader 遵循过半原则:
Zookeeper 使用 ZAB(Zookeeper Atomic Broadcast)协议来保证数据一致性和 Leader 选举。以下是 Leader 选举的基本过程:
① 初始化: 所有服务器启动时,状态为 LOOKING,表示它们正在寻找 Leader。
② 选举消息: 每个 LOOKING 状态的服务器会向其他服务器发送选举消息,包含自己的 ID 和最新的 ZXID(事务 ID)。
③ 比较 ZXID: 服务器收到选举消息后,会比较 ZXID。ZXID 较大的服务器优先成为 Leader。如果 ZXID 相同,则比较服务器 ID,ID 较大的服务器优先。
④ 投票: 每个服务器会向其他服务器发送投票消息,表示支持某个服务器成为 Leader。如果一个服务器收到超过半数的投票支持,它将成为 Leader。
⑤ Leader 确认: 成为 Leader 的服务器会向其他服务器发送确认消息,表示自己已成为 Leader。其他服务器收到确认消息后,状态变为 FOLLOWING,表示它们已成为 Follower。
**⑥ Leader 服务:**Leader 开始处理写请求,并将更改同步到 Followers。Followers 处理读请求,并接收 Leader 同步的写操作。
补充:
- Quorum: 选举过程中需要多数服务器(Quorum)的同意。例如,一个三台服务器的 Ensemble 需要两台服务器的同意。
- ZXID: ZXID 是事务 ID,用于比较服务器的数据更新情况。ZXID 较大的服务器优先成为 -Leader。
**- 服务器 ID:**如果 ZXID 相同,则比较服务器 ID。ID 较大的服务器优先。
3、Zookeeper 高可用
Zookeeper 的高可用性是通过其分布式架构和 Leader 选举机制来实现的。以下是确保 Zookeeper 高可用性的关键点和配置建议:
网络配置:
- 稳定网络:确保集群中各服务器之间的网络连接稳定,避免网络分区导致脑裂问题
- 低延迟:尽量减少网络延迟,以提高数据同步和 Leader 选举的效率
硬件配置:
- 高性能服务器:选择高性能的服务器,确保处理能力和存储容量满足需求
- 冗余硬件:使用冗余硬件(如 RAID、双电源),提高硬件可靠性
Zookeeper 配置:
- tickTime:基本时间单位(毫秒),建议根据网络延迟和性能需求调整
- initLimit:Follower 初始化连接到 Leader 的超时时间,建议根据网络延迟调整
- syncLimit:Follower 与 Leader 同步的超时时间,建议根据网络延迟调整
- dataDir:数据存储目录,建议使用高性能存储设备
- clientPort:客户端连接端口,建议使用默认端口 2181
监控和日志:
- 监控工具:使用如 Zabbix、Prometheus监控 Zookeeper 集群的状态和性能
常见问题和解决方案
- 网络分区:确保网络稳定,使用冗余网络连接,避免单点故障。
- Leader 选举失败:检查网络连接和配置参数,确保 Quorum 机制正常工作。
- 数据一致性问题:使用 ZAB 协议确保数据一致性,定期备份数据。
4、Zookeeper 可伸缩扩展性原理与设计
在Observer出现之前,Zookeeper的伸缩性由Follower来实现,可以通过添加Follower节点的数量来保证Zookeeper服务的读性能,但是随着Follower节点数量的增加,Zookeeper服务的写性能受到了影响。当客户端提交一个请求,若是读请求,则由每台Server的本地副本数据库直接响应;若是写请求,需要通过一致性协议(Zab)来处理。
Zab协议规定:
来自客户端的所有写请求都要转发给集群中唯一的Leader,当Leader收到一个写请求时,就会发起一个提案进行投票,然后其它的Server对该提案进行投票,之后Leader收集投票的结果,当投票数据量过半时,Leader会向所有的Server发送一个通知消息;最后当客户端所连接的Server收到该消息时,会把该操作更新并对客户端的写请求做出回应。
写性能问题:
- ① Zookeeper在上述协议中实际扮演了两个职能,一方面从客户端接收连接与操作请求,另一方面对操作结果进行投票,这两个职能在集群扩展的时候彼此制约;
- ② 从Zab协议对写请求的处理过程中可以发现,增加Follower的数量,则增加了协议投票的过程压力,因为Leader节点必须等待集群中过半Server响应投票,是节点的增加使得部分计算机运行较慢,从而拖慢整个投票过程的可能性也随之提高,随着集群变大,写操作也会随之下降;
解决办法:
- 为解决增加Follower的写性能问题,不得不在增加集群规模和保持较好吞吐性能之间进行权衡,为了打破这一耦合关系,引入了不参与投票的服务器Observer,Observer可以接受客户端的连接,并将写请求转发给Leader节点,但Leader节点不会要求Observer参加投票;
- Observer的扩展,给Zookeeper的可伸缩性带来了全新的景象,加入很多Observer节点,无需担心严重影响写吞吐量,Observer提升读性能的可伸缩性,并且还提供了广域网能力;
- 但Observer因为协议中的通知阶段,仍然与服务器的数量呈线性关系,但是这里的串行开销非常低,因此,可以认为在通知服务器阶段不会成为瓶颈。
5、Zookeeper 配置步骤
-
- Zookeeper安装目录:/usr/local/zookeeper
-
- Zookeeper配置目录:/usr/local/zookeeper/conf/
① 安装 Zookeeper:
下载 Zookeeper 并解压到指定目录;配置环境变量 ZOOKEEPER_HOME 和 PATH
② 配置文件:
在 Zookeeper 的配置目录中创建 zoo.cfg 文件,配置示例:
bash
tickTime=2000
dataDir=/var/lib/zookeeper
clientPort=2181
initLimit=5
syncLimit=2
server.1=zoo1:2888:3888
server.2=zoo2:2888:3888
server.3=zoo3:2888:3888
tickTime:基本时间单位(毫秒)。
dataDir:数据存储目录。
clientPort:客户端连接端口。
initLimit:Follower 初始化连接到 Leader 的超时时间。
syncLimit:Follower 与 Leader 同步的超时时间。
server.X:指定每个服务器的地址和端口。
③ 创建 myid 文件:
在 dataDir 目录下创建 myid 文件,内容为服务器的 ID(如 1、2、3)。
④ 启动 Zookeeper 服务:
在每台服务器上启动 Zookeeper 服务:
$ZOOKEEPER_HOME/bin/zkServer.sh start
⑤ 验证集群状态:确保每台服务器的状态正确(Leader 或 Follower)
$ZOOKEEPER_HOME/bin/zkServer.sh status
Zookeeper集群部署示例:
zookeeper集群图例:
|-----------|--------------|----------|----------|
| 主机名称 | IP地址 | 相关配置 | 角色 |
| hadpoo1 | 192.168.1.50 | 最低配置2核4G | Observer |
| node-0001 | 192.168.1.51 | 最低配置2核4G | 自动选举分配 |
| node-0002 | 192.168.1.52 | 最低配置2核4G | 自动选举分配 |
| node-0003 | 192.168.1.53 | 最低配置2核4G | 自动选举分配 |
建议:重启4台云主机hadoop1、node-000、,node-0002、node-0003(清理缓存)
步骤1:配置Zookeeper,并同步安装目录给其他主机(hadoop1操作)
拷贝云盘public/hadoop/zookeeper-3.4.13.tar.gz到hadoop1
bash
[root@ecs-proxy hadoop]# scp zookeeper-3.4.13.tar.gz 192.168.1.50:/root
① 安装JAVA运行环境,并准备Zookeepeer安装目录(已完成)
bash
[root@hadoop1 ~]# yum install -y java-1.8.0-openjdk-devel
[root@hadoop1 ~]# tar -zxf zookeeper-3.4.13.tar.gz
[root@hadoop1 ~]# mv zookeeper-3.4.13 /usr/local/zookeeper
[root@hadoop1 ~]# cd /usr/local/zookeeper/
[root@hadoop1 zookeeper]# ls
② 修改配置文件(/usr/local/zookeeper/conf/zoo.cfg)
补充:Zookeeper配置文件默认是单机模式(Standalone),如果组建集群,在配置文件末尾添加集群节点成员,即成为集群模式
bash
[root@hadoop1 zookeeper]# cd conf/ //切换到配置目录
[root@hadoop1 conf]# cp zoo_sample.cfg zoo.cfg //拷贝配置模板文件
[root@hadoop1 conf]# vim zoo.cfg
server.1=node-0001:2888:3888 //自动选举leader\follower角色,无需指定
server.2=node-0002:2888:3888
server.3=node-0003:2888:3888
server.4=hadoop1:2888:3888:observer //不参与投票,指定observer角色
说明:server.运行id=主机名称:端口:范围:Observer角色
解释:server表示服务,.1表示运行id(唯一),主机名,2888,3888为通信端口
注意:要保证主机名能够被解析且互相能够Ping通,主机名和server.id为对应关系
③ 同步Hadoop1的/usr/local/zookeeper安装目录到所有node主机
bash
[root@hadoop1 conf]# for i in node-{0001..0003};do
> rsync -aXSH --delete /usr/local/zookeeper ${i}:/usr/local/
> done
步骤2:手工启动Zookeeper服务(hadoop1、node-0001、node-0002、node-0003操作)
根据Zookeeper配置文件中的dataDir定义,需在所有节点创建数据存储目录
bash
[root@hadoop1 conf]# cat zoo.cfg
① 创建数据存储目录(以hadoop1为例)
bash
[root@hadoop1 ~]# mkdir /tmp/zookeeper
② 创建myid文件,文件内容为主机运行id
本机的server.id与myid文件中的id必须对应,id的范围是1~255
bash
[root@hadoop1 ~]# grep -Po "\d+(?==${HOSTNAME})" /usr/local/zookeeper/conf/zoo.cfg > /tmp/zookeeper/myid //扩展:零宽断言
[root@hadoop1 ~]# cat /tmp/zookeeper/myid //Hadoop1对应的id为4
4
② 启动集群服务
bash
[root@hadoop1 ~]# /usr/local/zookeeper/bin/zkServer.sh start
③ 验证角色
bash
[root@hadoop1 ~]# jps
④ 当所有节点集群服务启动完成后,使用命令验证
bash
[root@hadoop1 ~]# for i in hadoop1 node-{0001..0003};do
> echo ${i};
> ssh ${i} "/usr/local/zookeeper/bin/zkServer.sh status"
> echo -e "\n";
> done
**常见报错:**查看角色,必须启动超过半数的机器才能选举角色,当节点未全部完成服务启动,即集群节点数量不足一半,查看状态会显示Error
Zookeeper集群管理示例:
[管理手册地址]:ZooKeeper Administrator's Guide
手册提供了一些简单的四字命令,用来管理集群;通过网络访问Zookeeper端口,来实现集群的状态查询, 例如:健康状态ruok、配置文件conf、集群状态mntr
例如1:测试四字命令,需通过socat工具来实现网络接口、数据报文格式发送;
bash
[root@hadoop1 ~]# yum install -y socat //安装socat工具
[root@hadoop1 ~]# socat - TCP:node-0001:2181
ruok //监测健康状态(交互界面)
imok
说明:标准输入ruok,转发给第二个地址处理,并通过标准输出返回结果imok;
解释:socat用途是把一组数据发送给第一个地址,再转发给第二个地址,让两个地址之间能够互相传输和通信;默认需要2组参数:
① -为占位符,表示默认地址,而默认地址即本地的标准输入输出键盘、鼠标显示器;
② 第二个地址是网络地址,协议是TCP、主机、端口号
bash
[root@hadoop1 ~]# socat - TCP:node-0001:2181
conf //配置文件conf
bash
[root@hadoop1 ~]# socat - TCP:node-0001:2181
mntr //集群状态mntr
例如2:使用zkstats脚本,查看Zookeeper各个服务器角色
bash
[root@ecs-proxy ~]# scp zkstats 192.168.1.50:/root
[root@hadoop1 ~]# cat zkstats
#!/bin/bash
function getzkstat(){ //定义函数
exec 2>/dev/null
exec 8<>/dev/tcp/$1/2181
echo stat >&8
Msg=$(cat <&8 |grep -P "^Mode:")
exec 8<&-
printf "%15s " $1
echo -e "${Msg:-Mode: \x1b[31mNULL\x1b[0m}"
}
if (( $# == 0 ));then
echo "${0##*/} zk1 zk2 zk3 ... ..."
else
for i in $@;do
getzkstat ${i}
done
fi
[root@hadoop1 ~]# chmod +x zkstats //授予执行权限
[root@hadoop1 ~]# ./zkstats hadoop1 node-{0001..0003}
hadoop1 Mode: observer
node-0001 Mode: follower
node-0002 Mode: leader
node-0003 Mode: follower
二、分布式消息队列Kafka
Kafka是由Linkedln开发的一个分布式、高吞吐量、高扩展性的消息队列系统,使用Scale编写,是一个消息中间件,主要应用在日志收集系统和消息系统,它具有高吞吐量、低延迟、可扩展性和容错性等特点。其他的消息队列中间件比如RabbitMQ、AcitveMQ。
1、Kafka的架构与设计
一个Kafka集群包含一个或多个的Producer,一个或多个的Broker,一个或多个的Consumer Group,和一个Zookeeper集群。Kafka通过Zookeeper管理集群配置,管理集群在运行过程中负责均衡、故障转移和恢复;Producer使用Push(推送)的方式将消息发布到Broker,Consumer使用Pull(拉取)的方式从Broker获取消息,两者都是主动操作的。
集群结构示例:
图中包含了2个Producer(生产者),一个Topic(主题),3个Partition(分区),3个Replica(副本),3个Broker(Kafka实例或节点),一个Consumer Group(消费者组),其中包含3个Consumer(消费者)
2、集群的角色:
① Producer 生产者
负责发布消息,生产者每发送一个条消息必须有一个Topic(主题),也可以说是消息的类别,生产者源源不断的向kafka服务器发送消息。
- 定义:生产者是向 Kafka 发布消息的应用程序。
- 职责:将消息发送到指定的 Topic 和分区。
② Topic主题
每一个发送到Kafka的消息都有一个主题,也可叫做一个类别;
- 定义:Topic 是消息的逻辑分类,生产者将消息发布到特定的 Topic,消费者订阅 Topic 以接收消息。
- 分区:每个 Topic 可以分为多个分区(Partition),分区是 Kafka 并行处理和扩展性的基础。
③ Partition 分区
生产者发送的消息数据Topic会被存储在分区中,这个分区的概念和ElasticSearch中分片的概念是一致的,都是想把数据分成多个块,好达到负载均衡的效果;
- 定义:分区是 Topic 的物理存储单元,分布在不同的 Broker 上。
- 特点:每个分区是一个有序的、不可变的消息序列,新消息被追加到分区的末尾。
④ Replica 副本
副本就是分区中数据的备份,是Kafka为了防止数据丢失或者服务器宕机采取的保护数据完整性的措施;
⑤ Broker 实例或节点
即Kafka的实例,启动一个Kafka就是一个Broker,多个Broker构成一个Kafka集群,这就是分布式的体现,服务器多了自然吞吐率效率提升。
- 定义:Kafka 集群中的每个服务器称为 Broker。
- 职责:负责存储和处理消息,处理生产者和消费者的请求。
⑥ consumer 消费者
Consume消费者来读取Kafka中的消息,可以消费任何Topic的数据,多个Consume组成一个消费者组,一般的一个消费者必须有一个组(Group)名,如果没有的话会被分一个默认的组名。
- 定义:消费者是从 Kafka 订阅和读取消息的应用程序。
- 职责:从指定的 Topic 和分区读取消息,并处理这些消息。
Kafka对消息保存时根据Topic进行归类,发送消息者成为Producer,消息接受者成为Consumer,此外Kafka集群有多个Kafka实例组成,每个实例(server)成为broker。无论是Kafka集群,还是producer和consumer都依赖于zookeeper来保证系统可用性集群保存一些meta元数据,Kafka将元数据信息保存到Zookeeper中,Broker会在Zookeeper注册并保持相关的元数据更新;
3、Kafka 核心概念
消息(Message):
- 定义:消息是 Kafka 中的基本数据单元,包含数据和元数据。
- 特点:消息被发布到 Topic 并存储在分区中。
偏移量(Offset):
- 定义:偏移量是分区中每条消息的唯一标识符,表示消息在分区中的位置。
- 特点:消费者通过偏移量来跟踪已消费的消息。
副本(Replica):
- 定义:副本是分区的备份,分布在不同的 Broker 上,确保数据的容错性。
- 特点:每个分区有一个 Leader 副本和多个 Follower 副本,Leader 处理读写请求,Follower 同步 Leader 的数据。
ISR(In-Sync Replica):
- 定义:ISR 是与 Leader 保持同步的副本集合。
- 特点:只有 ISR 中的副本才能参与 Leader 选举和写操作。
-
Kafka安装目录:/usr/local/kafka
-
Kafka配置文件:/usr/local/kafka/config/server.properties
Kafka集群部署示例:
|-----------|--------------|----------|----------|
| 主机名称 | IP地址 | 相关配置 | 角色 |
| hadpoo1 | 192.168.1.50 | 最低配置2核4G | Observer |
| node-0001 | 192.168.1.51 | 最低配置2核4G | 自动选举分配 |
| node-0002 | 192.168.1.52 | 最低配置2核4G | 自动选举分配 |
| node-0003 | 192.168.1.53 | 最低配置2核4G | 自动选举分配 |
步骤1:安装配置 kafka,并同步给其他主机(hadoop1操作)
拷贝云盘 public/hadoop/kafka_2.12-2.1.0.tgz 到 hadoop1
bash
[root@ecs-proxy hadoop]# scp kafka_2.12-2.1.0.tgz 192.168.1.50:/root
[root@hadoop1 ~]# tar -zxf kafka_2.12-2.1.0.tgz
[root@hadoop1 ~]# mv kafka_2.12-2.1.0 /usr/local/kafka
[root@hadoop1 ~]# ls /usr/local/kafka/
bash
[root@hadoop1 ~]# for i in node-{0001..0003};do
> rsync -aXSH --delete /usr/local/kafka ${i}:/usr/local/
> done
步骤2:修改配置文件并启动服务(node-0001、node-0002、node-0003操作)
bash
[root@node-0001 ~]# vim /usr/local/kafka/config/server.properties
21 broker.id=1 //broker.id,集群中唯一标识(不能冲突)
123 zookeeper.connect=node-0001:2181,node-0002:2181,node-0003:2181 // 指定zookeeper集群地址
[root@node-0001 ~]# /usr/local/kafka/bin/kafka-server-start.sh -daemon /usr/local/kafka/config/server.properties //启动所有主机的服务
补充:broker.id为每一个broker在集群中的唯一标识,要求是正数。当该服务器的IP地址发生改变时,broker.id没有变化,则不会影响consumers的消息情况;
步骤3:验证集群服务,发布订阅(不同主机上执行)
① Node-0001上,创建topic的消息类别
bash
[root@node-0001 ~]# /usr/local/kafka/bin/kafka-topics.sh --create --partitions 1 --replication-factor 1 --zookeeper localhost:2181 --topic mymsg
Created topic "mymsg".
② Node-0002上,运行生产者程序
bash
[root@node-0002 ~]# /usr/local/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic mymsg
>
③ Node-0003上,运行消费者程序
bash
[root@node-0003 ~]# /usr/local/kafka/bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic mymsg
在Node-0002上随意输入字符串或其他,查看Node-0003是否同步
三、Hadoop高可用集群
1、NameNode高可用
想实现Hadoop高可用就必须实现NameNode的高可用,NameNode是HDFS的核心,HDFS又是Hadoop的核心组件,所以NameNode在Hadoop集群中至关重要;
NameNode宕机,将导致整个集群不可用,且NameNode上存储了文件块映射信息表,如果NameNode数据丢失将导致整个集群的数据丢失,而NameNode的数据的更新又比较频繁,所以NameNode的高可用配置势在必行;
官方提供了两种解决方案:
- ① HDFS with NFS
- ② HDFS with QJM
方案对比:
- ① 都能实现热备;
- ② 都是一个Active和一个Standby;
- ③ 都使用Zookeeper和ZKFC来实现高可用;
- ④ NFS方案:把数据存储在共享存储里,还需要考虑NFS的高可用设计;
- ⑤ QJM方案:不需要共享存储,但需要让每一个DataNode都知道两个NameNode的位置,并把块信息和心跳包发送给Active和Standby这两个NameNode;
2、QJM方案分析
为HDFS集群配置两个NameNode,一个处于Active状态,另一个处于Standby状态,Active NameNode对外提供服务,而Standby则仅监听和同步Active的状态,以便能够在Active失效时进行切换;在任何时候只能有一个NameNode处于活动状态,如果出现两个Active NameNode(这种情况通常称为"split-brain脑裂",三个节点通讯阻断)会导致集群操作混乱,可能会导致数据丢失或状态异常;
① fsimage数据块映射信息,一致性
NameNode更新很频繁,为了保持主备数据的一致性,为了支持快速Failover故障切换,Standby NameNode持有集群中block块映射信息表的最新位置是非常必要的,为了达到这一目的,DataNodes上需要同时配置这两个NameNode的地址,同时和它们都建立心跳连接,并把客户端存储的block块信息位置汇报给两个NameNode生成fsimage,从而实现一致性;
② fsedit数据变更日志,主从同步
为了让Standby NameNode与Active NameNode保持同步,这两个NameNode都与一组称为JNS的互相独立的进程保持通信(Journal Nodes),当Active NameNode更新了,它将记录修改日志发送给Journal Node,Standby Node将会从Journal Node中读取这些日志,将日志变更应用在自己的数据中,并持续关注它们对日志的变更;
③ 主备切换
当Failover故障发生时,Standby Node首先读取Journal Node中所有的日志,并将它应用到自己的数据中;
获取Journal Node写权限:对于Journal Node而言,任何时候只允许一个NameNode作为Writer,在Failover期间,原来的Standby NameNode将会接管Active的所有职能,并负责向Journal Node写入日志记录;提升自己为Active NameNode;
高可用架构图:
-
- ZK为Zookeeper集群,用来存储元数据,保证元数据的一致性;
-
- Failover Controller为ZKFC,用来监控NameNode的存活状态;
-
- Journal Nodes用来记录Active NameNode的修改日志
Hadoop高可用集群部署示例:
高可用架构图:
-
- HDFS:NameNode ---> DataNode
-
- YARN:ResourceManager ---> NodeManager
-
- Zookeeper:QuorumPeerMain
-
- Journal Node:JournalNode
-
- ZKFC:DFSZKFailoverController
主机规划配置
步骤1:Standby NameNode节点-环境准备
① 配置主机名解析文件(hadoop1操作)
bash
[root@hadoop1 ~]# vim /etc/hosts
192.168.1.50 hadoop1
192.168.1.56 hadoop2 //添加hadoop2
192.168.1.51 node-0001
192.168.1.52 node-0002
192.168.1.53 node-0003
② 同步SSH密钥给hadoop2主机
bash
[root@hadoop1 ~]# rsync -aXSH --delete /root/.ssh hadoop2:/root/
补充:将整个/root/.ssh/目录中私钥和密钥同步到hadoop2,实现免密登录其它节点;
③ 同步主机名解析文件给所有主机
bash
[root@hadoop1 ~]# for i in hadoop2 node-{0001..0003};do
> rsync -av /etc/hosts ${i}:/etc/
> done
④ 安装JAVA运行环境(hadoop2操作)
bash
[root@hadoop2 ~]# yum install -y java-1.8.0-openjdk-devel
⑤ 禁用ssh key检测
bash
[root@hadoop2 ~]# vim /etc/ssh/ssh_config
60: StrictHostKeyChecking no
步骤2:HDFS集群配置部署(hadoop1操作)
官方手册:Apache Hadoop 2.7.7 -- HDFS High Availability Using the Quorum Journal Manager
① 修改环境配置文件:hadoop-env.sh
bash
[root@hadoop1 ~]# vim /usr/local/hadoop/etc/hadoop/hadoop-env.sh
25: export JAVA_HOME="/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.292.b10-1.el7_9.x86_64/"
33: export HADOOP_CONF_DIR="/usr/local/hadoop/etc/hadoop"
② 修改节点配置文件:slaves
bash
[root@hadoop1 ~]# vim /usr/local/hadoop/etc/hadoop/slaves
node-0001
node-0002
node-0003
③ 修改核心配置文件:core-site.xml
bash
[root@hadoop1 ~]# vim /usr/local/hadoop/etc/hadoop/core-site.xml
<configuration>
<property>
<name>fs.defaultFS</name> //定义文件系统
<value>hdfs://mycluster</value> //指定NameNode组(与后面的定义组名要一致)
</property>
<property>
<name>hadoop.tmp.dir</name> //数据目录配置参数
<value>/var/hadoop</value> //定义数据存放目录
</property>
<property>
<name>ha.zookeeper.quorum</name> //指定Zookeeper集群服务地址
<value>node-0001:2181,node-0002:2181,node-0003:2181</value>
</property>
<property>
<name>hadoop.proxyuser.nfsuser.groups</name> //NFSGW相关授权(不影响)
<value>*</value>
</property>
<property>
<name>hadoop.proxyuser.nfsuser.hosts</name> //NFSGW相关授权(不影响)
<value>*</value>
</property>
</configuration>
补充1:指定文件系统时,无法确定哪台NameNode作为Active节点,所以指定组
补充2:指定Zookeeper集群节点地址时,同时配置多个节点防止单点故障;
④ 修改分布式文件系统配置文件:hdfs-site.xml
bash
[root@hadoop1 ~]# vim /usr/local/hadoop/etc/hadoop/hdfs-site.xml
<configuration>
<property>
<name>dfs.nameservices</name> //定义NameNode组名(与core-site保持一致)
<value>mycluster</value>
</property>
<property>
<name>dfs.ha.namenodes.mycluster</name> //定义HDFS服务中的角色
<value>nn1,nn2</value> //nn1代表NameNode1,nn2代表NameNode2
</property>
<property>
<name>dfs.namenode.rpc-address.mycluster.nn1</name> //定义角色nn1对应主机
<value>hadoop1:8020</value> //指定rpc地址及端口
</property>
<property>
<name>dfs.namenode.rpc-address.mycluster.nn2</name> //定义角色nn2对应主机
<value>hadoop2:8020</value> //指定rpc地址及端口
</property>
<property>
<name>dfs.namenode.http-address.mycluster.nn1</name> //定义角色nn1对应NameNode1
<value>hadoop1:50070</value> //指定NameNode1的地址及端口号
</property>
<property>
<name>dfs.namenode.http-address.mycluster.nn2</name> //定义角色nn2对应NameNode1
<value>hadoop2:50070</value> //指定NameNode2的地址及端口号
</property>
<property>
<name>dfs.namenode.shared.edits.dir</name> //定义JournalNode集群的地址及端口号
<value>qjournal://node-0001:8485;node-0002:8485;node-0003:8485/mycluster</value>
</property>
<property>
<name>dfs.journalnode.edits.dir</name> //定义JournalNode的数据存放地址
<value>/var/hadoop/journal</value>
</property>
<property>
<name>dfs.client.failover.proxy.provider.mycluster</name> //Failover类服务名
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
<property>
<name>dfs.ha.fencing.methods</name> //远程管理方式
<value>sshfence</value> //使用SSH远程管理
</property>
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name> //定义SSH私钥的位置
<value>/root/.ssh/id_rsa</value> //SSH私钥存放地址
</property>
<property>
<name>dfs.ha.automatic-failover.enabled</name> //开启故障转移切换功能
<value>true</value>
</property>
<property>
<name>dfs.replication</name> //定义副本数量
<value>2</value>
</property>
<property>
<name>dfs.hosts.exclude</name> //移除主机列表(不影响)
<value>/usr/local/hadoop/etc/hadoop/exclude</value>
</property>
</configuration>
步骤3:Mapreduce分布式离线计算框架(Hadoop1操作)
① 修改计算框架配置文件:mapred-site.xml
bash
[root@hadoop1 ~]# vim /usr/local/hadoop/etc/hadoop/mapred-site.xml
<configuration>
<property>
<name>mapreduce.framework.name</name> //定义资源管理类
<value>yarn</value>
</property>
</configuration>
步骤4:YARN集群配置部署(Hadoop1操作)
① 修改资源管理配置文件:yarn-site.xml
bash
[root@hadoop1 ~]# vim /usr/local/hadoop/etc/hadoop/yarn-site.xml
<configuration>
<property>
<name>yarn.resourcemanager.ha.enabled</name> //激活HA配置
<value>true</value>
</property>
<property>
<name>yarn.resourcemanager.recovery.enabled</name> //管理节点状态自动恢复
<value>true</value>
</property>
<property>
<name>yarn.resourcemanager.store.class</name> //数据状态保存介质
<value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore</value>
</property>
<property>
<name>yarn.resourcemanager.zk-address</name> //Zookeeper服务器地址
<value>node-0001:2181,node-0002:2181,node-0003:2181</value>
</property>
<property>
<name>yarn.resourcemanager.cluster-id</name> //定义集群ID
<value>yarn-ha</value>
</property>
<property>
<name>yarn.resourcemanager.ha.rm-ids</name> //定义两个RM的角色
<value>rm1,rm2</value>
</property>
<property>
<name>yarn.resourcemanager.hostname.rm1</name> //rm1对应主机地址
<value>hadoop1</value>
</property>
<property>
<name>yarn.resourcemanager.hostname.rm2</name> //rm2对应主机地址
<value>hadoop2</value>
</property>
<!-- Site specific YARN configuration properties -->
<property>
<name>yarn.nodemanager.aux-services</name> //计算框架配置
<value>mapreduce_shuffle</value>
</property>
</configuration>
步骤5:初始化启动集群
重启所有机器,包括hadoop1、hadoop2、node-0001、node-0002、node-0003
① 启动Zookeeper(node-0001、node-0002、node-0003操作)
bash
[root@node-0001 ~]# /usr/local/zookeeper/bin/zkServer.sh start
[root@node-0002 ~]# /usr/local/zookeeper/bin/zkServer.sh start
[root@node-0003 ~]# /usr/local/zookeeper/bin/zkServer.sh start
在hadoop1上,使用脚本验证
bash
[root@hadoop1 ~]# ./zkstats node-{0001..0003} //投票自动选举
node-0001 Mode: follower
node-0002 Mode: leader
node-0003 Mode: follower
② 清空日志和实验数据,并同步配置文件(hadoop1操作)
bash
[root@hadoop1 ~]# rm -rf /var/hadoop/* /usr/local/hadoop/logs
[root@hadoop1 ~]# for i in hadoop2 node-{0001..0003};do
> rsync -av /etc/hosts ${i}:/etc/
> rsync -aXSH --delete /var/hadoop ${i}:/var/
> rsync -aXSH --delete /usr/local/hadoop ${i}:/usr/local/
> done
③ 启动 JournalNode 服务(node-0001、node-0002、node-0003操作)
bash
[root@node-0001 ~]# /usr/local/hadoop/sbin/hadoop-daemon.sh start journalnode
starting journalnode, logging to /usr/local/hadoop/logs/hadoop-root-journalnode-node-0001.out
[root@node-0001 ~]# jps
bash
[root@node-0002 ~]# /usr/local/hadoop/sbin/hadoop-daemon.sh start journalnode
[root@node-0003 ~]# /usr/local/hadoop/sbin/hadoop-daemon.sh start journalnode
④ 初始化集群(hadoop1操作)
# 格式化Zookeeper
bash
[root@hadoop1 ~]# /usr/local/hadoop/bin/hdfs zkfc -formatZK
# 格式化HDFS
bash
[root@hadoop1 ~]# /usr/local/hadoop/bin/hdfs namenode -format
# 格式化JournalNode
bash
[root@hadoop1 ~]# /usr/local/hadoop/bin/hdfs namenode -initializeSharedEdits
补充:格式化的本质就是生成数据结构,其中包括随机的UUID,主节点和备节点的UUID要求保持一致,所以需要将主节点的数据结构拷贝给备节点,实现数据结构一致;
bash
[root@hadoop1 ~]# tree /var/hadoop/
拷贝hadoop1的数据结构给hadoop2
bash
[root@hadoop1 ~]# rsync -aXSH --delete /var/hadoop/dfs hadoop2:/var/hadoop/
⑤ 停止JournalNode 服务(node-0001、node-0002、node-0003操作)
bash
[root@node-0001 ~]# /usr/local/hadoop/sbin/hadoop-daemon.sh stop journalnode
stopping journalnode
[root@node-0002 ~]# /usr/local/hadoop/sbin/hadoop-daemon.sh stop journalnode
stopping journalnode
[root@node-0003 ~]# /usr/local/hadoop/sbin/hadoop-daemon.sh stop journalnode
stopping journalnode
⑥ 启动集群(hadoop1、hadoop2操作)
bash
[root@hadoop1 ~]# /usr/local/hadoop/sbin/start-all.sh
bash
[root@hadoop2 ~]# /usr/local/hadoop/sbin/yarn-daemon.sh start resourcemanager
步骤6:验证集群
bash
[root@hadoop1 ~]# /usr/local/hadoop/bin/hdfs haadmin -getServiceState nn1
standby
[root@hadoop1 ~]# /usr/local/hadoop/bin/hdfs haadmin -getServiceState nn2
active
[root@hadoop1 ~]# /usr/local/hadoop/bin/yarn rmadmin -getServiceState rm1
active
[root@hadoop1 ~]# /usr/local/hadoop/bin/yarn rmadmin -getServiceState rm2
standby
[root@hadoop1 ~]# /usr/local/hadoop/bin/hdfs dfsadmin -report
bash
[root@hadoop1 ~]# /usr/local/hadoop/bin/yarn node -list
步骤7:使用高可用集群分析数据
bash
[root@hadoop1 ~]# cd /usr/local/hadoop
[root@hadoop1 hadoop]# ./bin/hadoop fs -mkdir /input
[root@hadoop1 hadoop]# ./bin/hadoop fs -put *.txt /input/
[root@hadoop1 hadoop]# ./bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.7.jar wordcount /input /output
[root@hadoop1 hadoop]# ./bin/hadoop fs -cat /output/*
步骤8:验证高可用服务
① 查看当前角色身份状态
bash
[root@hadoop1 ~]# /usr/local/hadoop/bin/hdfs haadmin -getServiceState nn1
standby //nn1为Hadoop1(备节点)
[root@hadoop1 ~]# /usr/local/hadoop/bin/hdfs haadmin -getServiceState nn2
active //nn2为Hadoop2(主节点)
② 停止hadoop2的NameNode服务,查看角色身份状态是否切换
bash
[root@hadoop2 ~]# /usr/local/hadoop/sbin/hadoop-daemon.sh stop namenode
stopping namenode
[root@hadoop1 ~]# /usr/local/hadoop/bin/hdfs haadmin -getServiceState nn2
bash
[root@hadoop1 ~]# /usr/local/hadoop/bin/hdfs haadmin -getServiceState nn1
active
③ 开启hadoop2的NameNode服务,查看角色身份状态变化
bash
[root@hadoop2 ~]# /usr/local/hadoop/sbin/hadoop-daemon.sh start namenode
starting namenode, logging to /usr/local/hadoop/logs/hadoop-root-namenode-hadoop2.out
[root@hadoop1 hadoop]# /usr/local/hadoop/bin/hdfs haadmin -getServiceState nn1
active
[root@hadoop1 hadoop]# /usr/local/hadoop/bin/hdfs haadmin -getServiceState nn2
standby
小结:
本篇章节为**【第五阶段】ARCHITECTURE-DAY5**的学习笔记,这篇笔记可以初步了解到 搭建Zookeeper高可用集群、搭建分布式消息队列kafka、搭建高可用hadoop集群,除此之外推荐参考相关学习网址:
Tip:毕竟两个人的智慧大于一个人的智慧,如果你不理解本章节的内容或需要相关笔记、视频,可私信小安,请不要害羞和回避,可以向他人请教,花点时间直到你真正的理解。