HDFS高可用机制实现

一、怎么理解HDFS高可用
HDFS高可用要解决的问题点:NameNode存在单点失效的问题
当NameNode失效后,所有的客户端包含MapReduce作业都将无法读写文件,因为NameNode是唯一存储元数据与文件到数据块映射的地方,为了避免这种情况的产生,则需要考虑搭建HDFS高可用集群来实现NameNode的高可用性。
HDFS高可用的机制:配置一对活动-备用NameNode,当活动NameNode失效后,备用NameNode可以接管它的任务并开始为客户端提供服务,这个过程保证不会有明显的中断
 
二、HDFS高可用实现原理
要实现上面所说的HDFS高可用机制,在架构上必须要做如下修改调整
通过双NameNode来消除单点故障带来的隐患,需要做如下工作:
元数据的管理方式需要改变:
    双NameNode内存中必须要各自保存一份元数据,edits日志则只能有一份
    只有Active状态的NameNode可以进行写操作
    两个NameNode都可以读取edits,这个共享的edits存放在一个共享存储中管理,通常使用Journal Node实现
 
备用NameNode接管工作之后,它会读取共享日志,实现与活动NameNode的状态同步,并继续读取由活动NameNode写入的新条目
 
如何进行切换:需要一个状态管理功能模块,实现一个ZKFailover,它常驻在每一个NameNode节点,利用ZK进行关态标识。当需要进行切换时,由ZK负责进行切换。切换时需要防止分裂混乱现象发生
 
DataNode 同时向两个NameNode发送数据处理报告,数据块的映射信息存储在NameNode的内存中,而并非磁盘上
 
客户端需要使用特定的机制来处理NameNode的失效问题,这个机制对于用户来说是无感知的
 
SecondaryName NameNode的角色被备用NameNode所包含,备用NameNode为活动NameNode命名空间设置周期性检查点
 
高可用HDFS架构图
HDFS高可用机制实现
  1. NameNode(NN)
        NameNode节点主要有两种状态:Active、Standby
  1. FailoverController(ZKFC)
        这个节点用来监控和控制NN的状切换,当集群中的活动NN失效后会切换Standby NN的状态为Active
  1. JournalNode(JN)
        这个节点用来共享edits日志文件,因为edits文件一旦丢失则会导致元数据丢失,数据也就会丢失,因而这里一般也是一个集群
  1. DataNode(DN)
        这个节点定时与NN进行通信,同时DN之间还会进行通信以进行数据块复制
  1. ZooKeeper(ZK)
        
        Active NN会把edits文件写到JN集群中的每一台机器上,active和standby的NN都可以读取edits文件,共享的edits文件存放在一个共享存储中管理,fsimage文件会在格式化时产生并会推送给其它NN节点
        FailoverController Active和FailoverController Standby分别对Active NN和Standby NN进行健康检查,把心跳数据传送给到ZooKeeper,如是Active NN掉线则ZooKeeper会进行选举,选举出来后由FailoverController进行切换
        DN中的信息会同时发送给到Active NN 和 Standby NN
 
