Hadoop HA高可用

HA概述

  • 所谓HA(High Availablity),即高可用(7*24小时不中断服务)
  • 实现高可用最关键的策略是消除单点故障。HA严格来说应该分成各个组件的HA机制:
    • HDFS的HA
    • YARN的HA
  • NameNode主要在以下两个方面影响HDFS集群
    • NameNode机器发生意外,如宕机,集群将无法使用,直到管理员重启
    • NameNode机器需要升级,包括软件、硬件升级,此时集群也将无法使用
  • HDFS HA功能通过配置多个NameNodes(Active/Standby)实现在集群中对NameNode的热备来解决上述问题。如果出现故障,如机器崩溃或机器需要升级维护,这时可通过此种方式将NameNode很快的切换到另外一台机器。

    HDFS-HA集群搭建

    现有HDFS集群的规划

    | hadoop102 | hadoop103 | hadoop104 | | —- | —- | —- | | NameNode | | SecondaryNameNode | | DataNode | DataNode | DataNode |

HA规划

  • HA的主要目的是消除NameNode的单点故障,需要将hdfs集群规划如下 | hadoop102 | hadoop103 | hadoop104 | | —- | —- | —- | | NameNode | NameNode | NameNode | | DataNode | DataNode | DataNode |

HDFS-HA核心问题

怎么保证三台NameNode的数据一致

  • Fsimage:让一台nn生成数据,让其它机器nn同步
  • Edits:需要引进新的模块JournalNode来保证 edits的文件的数据一致性

    怎么同时让只有一台nn是active,其它都是standby

  • 手动分配

  • 自动分配

    2nn在ha架构中并不存在,定期合并fsimage和edits的活谁来干?

  • 由standby的nn来干

    如果nn真的发生了问题,怎么让其它的nn上位干活

  • 手动故障转移

  • 自动故障转移

    HDFS-HA手动模式

    环境准备

  • 修改IP

  • 修改主机名及主机名和IP地址映射
  • 关闭防火墙
  • ssh免密登录
  • 安装JDK、配置环境变量等

    规划机器

    | hadoop102 | hadoop103 | hadoop104 | | —- | —- | —- | | NameNode | NameNode | NameNode | | JournalNode | JournalNode | JournalNode | | DataNode | DataNode | DataNode |

