• Hadoop高可用集群


    Hadoop高可用集群

    由于一个HDFS集群由一个NameNode节点和多个DataNode节点组成,一旦NameNode节点宕机,那么HDFS将不能进行文件的上传与下载。 

    由于一个Yarn集群由一个ResourceManager节点和多个NodeManager节点组成,一旦ResourceManager节点宕机,那么YARN集群将不能进行资源的调度。

    Hadoop各个模块剖析:https://www.cnblogs.com/funyoung/p/9889719.html

    Hadoop集群管理:https://www.cnblogs.com/funyoung/p/9920828.html

     

    1.搭建HDFS的高可用集群

    由于一个HDFS集群由一个NameNode节点和多个DataNode节点组成,一旦NameNode节点宕机,那么HDFS将不能进行文件的上传与下载。

    Hadoop依赖Zookeeper实现HDFS集群的高可用,由状态为Active的NameNode节点对外提供服务,而状态为StandBy的NameNode节点则负责数据的同步,一旦状态为Active的NameNode节点宕机,则状态为StandBy的NameNode节点将会切换为Active状态对外提供服务。

     

     

     

     

     

     

     

     

     

     

     

     

     

    Hadoop提供了NameService进程,其是NameNode的代理,客户端直接访问的是NameService,NameService会将请求转发给状态为Active的NameNode。

    当启动HDFS时,DataNode节点会同时向两个NameNode节点进行注册。

     

    关于NameService如何进行状态转移

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    Hadoop提供了FailoverControllerActive和FailoverControllerStandBy两个进程用于监控NameNode的生命周期。

    FailoverControllerActive和FailoverControllerStandBy会分别监控对应状态的NameNode,若NameNode无异常则定期向Zookeeper集群发送心跳,若在一定时间内Zookeeper集群没收到FailoverControllerActive发送的心跳,则认为此时状态为Active的NameNode已经无法对外提供服务,因此将状态为StandBy的NameNode切换为Active状态。

     

    关于NameNode之间的数据如何进行同步

    Hadoop提供了JournalNode用于存放NameNode中的编辑日志,当状态为Active的NameNode节点执行任何名称空间上的修改时,它都会将修改保存到JournalNode集群中,而状态为StandBy的NameNode节点会实时的从JournalNode集群中进行同步。

     

    1.1 修改配置

     

    1.安装并配置Zookeeper集群

     

    2.配置HDFS(hdfs-site.xml)

    <configuration> 
      <!-- 指定NameService的名称 -->  
      <property> 
        <name>dfs.nameservices</name>  
        <value>mycluster</value> 
      </property>  
      <!-- 指定NameService下两个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>192.168.1.80:8020</value> 
      </property>  
      <property> 
        <name>dfs.namenode.rpc-address.mycluster.nn2</name>  
        <value>192.168.1.81:8020</value> 
      </property>  
      <!-- 分别指定NameNode的可视化管理界面的地址 -->  
      <property> 
        <name>dfs.namenode.http-address.mycluster.nn1</name>  
        <value>192.168.1.80:50070</value> 
      </property>  
      <property> 
        <name>dfs.namenode.http-address.mycluster.nn2</name>  
        <value>192.168.1.81:50070</value> 
      </property>  
      <!-- 指定NameNode编辑日志存储在JournalNode集群中的目录-->  
      <property> 
        <name>dfs.namenode.shared.edits.dir</name>  
        <value>qjournal://192.168.1.80:8485;192.168.1.81:8485;192.168.1.82:8485/mycluster</value> 
      </property>
      <!-- 指定JournalNode集群存放日志的目录-->  
      <property> 
        <name>dfs.journalnode.edits.dir</name>  
        <value>/usr/hadoop/hadoop-2.9.0/journalnode</value> 
      </property>  
      <!-- 配置NameNode失败自动切换的方式-->  
      <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>  
      <!-- 开启失败故障自动转移-->  
      <property> 
        <name>dfs.ha.automatic-failover.enabled</name>  
        <value>true</value> 
      </property>  
      <!-- 配置Zookeeper地址-->  
      <property> 
        <name>ha.zookeeper.quorum</name>  
        <value>192.168.1.80:2181,192.168.1.81:2181,192.168.1.82:2181</value> 
      </property>  
      <!-- 文件在HDFS中的备份数(小于等于DataNode) -->  
      <property> 
        <name>dfs.replication</name>  
        <value>3</value> 
      </property>  
      <!-- 关闭HDFS的访问权限 -->  
      <property> 
        <name>dfs.permissions.enabled</name>  
        <value>false</value> 
      </property>  
      <!-- 指定一个配置文件,使NameNode过滤配置文件中指定的host -->  
      <property> 
        <name>dfs.hosts.exclude</name>  
        <value>/usr/hadoop/hadoop-2.9.0/etc/hadoop/hdfs.exclude</value> 
      </property> 
    </configuration>

    3.配置Hadoop公共属性(core-site.xml)

    <configuration> 
      <!-- Hadoop工作目录,用于存放Hadoop运行时产生的临时数据 -->
      <property> 
        <name>hadoop.tmp.dir</name>  
        <value>/usr/hadoop/hadoop-2.9.0/data</value> 
      </property>  
      <!-- 默认的NameNode,使用NameService的名称 -->  
      <property> 
        <name>fs.defaultFS</name>  
        <value>hdfs://mycluster</value> 
      </property>  
      <!-- 开启Hadoop的回收站机制,当删除HDFS中的文件时,文件将会被移动到回收站(/usr/<username>/.Trash),在指定的时间过后再对其进行删除,此机制可以防止文件被误删除 -->  
      <property> 
        <name>fs.trash.interval</name>  
        <!-- 单位是分钟 -->  
        <value>1440</value> 
      </property> 
    </configuration> 

    在HDFS HA集群中,StandBy的NameNode会对namespace进行checkpoint操作,因此就不需要在HA集群中运行SecondaryNameNode、CheckpintNode、BackupNode

     

    1.2 启动HDFS高可用集群

    1.分别启动JournalNode

     

     

     

     

     

     

     

     

     

    2.格式化第一个NameNode并启动

     

     

     

     

     

     

    3.第二个NameNode同步第一个NameNode的信息

     

     

    4.启动第二个NameNode

     

     

     

     

    5.启动Zookeeper集群

     

     

     

     

     

     

     

     

     

     

     

     

     

    6.格式化Zookeeper

     

    当格式化ZK后,ZK中将会多了hadoop-ha节点。

     

    7.重启HDFS集群

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    当HDFS高可用集群启动后,可以分别访问NameNode的可视化管理界面查看NameNode的状态状态,http://192.168.1.80:50070http://192.168.1.81:50070

     

    img

    img

     

    8.模拟NameNode宕机,手动杀死进程。

     

     

     

     

    此时访问NameNode可视化管理界面,可以查看到主机名为hadoop1的NameNode节点其状态从StandBy切换成Active。

     

    img

     

    1.3 JAVA操作HDFS高可用集群

    由于在HDFS高可用集群中存在两个NameNode,且服务端暴露的是NameService,因此在通过JAVA连接HDFS高可用集群时需要使用Configuration实例进行相关的配置。

    /**
     * @Auther: ZHUANGHAOTANG
     * @Date: 2018/11/6 11:49
     * @Description:
     */
    public class HDFSUtils {
    ​
        private static Logger logger = LoggerFactory.getLogger(HDFSUtils.class);
    ​
        /**
         * NameNode Service
         */
        private static final String NAMESERVER_URL = "hdfs://mycluster:8020";
    ​
        /**
         * NameNode服务列表
         */
        private static final String[] NAMENODE_URLS = {"192.168.1.80:8020", "192.168.1.81:8020"};
    ​
        /**
         * HDFS文件系统连接对象
         */
        private static FileSystem fs = null;
    ​
        static {
            Configuration conf = new Configuration();
            //指定默认连接的NameNode,使用NameService的地址
            conf.set("fs.defaultFS", NAMESERVER_URL);
            //指定NameService的名称
            conf.set("dfs.nameservices", "mycluster");
            //指定NameService下的NameNode列表
            conf.set("dfs.ha.namenodes.mycluster", "nn1,nn2");
            //分别指定NameNode的RPC通讯地址
            conf.set("dfs.namenode.rpc-address.mycluster.nn1", NAMENODE_URLS[0]);
            conf.set("dfs.namenode.rpc-address.mycluster.nn2", NAMENODE_URLS[1]);
            //配置NameNode失败自动切换的方式
            conf.set("dfs.client.failover.proxy.provider.mycluster", "org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider");
            try {
                fs = FileSystem.get(URI.create(NAMESERVER_URL), conf);
            } catch (IOException e) {
                logger.info("初始化HDFS连接失败:{}", e);
            }
        }
    ​
        /**
         * 创建目录
         */
        public static void mkdir(String dir) throws Exception {
            dir = NAMESERVER_URL + dir;
            if (!fs.exists(new Path(dir))) {
                fs.mkdirs(new Path(dir));
            }
        }
    ​
        /**
         * 删除目录或文件
         */
        public static void delete(String dir) throws Exception {
            dir = NAMESERVER_URL + dir;
            fs.delete(new Path(dir), true);
        }
    ​
        /**
         * 遍历指定路径下的目录和文件
         */
        public static List<String> listAll(String dir) throws Exception {
            List<String> names = new ArrayList<>();
            dir = NAMESERVER_URL + dir;
            FileStatus[] files = fs.listStatus(new Path(dir));
            for (FileStatus file : files) {
                if (file.isFile()) { //文件
                    names.add(file.getPath().toString());
                } else if (file.isDirectory()) { //目录
                    names.add(file.getPath().toString());
                } else if (file.isSymlink()) { //软或硬链接
                    names.add(file.getPath().toString());
                }
            }
            return names;
        }
    ​
        /**
         * 上传当前服务器的文件到HDFS中
         */
        public static void uploadLocalFileToHDFS(String localFile, String hdfsFile) throws Exception {
            hdfsFile = NAMESERVER_URL + hdfsFile;
            Path src = new Path(localFile);
            Path dst = new Path(hdfsFile);
            fs.copyFromLocalFile(src, dst);
        }
    ​
        /**
         * 通过流上传文件
         */
        public static void uploadFile(String hdfsPath, InputStream inputStream) throws Exception {
            hdfsPath = NAMESERVER_URL + hdfsPath;
            FSDataOutputStream os = fs.create(new Path(hdfsPath));
            BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
            byte[] data = new byte[1024];
            int len;
            while ((len = bufferedInputStream.read(data)) != -1) {
                if (len == data.length) {
                    os.write(data);
                } else { //最后一次读取
                    byte[] lastData = new byte[len];
                    System.arraycopy(data, 0, lastData, 0, len);
                    os.write(lastData);
                }
            }
            inputStream.close();
            bufferedInputStream.close();
            os.close();
        }
    ​
        /**
         * 从HDFS中下载文件
         */
        public static byte[] readFile(String hdfsFile) throws Exception {
            hdfsFile = NAMESERVER_URL + hdfsFile;
            Path path = new Path(hdfsFile);
            if (fs.exists(path)) {
                FSDataInputStream is = fs.open(path);
                FileStatus stat = fs.getFileStatus(path);
                byte[] data = new byte[(int) stat.getLen()];
                is.readFully(0, data);
                is.close();
                return data;
            } else {
                throw new Exception("File Not Found In HDFS");
            }
        }
    ​
    }

    2.搭建YARN高可用集群

    由于一个Yarn集群由一个ResourceManager节点和多个NodeManager节点组成,一旦ResourceManager节点宕机,那么YARN集群将不能进行资源的调度。

     

     

     

     

     

     

     

     

     

    Hadoop依赖Zookeeper实现YARN集群的高可用,首先启动两个ResourceManager,且由状态为Active的ResourceManager节点对外提供服务,而状态为StandBy的ResourceManager节点则负责数据的同步,一旦状态为Active的ResourceManager节点宕机,则状态为StandBy的ResourceManager节点将会切换为Active状态,对外提供服务。

     

    2.1 修改配置

     

    1.安装并配置Zookeeper集群

     

    2.配置YARN(yarn-site.xml)

    <configuration> 
      <!-- 配置Reduce取数据的方式是shuffle(随机) -->  
      <property> 
        <name>yarn.nodemanager.aux-services</name>  
        <value>mapreduce_shuffle</value> 
      </property>  
      <!-- 开启日志 -->  
      <property> 
        <name>yarn.log-aggregation-enable</name>  
        <value>true</value> 
      </property>  
      <!-- 设置日志的删除时间 -1:禁用,单位为秒 -->  
      <property> 
        <name>yarn.log-aggregation。retain-seconds</name>  
        <value>864000</value> 
      </property>  
      <!-- 设置yarn的内存大小,单位是MB -->  
      <property> 
        <name>yarn.nodemanager.resource.memory-mb</name>  
        <value>8192</value> 
      </property>  
      <!-- 设置yarn的CPU核数 -->  
      <property> 
        <name>yarn.nodemanager.resource.cpu-vcores</name>  
        <value>8</value> 
      </property>
      <!-- YARN HA配置 -->  
      <!-- 开启yarn ha -->  
      <property> 
        <name>yarn.resourcemanager.ha.enabled</name>  
        <value>true</value> 
      </property>  
      <!-- 指定yarn ha的名称 -->  
      <property> 
        <name>yarn.resourcemanager.cluster-id</name>  
        <value>cluster1</value> 
      </property>  
      <!-- 分别指定两个ResourceManager的名称 -->  
      <property> 
        <name>yarn.resourcemanager.ha.rm-ids</name>  
        <value>rm1,rm2</value> 
      </property>  
      <!-- 分别指定两个ResourceManager的地址 -->  
      <property> 
        <name>yarn.resourcemanager.hostname.rm1</name>  
        <value>192.168.1.80</value> 
      </property>  
      <property> 
        <name>yarn.resourcemanager.hostname.rm2</name>  
        <value>192.168.1.81</value> 
      </property>  
      <!-- 分别指定两个ResourceManager的Web访问地址 -->  
      <property> 
        <name>yarn.resourcemanager.webapp.address.rm1</name>  
        <value>192.168.1.80:8088</value> 
      </property>  
      <property> 
        <name>yarn.resourcemanager.webapp.address.rm2</name>  
        <value>192.168.1.81:8088</value> 
      </property>  
      <!-- 配置使用的Zookeeper集群 -->  
      <property> 
        <name>yarn.resourcemanager.zk-address</name>  
        <value>192.168.1.80:2181,192.168.1.81:2181,192.168.1.82:2181</value> 
      </property>  
      <!-- ResourceManager Restart配置 -->  
      <!-- 启用ResourceManager的restart功能,当ResourceManager重启时将会保存当前运行的信息到指定的位置,当重启成功后自动进行读取 -->  
      <property> 
        <name>yarn.resourcemanager.recovery.enabled</name>  
        <value>true</value> 
      </property>  
      <!-- ResourceManager Restart使用的存储方式(实现类) -->  
      <property> 
        <name>yarn.resourcemanager.store.class</name>  
        <value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore</value> 
      </property>  
      <!-- ResourceManager重启时数据保存在Zookeeper中的目录 -->  
      <property> 
        <name>yarn.resourcemanager.zk-state-store.parent-path</name>  
        <value>/rmstore</value> 
      </property>  
      <!-- NodeManager Restart配置 -->  
      <!-- 启用NodeManager的restart功能,当NodeManager重启时将会保存当前运行时的信息到指定的位置,重启成功后自动进行读取 -->  
      <property> 
        <name>yarn.nodemanager.recovery.enabled</name>  
        <value>true</value> 
      </property>  
      <!-- NodeManager重启时数据保存在本地的目录 -->  
      <property> 
        <name>yarn.nodemanager.recovery.dir</name>  
        <value>/usr/hadoop/hadoop-2.9.0/data/rsnodemanager</value> 
      </property>  
      <!-- 配置NodeManager的RPC通讯端口 -->  
      <property> 
        <name>yarn.nodemanager.address</name>  
        <value>0.0.0.0:45454</value> 
      </property> 
    </configuration>

    ResourceManager Restart使用的存储方式(实现类)

    #保存在ZK当中
    org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore
    ​
    #保存在HDFS中
    org.apache.hadoop.yarn.server.resourcemanager.recovery.FileSystemRMStateStore
    ​
    #保存在本地
    org.apache.hadoop.yarn.server.resourcemanager.recovery.LeveldbRMStateStore 

    使用不同的存储方式将需要额外的配置项,可参考官网,http://hadoop.apache.org/docs/current/hadoop-yarn/hadoop-yarn-site/ResourceManagerRestart.html

     

    2.2 启动YARN高可用集群

    1.在ResourceManager节点中启动YARN集群

     

     

     

     

     

     

     

     

     

    2.手动启动另一个ResourceManager

    img

     

    3.当启动YARN高可用集群后,可以分别访问ResourceManager的可视化管理界面,http://192.168.1.80:8088http://192.168.1.81:8088

    当访问状态为StandBy的ResourceManager时,将会将请求重定向到状态为Active的ResourceManager的可视化管理界面。

     

    4.模拟ResourceManager宕机,手动杀死进程。

     

     

     

     

     

    Zookeeper在一定时间内没有接收到状态为Active的ResourceManager发送的心跳时,将会立即将状态为StandBy的ResourceManager切换为Active。

  • 相关阅读:
    display: flex
    TTStand --Variant的应用
    跨域
    HTTP 响应状态代码
    SQL Server 2017 Developer and Express
    WPF 中 通过点击ListBox中的元素自动选中一整项
    C#计算屏幕的物理宽和高
    C#常用设计模式
    EntityFrameworkCore之工作单元的封装
    内存包装类 Memory 和 Span 相关类型
  • 原文地址:https://www.cnblogs.com/funyoung/p/9947105.html
Copyright © 2020-2023  润新知