三、如何搭建HDFS高可用
 
  1. 配置Zookeeper
        Zookeeper下载地址: https://mirror.bit.edu.cn/apache/zookeeper/
        上传文件至node1
        解压缩Zookeeper
        tar -zxvf zookeeper-3.4.14.tar.gz
        在zookeeper解压的文件夹下的conf文件夹下创建zoo.cfg文件
            tickTime=2000
            clientPort=2181
            initLimit=5
            syncLimit=2
            dataDir=/opt/zookeeper/data
            server.1=node1:2888:3888
            server.2=node2:2888:3888
            server.3=node3:2888:3888
        dataDir:表示存放zookeeper数据文件目录
        server.1、server.2、server.3分别对应的是1,2,3个节点,其中2888,3888表示接收和发送数据的端口
        
        在dataDir所在的目录需要创建myid文件
        在node1节点的创建文件夹/opt/zookeeper/data,并在这个目录下新建一个myid文件,其中的内容录入1,这样就和server.1对应起来了
        同上node2和node3中也建立上面的文件夹目录并在其中分别新增myid并输入内容 2和3
        
         把在node1上已经安装好的zookeeper复制到node2和node3
            使用scp -r 命令
            
        启动zookeeper
        在zookeeper中bin中执行命令 sh zkServer.sh start
        启动后可以使用命令jps查看进程  有一个进度 QuorumPeerMain
 
        2. 对于Hadoop的配置
        这里涉及到四个配置文件 hadoop-env.sh、core-site.xml、hdfs-site.xml、workers
 
        hadoop-env.sh
            export JAVA_HOME=/usr/java/jdk1.8.0_251-amd64
            export HDFS_NAMENODE_USER=root
            export HDFS_DATANODE_USER=root
            export HDFS_ZKFC_USER=root
            export HDFS_JOURNALNODE_USER=root
        
        core-site.xml
            <configuration>
                <property>
                    <name>fs.defaultFS</name>
                    <value>hdfs://mycluster</value>
                </property>
                <property>
                    <name>hadoop.tmp.dir</name>
                    <value>/opt/hadoopdata</value>
                </property>
                <property>
                    <name>hadoop.http.staticuser.user</name>
                    <value>root</value>
                </property>
                <property>
                    <name>ha.ZooKeeper.quorum</name>
                    <value>node1:2181,node2:2181,node3:2181</value>
                </property>
            </configuration>
            hadoop.http.staticuser.user:定义了网页访问的用户名
            ha.ZooKeeper.quorum:定义了ZooKeeper集群
            
        hdfs-site.xml
            <configuration>
                <property>
                   <name>dfs.nameservices</name>
                   <value>mycluster</value>
                </property>
               <property>
                  <name>dfs.ha.namenodes.mycluster</name>
                 <value>nn1,nn2</value>
              </property>
              <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>
              <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>
            <property>
                <name>dfs.namenode.shared.edits.dir</name>
                <value>qjournal://node1:8485;node2:8485;node3:8485/xie</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>/root/.ssh/id_rsa</value>
             </property>
             <property>
                <name>dfs.journalnode.edits.dir</name>
                <value>/opt/journalnode/data</value>
             </property>
             <property>
                 <name>dfs.ha.automatic-failover.enabled.ns</name>
                 <value>true</value>
              </property>
        </configuration>
 
        dfs.nameservices:配置集群ID
        dfs.ha.namenodes.mycluster:配置Name Node的ID号
        dfs.namenode.rpc-address.mycluster.nn1:定义NameNode的主机及rpc协议端口
        dfs.namenode.http-address.mycluster.nn1:定义NameNode的主机及http协议端口
        dfs.namenode.shared.edits.dir:定义共享deits的URL
        dfs.client.failover.proxy.provider.mycluster:定义返回Active NameNode的类
        dfs.ha.fencing.methods:定义NameNode切换时的隔离方法
        dfs.ha.fencing.ssh.private-key-files:定义隔离方法的**
        dfs.journalnode.edits.dir:保存edits文件的目录
        dfs.ha.automatic-failover.enabled:定义开启自动切换
 
        workers文件:
            这个文件主要用来配置DataNode的节点,配置内容如下:
            node1
            node2
            node3
        、
        3. 向节点上的机器复制配置文件
        把上面配置好的文件复制到其它节点上
            使用如下命令:
                scp hadoop-env.sh [email protected]:/root/software/hadoop-3.1.3/etc/hadoop/
            使用类似上面的命令把hadoop-env.sh、core-site.xml、hdfs-site.xml、workers 这四个配置文件复制到node2和node3
 
        4. 启动JN节点
           hdfs --daemon start journalnode
        
        注意:在这个过程中还修改了一个文件:这个文件位于hadoop的bin目录下的hdfs
        修改内容如下:
         HADOOP_SHELL_EXECNAME="root"
       并把这个修改文件复制到其它节点
        重启hdfs
 
        5. 执行格式化操作
        在node1上执行格式化操作
        hdfs namenode -format
        注意:对于/ect/hosts文件中把127.0.0.1这个信息屏蔽掉
 
        6. 把元数据从node1复制到node2
        因为我们需要设置两个NameNode所以需要进行复制
 
        7. 格式化ZKFC
        在NameNode节点上启动的ZKFC进程内部运行着3个服务对象
        HealthMonitor:定期检查NameNode是否不可用或是否进入一个不健康的状态,并通知到ZooKeeper Failover Controller
        ActiveStandbyElector:控制和监控NameNode在Zookeeper上的状态
        ZKFailoverController:协调前两个对象并处理它们通知的 event变化事件,完成自动切换过程
        格式化ZKFC命令如下:
            hdfs zkfc -formatZK
 
        注意:zk在格式化的过程中可能会遇到一些网络等相关的问题一般的排查方法如下:
            第一,zoo.cfg文件配置出错:dataLogDir指定的目录未被创建;
            第二,myid文件中的整数格式不对,或者与zoo.cfg中的server整数不对应
            第三,防火墙未关闭;
            第四,2181端口被占用;
            第五,zoo.cfg文件中主机名出错;
            第六,hosts文件中,本机的主机名有两个对应,只需保留主机名和ip地址的映射
            
        8. 启动集群
        start-dfs.sh
        
        在浏览器中进行访问:
         http://192.168.2.2:9870/
        HDFS高可用机制实现
        HDFS高可用机制实现
        以上则完成了整理个高可用HDFS集群的配置
        现在我们可以看到node2为active的状态,node1为standby的状态
        我们查看node2现在的进程
        使用:jps命令
        HDFS高可用机制实现
        接下来把node1的进程 ID为4086的NameNode进行手动杀死
        kill -9 4086
        这个时候我们可以看到node1自动切换为active状态
        HDFS高可用机制实现