配置HDFS-HA集群

  • 官方地址:http://hadoop.apache.org/
  • 在opt目录下创建一个ha文件夹
    • cd /opt
    • mkdir ha
  • /opt/module下的hadoop-3.1.3拷贝到 /opt/ha目录下(记得删除data和logs目录)
    • cp -r /opt/module/hadoop-3.1.3 /opt/ha/
  • 配置core-site.xml

    1. <configuration>
    2. <!-- 把多个NameNode的地址组装成一个集群mycluster -->
    3. <property>
    4. <name>fs.defaultFS</name>
    5. <value>hdfs://mycluster</value>
    6. </property>
    7. <!-- 指定hadoop数据的存储目录 -->
    8. <property>
    9. <name>hadoop.tmp.dir</name>
    10. <value>/opt/ha/hadoop-3.1.3/data</value>
    11. </property>
    12. </configuration>
  • 配置 hdfs-site.xml

    <configuration>
    <!-- NameNode 数据存储目录 -->
    <property>
       <name>dfs.namenode.name.dir</name>
       <value>file://${hadoop.tmp.dir}/name</value>
    </property>
    
    <!-- DataNode 数据存储目录 -->
    <property>
       <name>dfs.datanode.data.dir</name>
       <value>file://${hadoop.tmp.dir}/data</value>
    </property>
    
    <!-- JournalNode 数据存储目录 -->
    <property>
       <name>dfs.journalnode.edits.dir</name>
       <value>${hadoop.tmp.dir}/jn</value>
    </property>
    
    <!-- 完全分布式集群名称 -->
    <property>
       <name>dfs.nameservices</name>
       <value>mycluster</value>
    </property>
    
    <!-- 集群中 NameNode 节点都有哪些 -->
    <property>
       <name>dfs.ha.namenodes.mycluster</name>
       <value>nn1,nn2,nn3</value>
    </property>
    
    <!-- NameNode 的 RPC 通信地址 --> 
    <property>
       <name>dfs.namenode.rpc-address.mycluster.nn1</name>
       <value>hadoop102:8020</value>
    </property>
    <property>
       <name>dfs.namenode.rpc-address.mycluster.nn2</name>
       <value>hadoop103:8020</value>
    </property>
    <property>
       <name>dfs.namenode.rpc-address.mycluster.nn3</name>
       <value>hadoop104:8020</value>
    </property>
    
    <!-- NameNode 的 http 通信地址 -->
    <property>
       <name>dfs.namenode.http-address.mycluster.nn1</name>
       <value>hadoop102:9870</value>
    </property>
    <property>
       <name>dfs.namenode.http-address.mycluster.nn2</name>
       <value>hadoop103:9870</value>
    </property>
    <property>
       <name>dfs.namenode.http-address.mycluster.nn3</name>
       <value>hadoop104:9870</value>
    </property>
    
    <!-- 指定 NameNode 元数据在 JournalNode 上的存放位置 --> 
    <property>
        <name>dfs.namenode.shared.edits.dir</name>
        <value>qjournal://hadoop102:8485;hadoop103:8485;hadoop104:8485/mycluster</value>
    </property>
    
    <!-- 访问代理类:client 用于确定哪个 NameNode 为 Active -->
    <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>
    
    <!-- 使用隔离机制时需要 ssh 秘钥登录-->
    <property>
       <name>dfs.ha.fencing.ssh.private-key-files</name>
       <value>/root/.ssh/id_rsa</value>
    </property>
    </configuration>
    
  • 分发配置好的hadoop环境到其它节点

    • 先在Hadoop103和hadoop104分别创建 ha目录
    • ./xsync /opt/ha/hadoop-3.1.3/

      启动HDFS-HA集群

      将 Hadoop_HOME 环境变量更改到HA目录(三台机器)

  • vi /etc/profile.d/my_env.sh

  • HADOOP_HOME部分改为如下 ```xml

    JAVA_HOME

    export JAVA_HOME=/opt/module/jdk1.8.0_212 export PATH=$PATH:$JAVA_HOME/bin

HADOOP_HOME

export HADOOP_HOME=/opt/ha/hadoop-3.1.3 export PATH=$PATH:$HADOOP_HOME/bin export PATH=$PATH:$HADOOP_HOME/sbin


- 三台机器全部 `source`环境变量
   - `source /etc/profile`
<a name="u57ys"></a>
#### 在各个 `JournalNode`节点上,输入以下命令启动 `journalnode` 服务

- `[root@hadoop102 ~]# hdfs --daemon start journalnode`
- `[root@hadoop103 ~]# hdfs --daemon start journalnode`
- `[root@hadoop104 ~]# hdfs --daemon start journalnode`
<a name="j0tD8"></a>
#### 在nn1上(hadoop102),对其进行格式化,并启动

- `hdfs namenode -format` //格式化
- `hdfs --daemon start namenode`
<a name="eaphS"></a>
#### 在nn2和nn3上(hadoop103、hadoop104),同步nn1的元数据信息

- `hdfs namenode -bootstrapStandby`
- `hdfs namenode -bootstrapStandby`
<a name="AMykO"></a>
#### 启动nn2和nn3

- `hdfs --daemon start namenode`
- `hdfs --daemon start namenode`
<a name="QblB0"></a>
#### 查看web页面

