当前位置: 移动技术网 > IT编程>开发语言>Java > Hadoop高可用集群

Hadoop高可用集群

2018年11月13日  | 移动技术网IT编程  | 我要评论

1.简介

 

 

若hdfs集群中只配置了一个namenode,那么当该namenode所在的节点宕机,则整个hdfs就不能进行文件的上传和下载。

若yarn集群中只配置了一个resourcemanager,那么当该resourcemanager所在的节点宕机,则整个yarn就不能进行任务的计算。

*hadoop依赖zookeeper进行各个模块的ha配置,其中状态为active的节点对外提供服务,而状态为standby的节点则只负责数据的同步,在必要时提供快速故障转移。

 

hadoop各个模块剖析:

hadoop集群管理:

 

 

2.hdfs ha集群

 

 

2.1 模型


当有两个namenode时,提供哪个namenode地址给客户端?

 

 

1.hadoop提供了nameservice进程,其是namenode的代理,维护namenode列表并存储namenode的状态,客户端直接访问的是nameservice,nameservice会将请求转发给当前状态为active的namenode。

2.当启动hdfs时,datanode将同时向两个namenode进行注册。

 

 

怎样发现namenode无法提供服务以及如何进行namenode间状态的切换?

 



1.hadoop提供了failovercontrolleractive和failovercontrollerstandby两个进程用于namenode的生命监控。

2.failovercontrolleractive和failovercontrollerstandby会分别监控对应状态的namenode,若namenode无异常则定期向zookeeper集群发送心跳,若在一定时间内zookeeper集群没收到failovercontrolleractive发送的心跳,则认为此时状态为active的namenode已经无法对外提供服务,因此将状态为standby的namenode切换为active状态。

 

namenode之间的数据如何进行同步和共享?

1.hadoop提供了journalnode用于存放namenode中的编辑日志。

2.当激活的namenode执行任何名称空间上的修改时,它将修改的记录保存到journalnode集群中,备用的namenode能够实时监控journalnode集群中日志的变化,当监控到日志发生改变时会将其同步到本地。

 

*当状态为active的namenode无法对外提供服务时,zookeeper将会自动的将处于standby状态的namenode切换成active。

 

 

2.2 hdfs ha高可用集群搭建

 

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的web监控页面地址 -->  
  <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中的备份数(小于等于namenode) -->  
  <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>

 

*指定namenode的rpc通讯地址是为了接收failovercontrolleractive和failovercontrollerstandby以及datanode发送的心跳。

 

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

<configuration> 
  <!-- hadoop工作目录,用于存放hadoop运行时namenode、datanode产生的数据 -->  
  <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。

 

4.启动hdfs ha高可用集群

1.分别启动journalnode

 

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

 

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

 

4.启动第二个namenode

 

5.启动zookeeper集群

 

6.格式化zookeeper

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

 

7.重启hdfs集群

 

当hdfs ha集群启动完毕后,可以分别访问namenode管理页面查看当前namenode的状态,、。

 

 

*可以查看到主机名为hadoop1的namnode其状态为standby,而主机名为hadoop2的namenode其状态为active。

 

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

 

此时访问namenode管理页面,可见主机名为hadoop1的namenode其状态从原本的standby切换成active。

 

 

2.3 java操作hdfs ha集群

 

*由于在hdfs ha集群中存在两个namenode,且服务端暴露的是nameservice,因此在通过java连接hdfs ha集群时需要使用configuration实例进行相关的配置。

 

/**
 * @auther: zhuanghaotang
 * @date: 2018/11/6 11:49
 * @description:
 */
public class hdfsutils {

    /**
     * hdfs namennode url
     */
    private static final string namenode_url = "hdfs://mycluster:8020";

    /**
     * 配置项
     */
    private static configuration conf = null;

    static {
        conf = new configuration();
        //指定默认连接的namenode,使用nameservice的名称
        conf.set("fs.defaultfs", "hdfs://mycluster");
        //指定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", "hadoop1:8020");
        conf.set("dfs.namenode.rpc-address.mycluster.nn2", "hadoop2:8020");
        //配置namenode失败自动切换的方式
        conf.set("dfs.client.failover.proxy.provider.mycluster", "org.apache.hadoop.hdfs.server.namenode.ha.configuredfailoverproxyprovider");
    }

    /**
     * 创建目录
     */
    public static void mkdir(string dir) throws exception {
        if (stringutils.isblank(dir)) {
            throw new exception("parameter is null");
        }
        dir = namenode_url + dir;
        filesystem fs = filesystem.get(uri.create(namenode_url), conf);
        if (!fs.exists(new path(dir))) {
            fs.mkdirs(new path(dir));
        }
        fs.close();
    }

