高可用配置
生产环境中,Hadoop 集群需要高可用(HA)配置,避免单点故障。本章将详细介绍 HDFS 和 YARN 的高可用配置方法。
高可用概述
单点故障问题
在非 HA 模式下,存在以下单点故障:
| 组件 | 单点故障影响 |
|---|---|
| NameNode | 整个集群不可用 |
| ResourceManager | 无法提交新作业,运行中的作业不受影响 |
高可用方案
Hadoop 高可用通过主备切换实现:
前置条件
ZooKeeper 集群
高可用依赖 ZooKeeper 进行主备选举和协调:
# 在各 ZooKeeper 节点执行
# 下载 ZooKeeper
wget https://downloads.apache.org/zookeeper/zookeeper-3.8.0/apache-zookeeper-3.8.0-bin.tar.gz
tar -zxvf apache-zookeeper-3.8.0-bin.tar.gz -C /opt/
# 配置 zoo.cfg
cat > /opt/zookeeper/conf/zoo.cfg << EOF
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/opt/zookeeper/data
clientPort=2181
server.1=zk1:2888:3888
server.2=zk2:2888:3888
server.3=zk3:2888:3888
EOF
# 创建 myid 文件
echo "1" > /opt/zookeeper/data/myid
# 启动 ZooKeeper
/opt/zookeeper/bin/zkServer.sh start
SSH 免密登录
确保各节点之间可以免密登录:
# 生成密钥
ssh-keygen -t rsa
# 复制公钥到其他节点
ssh-copy-id node2
ssh-copy-id node3
HDFS 高可用配置
集群规划
以 3 节点集群为例:
| 节点 | NameNode | DataNode | JournalNode | ZooKeeper |
|---|---|---|---|---|
| node1 | Active | - | 是 | 是 |
| node2 | Standby | 是 | 是 | 是 |
| node3 | - | 是 | 是 | 是 |
配置文件
core-site.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 集群名称 -->
<property>
<name>fs.defaultFS</name>
<value>hdfs://mycluster</value>
</property>
<!-- 临时目录 -->
<property>
<name>hadoop.tmp.dir</name>
<value>/opt/hadoop/tmp</value>
</property>
<!-- ZooKeeper 地址 -->
<property>
<name>ha.zookeeper.quorum</name>
<value>node1:2181,node2:2181,node3:2181</value>
</property>
<!-- 代理用户 -->
<property>
<name>hadoop.proxyuser.hadoop.hosts</name>
<value>*</value>
</property>
<property>
<name>hadoop.proxyuser.hadoop.groups</name>
<value>*</value>
</property>
</configuration>
hdfs-site.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 定义集群名称 -->
<property>
<name>dfs.nameservices</name>
<value>mycluster</value>
</property>
<!-- 定义 NameNode 标识 -->
<property>
<name>dfs.ha.namenodes.mycluster</name>
<value>nn1,nn2</value>
</property>
<!-- NameNode RPC 地址 -->
<property>
<name>dfs.namenode.rpc-address.mycluster.nn1</name>
<value>node1:8020</value>
</property>
<property>
<name>dfs.namenode.rpc-address.mycluster.nn2</name>
<value>node2:8020</value>
</property>
<!-- NameNode HTTP 地址 -->
<property>
<name>dfs.namenode.http-address.mycluster.nn1</name>
<value>node1:9870</value>
</property>
<property>
<name>dfs.namenode.http-address.mycluster.nn2</name>
<value>node2:9870</value>
</property>
<!-- JournalNode 地址 -->
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://node1:8485;node2:8485;node3:8485/mycluster</value>
</property>
<!-- JournalNode 数据目录 -->
<property>
<name>dfs.journalnode.edits.dir</name>
<value>/opt/hadoop/data/journalnode</value>
</property>
<!-- 故障转移代理类 -->
<property>
<name>dfs.client.failover.proxy.provider.mycluster</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
<!-- 隔离机制 -->
<property>
<name>dfs.ha.fencing.methods</name>
<value>sshfence</value>
</property>
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/home/hadoop/.ssh/id_rsa</value>
</property>
<property>
<name>dfs.ha.fencing.ssh.connect-timeout</name>
<value>30000</value>
</property>
<!-- 启用自动故障转移 -->
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
<!-- 数据目录 -->
<property>
<name>dfs.namenode.name.dir</name>
<value>/opt/hadoop/data/namenode</value>
</property>
<property>
<name>dfs.datanode.data.dir</name>
<value>/opt/hadoop/data/datanode</value>
</property>
<!-- 副本数 -->
<property>
<name>dfs.replication</name>
<value>3</value>
</property>
<!-- 权限检查 -->
<property>
<name>dfs.permissions.enabled</name>
<value>false</value>
</property>
</configuration>
启动步骤
# 1. 启动 ZooKeeper(在各 ZooKeeper 节点执行)
zkServer.sh start
# 2. 启动 JournalNode(在各 JournalNode 节点执行)
hdfs --daemon start journalnode
# 3. 格式化 NameNode(在第一个 NameNode 执行)
hdfs namenode -format
# 4. 启动第一个 NameNode
hdfs --daemon start namenode
# 5. 同步第二个 NameNode(在第二个 NameNode 执行)
hdfs namenode -bootstrapStandby
# 6. 启动第二个 NameNode
hdfs --daemon start namenode
# 7. 初始化 ZooKeeper 故障转移(在任一 NameNode 执行)
hdfs zkfc -formatZK
# 8. 启动 ZKFC(在各 NameNode 执行)
hdfs --daemon start zkfc
# 9. 启动 DataNode(在各 DataNode 执行)
hdfs --daemon start datanode
验证高可用
# 查看 NameNode 状态
hdfs haadmin -getAllServiceState
# 手动切换 Active
hdfs haadmin -transitionToActive nn2
# 模拟故障
# 杀掉 Active NameNode 进程,观察是否自动切换
kill -9 <namenode-pid>
YARN 高可用配置
集群规划
| 节点 | ResourceManager | NodeManager |
|---|---|---|
| node1 | Active | - |
| node2 | Standby | 是 |
| node3 | - | 是 |
配置文件
yarn-site.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 启用 RM HA -->
<property>
<name>yarn.resourcemanager.ha.enabled</name>
<value>true</value>
</property>
<!-- 集群 ID -->
<property>
<name>yarn.resourcemanager.cluster-id</name>
<value>yarn-cluster</value>
</property>
<!-- RM 标识 -->
<property>
<name>yarn.resourcemanager.ha.rm-ids</name>
<value>rm1,rm2</value>
</property>
<!-- RM 主机名 -->
<property>
<name>yarn.resourcemanager.hostname.rm1</name>
<value>node1</value>
</property>
<property>
<name>yarn.resourcemanager.hostname.rm2</name>
<value>node2</value>
</property>
<!-- RM Web UI 地址 -->
<property>
<name>yarn.resourcemanager.webapp.address.rm1</name>
<value>node1:8088</value>
</property>
<property>
<name>yarn.resourcemanager.webapp.address.rm2</name>
<value>node2:8088</value>
</property>
<!-- ZooKeeper 地址 -->
<property>
<name>yarn.resourcemanager.zk-address</name>
<value>node1:2181,node2:2181,node3:2181</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>
<!-- NodeManager 配置 -->
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.nodemanager.resource.memory-mb</name>
<value>8192</value>
</property>
<property>
<name>yarn.nodemanager.resource.cpu-vcores</name>
<value>8</value>
</property>
<!-- 调度器配置 -->
<property>
<name>yarn.scheduler.minimum-allocation-mb</name>
<value>1024</value>
</property>
<property>
<name>yarn.scheduler.maximum-allocation-mb</name>
<value>8192</value>
</property>
<!-- 日志聚合 -->
<property>
<name>yarn.log-aggregation-enable</name>
<value>true</value>
</property>
</configuration>
启动步骤
# 1. 确保 ZooKeeper 已启动
# 2. 启动 ResourceManager(在各 RM 节点执行)
yarn --daemon start resourcemanager
# 3. 启动 NodeManager(在各 NM 节点执行)
yarn --daemon start nodemanager
验证高可用
# 查看 RM 状态
yarn rmadmin -getAllServiceState
# 手动切换 Active
yarn rmadmin -transitionToActive rm2
# 模拟故障
kill -9 <rm-pid>
故障转移控制器
ZKFC(ZooKeeper Failover Controller)
ZKFC 运行在每个 NameNode 上,负责:
- 健康检查:定期检查 NameNode 状态
- 会话管理:维护与 ZooKeeper 的会话
- 选举触发:当 Active 故障时触发选举
ZKFC 配置
<!-- 健康检查间隔 -->
<property>
<name>ha.zookeeper.acl-znode-parent</name>
<value>/hadoop-ha/mycluster</value>
</property>
<!-- 健康检查超时 -->
<property>
<name>ha.failover-controller.new-active.rpc-timeout.ms</name>
<value>60000</value>
</property>
运维操作
手动故障转移
# HDFS 手动切换
hdfs haadmin -transitionToStandby nn1
hdfs haadmin -transitionToActive nn2
# YARN 手动切换
yarn rmadmin -transitionToStandby rm1
yarn rmadmin -transitionToActive rm2
查看状态
# 查看 HDFS NameNode 状态
hdfs haadmin -getAllServiceState
hdfs haadmin -getServiceState nn1
# 查看 YARN ResourceManager 状态
yarn rmadmin -getAllServiceState
yarn rmadmin -getServiceState rm1
故障恢复
当 Active 节点故障恢复后:
# 启动恢复的节点
hdfs --daemon start namenode
# 查看状态(应该是 Standby)
hdfs haadmin -getServiceState nn1
# 如需切换为 Active
hdfs haadmin -transitionToActive nn1
小结
本章介绍了 Hadoop 高可用的配置方法:
-
HDFS 高可用:通过 Active/Standby NameNode 和 JournalNode 实现。
-
YARN 高可用:通过 Active/Standby ResourceManager 和 ZooKeeper 实现。
-
故障转移:ZKFC 自动检测故障并触发切换。
高可用配置是生产环境部署的必备条件,可以避免单点故障导致的集群不可用问题。