Bootstrap

Linux云计算 |【第五阶段】ARCHITECTURE-DAY5

主要内容:

搭建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 集群的状态和性能

常见问题和解决方案

  1. 网络分区:确保网络稳定,使用冗余网络连接,避免单点故障。
  2. Leader 选举失败:检查网络连接和配置参数,确保 Quorum 机制正常工作。
  3. 数据一致性问题:使用 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 文件,配置示例:

​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

[root@ecs-proxy hadoop]# scp zookeeper-3.4.13.tar.gz 192.168.1.50:/root

① 安装JAVA运行环境,并准备Zookeepeer安装目录(已完成)

[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),如果组建集群,在配置文件末尾添加集群节点成员,即成为集群模式

[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主机

[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定义,需在所有节点创建数据存储目录

[root@hadoop1 conf]# cat zoo.cfg

① 创建数据存储目录(以hadoop1为例)

[root@hadoop1 ~]# mkdir /tmp/zookeeper

② 创建myid文件,文件内容为主机运行id

# 本机的server.id与myid文件中的id必须对应,id的范围是1~255

[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

② 启动集群服务

[root@hadoop1 ~]# /usr/local/zookeeper/bin/zkServer.sh start

③ 验证角色

[root@hadoop1 ~]# jps

④ 当所有节点集群服务启动完成后,使用命令验证

[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工具来实现网络接口、数据报文格式发送;

[root@hadoop1 ~]# yum install -y socat        //安装socat工具
[root@hadoop1 ~]# socat - TCP:node-0001:2181
ruok         //监测健康状态(交互界面)
imok

说明:标准输入ruok,转发给第二个地址处理,并通过标准输出返回结果imok;

解释:socat用途是把一组数据发送给第一个地址,再转发给第二个地址,让两个地址之间能够互相传输和通信;默认需要2组参数:

① -为占位符,表示默认地址,而默认地址即本地的标准输入输出键盘、鼠标显示器;

② 第二个地址是网络地址,协议是TCP、主机、端口号

[root@hadoop1 ~]# socat - TCP:node-0001:2181
conf         //配置文件conf

[root@hadoop1 ~]# socat - TCP:node-0001:2181
mntr          //集群状态mntr

 

例如2:使用zkstats脚本,查看Zookeeper各个服务器角色

[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

[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/

[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操作)

[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的消息类别

[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上,运行生产者程序

[root@node-0002 ~]# /usr/local/kafka/bin/kafka-console-producer.sh --broker-list  localhost:9092 --topic mymsg
> 

③ Node-0003上,运行消费者程序

[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操作)

[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主机

[root@hadoop1 ~]# rsync -aXSH --delete /root/.ssh hadoop2:/root/

补充:将整个/root/.ssh/目录中私钥和密钥同步到hadoop2,实现免密登录其它节点;

③ 同步主机名解析文件给所有主机

[root@hadoop1 ~]# for i in hadoop2 node-{0001..0003};do
> rsync -av /etc/hosts ${i}:/etc/
> done

④ 安装JAVA运行环境(hadoop2操作)

[root@hadoop2 ~]# yum install -y java-1.8.0-openjdk-devel

⑤ 禁用ssh key检测

[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

[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

[root@hadoop1 ~]# vim /usr/local/hadoop/etc/hadoop/slaves
node-0001
node-0002
node-0003

③ 修改核心配置文件:core-site.xml

[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

[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

[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

[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操作)

[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上,使用脚本验证

[root@hadoop1 ~]# ./zkstats node-{0001..0003}      //投票自动选举
      node-0001 Mode: follower
      node-0002 Mode: leader
      node-0003 Mode: follower

② 清空日志和实验数据,并同步配置文件(hadoop1操作)

[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操作)

[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

[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

[root@hadoop1 ~]# /usr/local/hadoop/bin/hdfs zkfc -formatZK

# 格式化HDFS

[root@hadoop1 ~]# /usr/local/hadoop/bin/hdfs namenode -format

# 格式化JournalNode

[root@hadoop1 ~]# /usr/local/hadoop/bin/hdfs namenode -initializeSharedEdits

补充:格式化的本质就是生成数据结构,其中包括随机的UUID,主节点和备节点的UUID要求保持一致,所以需要将主节点的数据结构拷贝给备节点,实现数据结构一致;

[root@hadoop1 ~]# tree /var/hadoop/

# 拷贝hadoop1的数据结构给hadoop2

[root@hadoop1 ~]# rsync -aXSH --delete /var/hadoop/dfs hadoop2:/var/hadoop/

⑤ 停止JournalNode 服务(node-0001、node-0002、node-0003操作)

[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操作)

[root@hadoop1 ~]# /usr/local/hadoop/sbin/start-all.sh

[root@hadoop2 ~]# /usr/local/hadoop/sbin/yarn-daemon.sh start resourcemanager

步骤6:验证集群

[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

[root@hadoop1 ~]# /usr/local/hadoop/bin/yarn node -list

步骤7:使用高可用集群分析数据

[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:验证高可用服务

① 查看当前角色身份状态

[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服务,查看角色身份状态是否切换

[root@hadoop2 ~]# /usr/local/hadoop/sbin/hadoop-daemon.sh stop namenode
stopping namenode

[root@hadoop1 ~]# /usr/local/hadoop/bin/hdfs haadmin -getServiceState nn2

[root@hadoop1 ~]# /usr/local/hadoop/bin/hdfs haadmin -getServiceState nn1
active

③ 开启hadoop2的NameNode服务,查看角色身份状态变化

[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:毕竟两个人的智慧大于一个人的智慧,如果你不理解本章节的内容或需要相关笔记、视频,可私信小安,请不要害羞和回避,可以向他人请教,花点时间直到你真正的理解。

;