- ![image.png](https://cdn.nlark.com/yuque/0/2022/png/25955514/1650337703637-91064cdd-f820-412e-b648-77e4249b1157.png#clientId=u50c6f38a-b6e0-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=153&id=u2bc13de9&margin=%5Bobject%20Object%5D&name=image.png&originHeight=478&originWidth=1286&originalType=binary&ratio=1&rotation=0&showTitle=false&size=66345&status=done&style=none&taskId=u40c097dc-3973-427e-aecd-22355018e8a&title=&width=411)
- ![image.png](https://cdn.nlark.com/yuque/0/2022/png/25955514/1650337718605-02de620d-ac7c-4990-b6f1-3ca69712ef5e.png#clientId=u50c6f38a-b6e0-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=155&id=uc8699529&margin=%5Bobject%20Object%5D&name=image.png&originHeight=488&originWidth=1290&originalType=binary&ratio=1&rotation=0&showTitle=false&size=66580&status=done&style=none&taskId=u0d385a8c-eae2-4c71-9675-72435f98d6d&title=&width=411)
- ![image.png](https://cdn.nlark.com/yuque/0/2022/png/25955514/1650337792834-df9da0f8-b2ef-463e-97ed-fa8a6a142715.png#clientId=u50c6f38a-b6e0-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=167&id=u382bf304&margin=%5Bobject%20Object%5D&name=image.png&originHeight=518&originWidth=1278&originalType=binary&ratio=1&rotation=0&showTitle=false&size=66717&status=done&style=none&taskId=u4b2da659-9ec1-4c69-8e2e-12d16915000&title=&width=411)
<a name="xBI5L"></a>
#### 在所有节点上,启动datanode

- `hdfs --daemon start datanode`
<a name="dqGqx"></a>
#### 将nn1切换为Active

- `hdfs haadmin -transitionToActive nn1`
<a name="ebAex"></a>
#### 查看是否Active

- `hdfs haadmin -getServiceState nn1`
- ![image.png](https://cdn.nlark.com/yuque/0/2022/png/25955514/1650337908793-0a6b4ab7-c66e-49ae-80d5-f9dfd0ccf3e0.png#clientId=u50c6f38a-b6e0-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=157&id=u48f4eeae&margin=%5Bobject%20Object%5D&name=image.png&originHeight=520&originWidth=1462&originalType=binary&ratio=1&rotation=0&showTitle=false&size=71828&status=done&style=none&taskId=u32065aae-7a45-4804-b875-405f8bfac9e&title=&width=441)
<a name="PvsrB"></a>
## HDFS-HA自动模式
<a name="uH6S4"></a>
### HDFS-HA自动故障转移工作机制

- 自动故障转移为HDFS部署增加了两个新组件:ZooKeeper和ZKFailoverController(ZKFC)进程,如图所示:ZooKeeper是维护少量协调数据,通知客户端这些数据的改变和监视客户端故障的高可用服务。
- ![image.png](https://cdn.nlark.com/yuque/0/2022/png/25955514/1650338028163-0c1f48b5-b781-4502-968a-d22aee3e187a.png#clientId=u50c6f38a-b6e0-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=366&id=ua4513ef7&margin=%5Bobject%20Object%5D&name=image.png&originHeight=732&originWidth=1434&originalType=binary&ratio=1&rotation=0&showTitle=false&size=182559&status=done&style=none&taskId=u46fda2b5-e456-42ba-a0b3-0a65bc2bac1&title=&width=717)
<a name="VBZ2n"></a>
### HDFS-HA自动故障转移的集群规划
| hadoop102 | hadoop103 | hadoop104 |
| --- | --- | --- |
| NameNode | NameNode | NameNode |
| JournalNode | JournalNode | JournalNode |
| DataNode | DataNode | DataNode |
| Zookeeper | Zookeeper | Zookeeper |
| ZKFC | ZKFC | ZKFC |

<a name="aFTWp"></a>
### 配置HDFS-HA自动故障转移
<a name="Pw7ZE"></a>
#### 具体配置

- 在`hdfs-site.xml`中增加
```xml
<!-- 启用 nn 故障自动转移 --> 
<property>
    <name>dfs.ha.automatic-failover.enabled</name>
    <value>true</value>
</property>
  • core-site.xml文件中增加

    <!-- 指定 zkfc 要连接的 zkServer 地址 --> 
    <property>
      <name>ha.zookeeper.quorum</name>
      <value>hadoop102:2181,hadoop103:2181,hadoop104:2181</value>
    </property>
    
  • 分发配置

    • ./xsync /opt/ha/hadoop-3.1.3/etc/hadoop/

      启动

  • 关闭所有HDFS服务

  • 启动Zookeeper集群
    • zkServer.sh start
  • 启动Zookeeper后,然后再初始化HA的Zookeeper中状态
    • hdfs zkfc -formatZK
  • 启动HDFS服务

    • start-dfs.sh

      解决NN连接不上JN的问题

  • 自动故障转移配置好以后,然后使用 start-dfs.sh群起脚本启动hdfs集群,有可能会遇到NameNode起来一会后,进程自动关闭的问题。查看NameNode日志,报错信息如下:

    2020-08-17 10:11:49,676 INFO org.apache.hadoop.ipc.Client: Retrying connect to server: hadoop103/192.168.6.103:8485. Already tried 9 time(s); retry policy is RetryUpToMaximumCountWithFixedSleep(maxRetries=10, sleepTime=1000 MILLISECONDS)
    2020-08-17 10:11:49,678 WARN org.apache.hadoop.hdfs.server.namenode.FSEditLog: Unable to determine input streams from QJM to [192.168.6.102:8485, 192.168.6.103:8485, 192.168.6.104:8485]. Skipping. org.apache.hadoop.hdfs.qjournal.client.QuorumException: Got too many exceptions to achieve quorum size 2/3. 3 exceptions thrown:
    192.168.6.103:8485: Call From hadoop102/192.168.6.102 to hadoop103:8485 failed on connection exception: java.net.ConnectException: 拒绝连接; For more
    details see: http://wiki.apache.org/hadoop/ConnectionRefused 192.168.6.102:8485: 
    Call From hadoop102/192.168.6.102 to hadoop102:8485 failed on connection exception: 
    java.net.ConnectException: 拒绝连接; For more details see: http://wiki.apache.org/hadoop/ConnectionRefused 192.168.6.104:8485: 
    Call From hadoop102/192.168.6.102 to hadoop104:8485 failed on connection exception:
    java.net.ConnectException: 拒绝连接; For more details see: http://wiki.apache.org/hadoop/ConnectionRefused
    
  • 查看报错日志,可分析出报错原因是因为 NameNode 连接不上 JournalNode,而利 用 jps 命令查看到三台 JN 都已经正常启动,为什么 NN 还是无法正常连接到 JN 呢?这 是因为 start-dfs.sh 群起脚本默认的启动顺序是先启动 NN,再启动 DN,然后再启动 JN, 并且默认的 rpc 连接参数是重试次数为 10,每次重试的间隔是 1s,也就是说启动完 NN 以后的 10s 中内,JN 还启动不起来,NN 就会报错了。

  • 解决方案:可以等JN成功启动后,手动启动下三台NN
    • hdfs --daemon start namenode
  • 也可以在 core-site.xml里适当调大参数

    <!-- NN 连接 JN 重试次数,默认是 10 次 --> 
    <property>
    <name>ipc.client.connect.max.retries</name>
    <value>20</value> </property>
    <!-- 重试时间间隔,默认 1s --> 
    <property>
    <name>ipc.client.connect.retry.interval</name>
    <value>5000</value>
    </property>
    

    YARN-HA配置

    YARN-HA工作机制

  • image.png

    具体配置

  • yarn-site.xml

    <configuration>
    <property>
       <name>yarn.nodemanager.aux-services</name>
       <value>mapreduce_shuffle</value>
    </property>
    <!-- 启用 resourcemanager ha --> <property>
    <name>yarn.resourcemanager.ha.enabled</name>
    <value>true</value>
    </property>
    <!-- 声明两台 resourcemanager 的地址 --> <property>
    <name>yarn.resourcemanager.cluster-id</name>
    <value>cluster-yarn1</value>
    </property>
    <!--指定 resourcemanager 的逻辑列表--> <property>
    <name>yarn.resourcemanager.ha.rm-ids</name>
    <value>rm1,rm2,rm3</value>
    </property>
    <!-- ========== rm1 的配置 ========== --> <!-- 指定 rm1 的主机名 -->
    <property>
    <name>yarn.resourcemanager.hostname.rm1</name>
    <value>hadoop102</value>
    </property>
    <!-- 指定 rm1 的 web 端地址 --> <property>
    <name>yarn.resourcemanager.webapp.address.rm1</name>
    <value>hadoop102:8088</value>
    </property>
    <!-- 指定 rm1 的内部通信地址 --> <property>
    <name>yarn.resourcemanager.address.rm1</name>
    <value>hadoop102:8032</value>
    </property>
    <!-- 指定 AM 向 rm1 申请资源的地址 --> <property>
    <name>yarn.resourcemanager.scheduler.address.rm1</name>
    <value>hadoop102:8030</value>
    </property>
    <!-- 指定供 NM 连接的地址 --> <property>
    <name>yarn.resourcemanager.resource-tracker.address.rm1</name>
    <value>hadoop102:8031</value>
    </property>
    <!-- ========== rm2 的配置 ========== -->
    <!-- 指定 rm2 的主机名 --> <property>
    <name>yarn.resourcemanager.hostname.rm2</name>
    <value>hadoop103</value>
    </property>
    <property>
    <name>yarn.resourcemanager.webapp.address.rm2</name>
    <value>hadoop103:8088</value>
    </property>
    <property>
    <name>yarn.resourcemanager.address.rm2</name>
    <value>hadoop103:8032</value>
    </property>
    <property>
    <name>yarn.resourcemanager.scheduler.address.rm2</name>
    <value>hadoop103:8030</value>
    </property>
    <property>
    <name>yarn.resourcemanager.resource-tracker.address.rm2</name>
    <value>hadoop103:8031</value>
    </property>
    <!-- ========== rm3 的配置 ========== --> <!-- 指定 rm1 的主机名 -->
    <property>
    <name>yarn.resourcemanager.hostname.rm3</name>
    <value>hadoop104</value>
    </property>
    <!-- 指定 rm1 的 web 端地址 --> <property>
    <name>yarn.resourcemanager.webapp.address.rm3</name>
    <value>hadoop104:8088</value>
    </property>
    <!-- 指定 rm1 的内部通信地址 --> <property>
    <name>yarn.resourcemanager.address.rm3</name>
    <value>hadoop104:8032</value>
    </property>
    <!-- 指定 AM 向 rm1 申请资源的地址 --> <property>
    <name>yarn.resourcemanager.scheduler.address.rm3</name>
    <value>hadoop104:8030</value>
    </property>
    <!-- 指定供 NM 连接的地址 --> <property>
    <name>yarn.resourcemanager.resource-tracker.address.rm3</name>
    <value>hadoop104:8031</value>
    </property>
    <!-- 指定 zookeeper 集群的地址 --> <property>
       <name>yarn.resourcemanager.zk-address</name>
       <value>hadoop102:2181,hadoop103:2181,hadoop104:2181</value>
    </property>
    <!-- 启用自动恢复 --> <property>
       <name>yarn.resourcemanager.recovery.enabled</name>
       <value>true</value>
    </property>
    <!-- 指定 resourcemanager 的状态信息存储在 zookeeper 集群 --> <property>
       <name>yarn.resourcemanager.store.class</name>
    <value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateSt
    ore</value>
    </property>
    <!-- 环境变量的继承 --> <property>
          <name>yarn.nodemanager.env-whitelist</name>
    <value>JAVA_HOME,HADOOP_COMMON_HOME,HADOOP_HDFS_HOME,HADOOP_CONF_DIR,CLAS
    SPATH_PREPEND_DISTCACHE,HADOOP_YARN_HOME,HADOOP_MAPRED_HOME</value>
    </property>
    </configuration>
    
  • 分发配置文件

    启动YARN

  • start-yarn.sh

  • 查看服务状态
    • yarn rmadmin -getServiceState rm1

      最终集群规划

      | hadoop102 | hadoop103 | hadoop104 | | —- | —- | —- | | NameNode | NameNode | NameNode | | JournalNode | JournalNode | JournalNode | | DataNode | DataNode | DataNode | | Zookeeper | Zookeeper | Zookeeper | | ZKFC | ZKFC | ZKFC | | ResourceManager | ResourceManager | ResourceManager | | NodeManager | NodeManager | NodeManager |