    /**
     * 删除目录或文件
     */
    public static void delete(string dir) throws exception {
        if (stringutils.isblank(dir)) {
            throw new exception("parameter is null");
        }
        dir = namenode_url + dir;
        filesystem fs = filesystem.get(uri.create(namenode_url), conf);
        fs.delete(new path(dir), true);
        fs.close();
    }


    /**
     * 遍历指定路径下的目录和文件
     */
    public static list<string> listall(string dir) throws exception {
        list<string> names = new arraylist<>();
        if (stringutils.isblank(dir)) {
            throw new exception("parameter is null");
        }
        dir = namenode_url + dir;
        filesystem fs = filesystem.get(uri.create(dir), conf);
        filestatus[] files = fs.liststatus(new path(dir));
        for (int i = 0, len = files.length; i < len; i++) {
            if (files[i].isfile()) { //文件
                names.add(files[i].getpath().tostring());
            } else if (files[i].isdirectory()) { //目录
                names.add(files[i].getpath().tostring());
            } else if (files[i].issymlink()) { //软或硬链接
                names.add(files[i].getpath().tostring());
            }
        }
        fs.close();
        return names;
    }


    /**
     * 上传当前服务器的文件到hdfs中
     */
    public static void uploadlocalfiletohdfs(string localfile, string hdfsfile) throws exception {
        if (stringutils.isblank(localfile) || stringutils.isblank(hdfsfile)) {
            throw new exception("parameter is null");
        }
        hdfsfile = namenode_url + hdfsfile;
        filesystem fs = filesystem.get(uri.create(namenode_url), conf);
        path src = new path(localfile);
        path dst = new path(hdfsfile);
        fs.copyfromlocalfile(src, dst);
        fs.close();
    }


    /**
     * 通过流上传文件
     */
    public static void uploadfile(string hdfspath, inputstream inputstream) throws exception {
        if (stringutils.isblank(hdfspath)) {
            throw new exception("parameter is null");
        }
        hdfspath = namenode_url + hdfspath;
        filesystem fs = filesystem.get(uri.create(namenode_url), conf);
        fsdataoutputstream os = fs.create(new path(hdfspath));
        bufferedinputstream bufferedinputstream = new bufferedinputstream(inputstream);
        byte[] data = new byte[1024];
        while (bufferedinputstream.read(data) != -1) {
            os.write(data);
        }
        os.close();
        fs.close();
    }


    /**
     * 从hdfs中下载文件
     */
    public static byte[] readfile(string hdfsfile) throws exception {
        if (stringutils.isblank(hdfsfile)) {
            throw new exception("parameter is null");
        }
        hdfsfile = namenode_url + hdfsfile;
        filesystem fs = filesystem.get(uri.create(namenode_url), conf);
        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();
            fs.close();
            return data;
        } else {
            throw new exception("file not found in hdfs");
        }
    }


}

 

 

 

3.yarn ha集群

 

 

3.1 模型

 

 

 

 

*启动两个resourcemanager后分别向zookeeper注册,通过zookeeper管理他们的状态,一旦状态为active的resourcemanager无法正常提供服务,zookeeper将会立即将状态为standby的resourcemanager切换为active。

 

 

3.2 yarn ha高可用集群搭建 

 

1.配置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使用的存储方式(实现类)

1.resourcemanager运行时的数据保存在zk中:org.apache.hadoop.yarn.server.resourcemanager.recovery.zkrmstatestore

2.resourcemanager运行时的数据保存在hdfs中:org.apache.hadoop.yarn.server.resourcemanager.recovery.filesystemrmstatestore

3.resourcemanager运行时的数据保存在本地:org.apache.hadoop.yarn.server.resourcemanager.recovery.leveldbrmstatestore

*使用不同的存储方式将需要额外的配置项,可参考官网,

 

 

2.启动yarn ha高可用集群

 

1.在resourcemanager所在节点中启动yarn集群

 

2.手动启动另一个resourcemanager

 

 

*当启动yarn ha集群后,可以分别访问resourcemanager管理页面,、。

访问状态为standby的resourcemanager时,会将请求重定向到状态为active的resourcemanager的管理页面。

 

3.模拟resourcemanager宕机,手动杀死进程

 

*zookeeper在一定时间内无法接收到状态为active的resourcemanager发送的心跳时,将会立即将状态为standby的resourcemanager切换为active。

 

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网