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 文件,配置示例:

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

相关推荐
A小辣椒1 天前
TShark:Wireshark CLI 功能
linux
A小辣椒2 天前
TShark:基础知识
linux
AlfredZhao2 天前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao2 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334662 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪3 天前
linux 拷贝文件或目录到指定的位置
linux
大树883 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠3 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质3 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
bush43 天前
嵌入式linux学习记录十四、术语
linux·嵌入式