Hadoop高可用

大数据技术之Hadoop

HDFS文件系统)

HDFS概念

1.1 概念

HDFS,它是一个文件系统,全称:Hadoop Distributed File System,用于存储文件通过目录树来定位文件;其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色。

1.2 组成

1HDFS集群包括,NameNodeDataNode以及Secondary Namenode

2NameNode负责管理整个文件系统的元数据,以及每一个路径(文件)所对应的数据块信息。

3DataNode 负责管理用户的文件数据块,每一个数据块都可以在多个datanode上存储多个副本。

4Secondary NameNode用来监控HDFS状态的辅助后台程序,每隔一段时间获取HDFS元数据的快照。

1.3 HDFS 文件块大小

HDFS中的文件在物理上是分块存储(block),块的大小可以通过配置参数( dfs.blocksize)来规定,默认大小在hadoop2.x版本中是128M,老版本中是64M

HDFS的块比磁盘的块大,其目的是为了最小化寻址开销。如果设置得足够大,从磁盘传输数据的时间会明显大于定位这个开始位置所需的时间。因而传输一个由多个块组成的文件的时间取决于磁盘传输速率

如果寻址时间约为10ms,而传输速率为100MB/s,为了使寻址时间仅占传输时间的1%,我们要将块大小设置约为100MB。默认块大小128MB

的大小:10ms*100*100M/s = 100M

 

HFDS命令行操作

1)基本语法

bin/hadoop fs 具体命令

2)参数大全

bin/hadoop fs

[-appendToFile <localsrc> ... <dst>]

        [-cat [-ignoreCrc] <src> ...]

        [-checksum <src> ...]

        [-chgrp [-R] GROUP PATH...]

        [-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...]

        [-chown [-R] [OWNER][:[GROUP]] PATH...]

        [-copyFromLocal [-f] [-p] <localsrc> ... <dst>]

        [-copyToLocal [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]

        [-count [-q] <path> ...]

        [-cp [-f] [-p] <src> ... <dst>]

        [-createSnapshot <snapshotDir> [<snapshotName>]]

        [-deleteSnapshot <snapshotDir> <snapshotName>]

        [-df [-h] [<path> ...]]

        [-du [-s] [-h] <path> ...]

        [-expunge]

        [-get [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]

        [-getfacl [-R] <path>]

        [-getmerge [-nl] <src> <localdst>]

        [-help [cmd ...]]

        [-ls [-d] [-h] [-R] [<path> ...]]

        [-mkdir [-p] <path> ...]

        [-moveFromLocal <localsrc> ... <dst>]

        [-moveToLocal <src> <localdst>]

        [-mv <src> ... <dst>]

        [-put [-f] [-p] <localsrc> ... <dst>]

        [-renameSnapshot <snapshotDir> <oldName> <newName>]

        [-rm [-f] [-r|-R] [-skipTrash] <src> ...]

        [-rmdir [--ignore-fail-on-non-empty] <dir> ...]

        [-setfacl [-R] [{-b|-k} {-m|-x <acl_spec>} <path>]|[--set <acl_spec> <path>]]

        [-setrep [-R] [-w] <rep> <path> ...]

        [-stat [format] <path> ...]

        [-tail [-f] <file>]

        [-test -[defsz] <path>]

        [-text [-ignoreCrc] <src> ...]

        [-touchz <path> ...]

        [-usage [cmd ...]]

3常用命令实操

1-help:输出这个命令参数

bin/hdfs dfs -help rm

2-ls: 显示目录信息

hadoop fs -ls /

3-mkdir:在hdfs上创建目录

hadoop fs  -mkdir  -p  /hdfs路径

(4-moveFromLocal从本地剪切粘贴到hdfs

hadoop  fs  - moveFromLocal  本地路径  /hdfs路径

5--appendToFile  追加一个文件到已经存在的文件末尾

hadoop  fs  -appendToFile  本地路径  /hdfs路径

6-cat :显示文件内容

hadoop fs -cat /hdfs路径

7-tail -f:监控文件

hadoop  fs  -tail -f /hdfs路径

8-chmod-chownlinux文件系统中的用法一样,修改文件所属权限

hadoop  fs  -chmod  777  /hdfs路径

hadoop  fs  -chown  someuser:somegrp   /hdfs路径

9-cp :从hdfs的一个路径拷贝到hdfs的另一个路径

hadoop  fs  -cp  /hdfs路径1  / hdfs路径2

10-mv:在hdfs目录中移动/重命名 文件

hadoop  fs  -mv  /hdfs路径  / hdfs路径

11-get:等同于copyToLocal,就是从hdfs下载文件到本地

hadoop fs -get / hdfs路径 ./本地路径

12-getmerge  :合并下载多个文到linux本地,比如hdfs的目录 /aaa/下有多个文件:log.1, log.2,log.3,...(注:是合成到Linux本地)

hadoop fs -getmerge /aaa/log.* ./log.sum

合成到不同的目录:hadoop fs -getmerge /hdfs1路径 /hdfs2路径 /

13-put:等同于copyFromLocal

hadoop  fs  -put  /本地路径  /hdfs路径

14-rm:删除文件或文件夹

hadoop fs -rm -r /hdfs路径

(15-df :统计文件系统的可用空间信息

hadoop  fs  -df  -h  / hdfs路径

(16-du统计文件夹的大小信息

[itstar@bigdata111 hadoop-2.8.4]$ hadoop fs -du -s -h / hdfs路径

188.5 M  /user/itstar/wcinput

 

[itstar@bigdata111 hadoop-2.8.4]$ hadoop fs -du  -h / hdfs路径

188.5 M  / hdfs路径

97       / hdfs路径

17-count:统计一个指定目录下的文件节点数量

hadoop fs -count /aaa/

[itstar@bigdata111 hadoop-2.8.4]$ hadoop fs -count / hdfs路径

       1             2          197657784 / hdfs路径

嵌套文件层级;  包含文件的总数

(18-setrep:设置hdfs中文件的副本数量:3是副本数,可改

hadoop fs -setrep 3 / hdfs路径

 

这里设置的副本数只是记录在namenode的元数据中,是否真的会有这么多副本,还得看datanode的数量。因为目前只有3设备,最多也就3副本,只有节点数的增加10台时副本数才能达到10

HDFS客户端操作

3.1 IDEA环境准备

{$MAVEN_HOME/conf/settings}

  <!--本地仓库所在位置-->

<localRepository>F:\m2\repository</localRepository>

 

<!--使用阿里云镜像去下载Jar包,速度更快-->

  <mirrors>

    <mirror>

      <id>alimaven</id>

      <name>aliyun maven</name>

      <url>http://maven.aliyun.com/nexus/content/groups/public/</url>

      <mirrorOf>central</mirrorOf>        

    </mirror>

  </mirrors>

 

<!--本地配置JDK8版本-->

<profiles>

<profile>  

  <id>jdk-1.8</id>  

   <activation>  

     <activeByDefault>true</activeByDefault>  

     <jdk>1.8</jdk>  

   </activation>  

<properties>  

<maven.compiler.source>1.8</maven.compiler.source>  

<maven.compiler.target>1.8</maven.compiler.target>

                <version>2.5.1</version>  

<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>

</properties>

</profile>

</profiles>

    <properties>

        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

    </properties>

 

3.1.0 Maven配置

3.1.1 Maven准备

<dependencies>

<dependency>

            <groupId>org.apache.hadoop</groupId>

            <artifactId>hadoop-common</artifactId>

            <version>2.8.4</version>

        </dependency>

        <dependency>

            <groupId>org.apache.hadoop</groupId>

            <artifactId>hadoop-hdfs</artifactId>

            <version>2.8.4</version>

        </dependency>

        <dependency>

            <groupId>org.apache.hadoop</groupId>

            <artifactId>hadoop-client</artifactId>

            <version>2.8.4</version>

        </dependency>

 

        <dependency>

            <groupId>org.projectlombok</groupId>

            <artifactId>lombok</artifactId>

            <version>1.16.10</version>

        </dependency>

 

        <dependency>

            <groupId>log4j</groupId>

            <artifactId>log4j</artifactId>

            <version>1.2.17</version>

        </dependency>

        <dependency>

            <groupId>org.slf4j</groupId>

            <artifactId>slf4j-api</artifactId>

            <version>1.7.7</version>

        </dependency>

 

        <!-- https://mvnrepository.com/artifact/junit/junit -->

        <dependency>

            <groupId>junit</groupId>

            <artifactId>junit</artifactId>

            <version>4.12</version>

            <scope>test</scope>

        </dependency>

   </dependencies>

 

3.1.2 IDEA准备

1配置HADOOP_HOME环境变量

2)采用hadoop编译后的bin 、lib两个文件夹(如果不生效,重新启动IDEA

3)创建第一个java工程

public class HdfsClientDemo1 {

public static void main(String[] args) throws Exception {

// 1 获取文件系统

Configuration configuration = new Configuration();

// 配置在集群上运行

configuration.set("fs.defaultFS", "hdfs://bigdata111:9000");

FileSystem fileSystem = FileSystem.get(configuration);

 

// 直接配置访问集群的路径和访问集群的用户名称

// FileSystem fileSystem = FileSystem.get(new URI("hdfs://bigdata111:9000"),configuration, "itstar");

 

// 2 把本地文件上传到文件系统中

fileSystem.copyFromLocalFile(new Path("f:/hello.txt"), new Path("/hello1.copy.txt"));

 

// 3 关闭资源

fileSystem.close();

System.out.println("over");

}

}

4)执行程序

注:eclipse运行可能需要配置用户名称

客户端去操作hdfs时,是有一个用户身份的。默认情况下,hdfs客户端api会从jvm中获取一个参数来作为自己的用户身份:-DHADOOP_USER_NAME=itstar,itstar为用户名称。

3.2 通过API操作HDFS

3.2.1 HDFS获取文件系统

1)详细代码

    /**

     * 打印本地hadoop地址值

     * IO的方式写代码

     */

    @Test

    public void intiHDFS() throws IOException {

        //F2 可以快速的定位错误

        // alt + enter自动找错误

        //1.创建配信信息对象 ctrl + alt + v  后推前  ctrl + shitl + enter 补全

        Configuration conf = new Configuration();

 

        //2.获取文件系统

        FileSystem fs = FileSystem.get(conf);

 

        //3.打印文件系统

        System.out.println(fs.toString());

    }

3.2.2 HDFS文件上传

    /**

     * 上传代码

     * 注意:如果上传的内容大于128MB,则是2

     */

    @Test

    public void putFileToHDFS() throws Exception {

        //注:import org.apache.hadoop.conf.Configuration;

        //ctrl + alt + v 推动出对象

        //1.创建配置信息对象

        Configuration conf = new Configuration();

 

        //2.设置部分参数

        conf.set("dfs.replication","2");

 

        //3.找到HDFS的地址

        FileSystem fs = FileSystem.get(new URI("hdfs://bigdata111:9000"), conf, "root");

 

        //4.上传本地Windows文件的路径

        Path src = new Path("D:\\hadoop-2.7.2.rar");

 

        //5.要上传到HDFS的路径

        Path dst = new Path("hdfs://bigdata111:9000/Andy");

 

        //6.以拷贝的方式上传,从src -> dst

        fs.copyFromLocalFile(src,dst);

 

        //7.关闭

        fs.close();

 

        System.out.println("上传成功");

}

3.2.3 HDFS文件下载

    /**

     * hadoop fs -get /HDFS文件系统

     * @throws Exception

     */

    @Test

    public void getFileFromHDFS() throws Exception {

        //1.创建配置信息对象  Configuration:配置

        Configuration conf = new Configuration();

 

        //2.找到文件系统

        //final URI uri     HDFS地址

        //final Configuration conf:配置信息

        // String user Linux用户名

        FileSystem fs = FileSystem.get(new URI("hdfs://bigdata111:9000"), conf, "root");

 

        //3.下载文件

        //boolean delSrc:是否将原文件删除

        //Path src :要下载的路径

        //Path dst :要下载到哪

        //boolean useRawLocalFileSystem :是否校验文件

        fs.copyToLocalFile(false,new Path("hdfs://bigdata111:9000/README.txt"),

                new Path("F:\\date\\README.txt"),true);

 

        //4.关闭fs

        //alt + enter 找错误

        //ctrl + alt + o  可以快速的去除没有用的导包

        fs.close();

        System.out.println("下载成功");

    }

3.2.4 HDFS目录创建

    /**

     * hadoop fs -mkdir /xinshou

     */

    @Test

    public void mkmdirHDFS() throws Exception {

        //1.创新配置信息对象

        Configuration configuration = new Configuration();

 

        //2.链接文件系统

        //final URI uri  地址

        //final Configuration conf  配置

        //String user   Linux用户

        FileSystem fs = FileSystem.get(new URI("hdfs://bigdata111:9000"), configuration, "root");

 

        //3.创建目录

        fs.mkdirs(new Path("hdfs://bigdata111:9000/Good/Goog/Study"));

 

        //4.关闭

        fs.close();

        System.out.println("创建文件夹成功");

    }

3.2.5 HDFS文件夹删除

    /**

     * hadoop fs -rm -r /文件

     */

    @Test

    public void deleteHDFS() throws Exception {

        //1.创建配置对象

        Configuration conf = new Configuration();

 

        //2.链接文件系统

        //final URI uri, final Configuration conf, String user

        //final URI uri  地址

        //final Configuration conf  配置

        //String user   Linux用户

        FileSystem fs = FileSystem.get(new URI("hdfs://bigdata111:9000"), conf, "root");

 

        //3.删除文件

        //Path var1   : HDFS地址

        //boolean var2 : 是否递归删除

        fs.delete(new Path("hdfs://bigdata111:9000/a"),false);

 

        //4.关闭

        fs.close();

        System.out.println("删除成功啦");

    }

3.2.6 HDFS文件名更改

@Test

public void renameAtHDFS() throws Exception{

// 1 创建配置信息对象

Configuration configuration = new Configuration();

 

FileSystem fs = FileSystem.get(new URI("hdfs://bigdata111:9000"),configuration, "itstar");

 

//2 重命名文件或文件夹

fs.rename(new Path("hdfs://bigdata111:9000/user/itstar/hello.txt"), new Path("hdfs://bigdata111:9000/user/itstar/hellonihao.txt"));

fs.close();

}

3.2.7 HDFS文件详情查看

查看文件名称、权限、长度信息

    /**

     * 查看【文件】名称、权限等

     */

    @Test

    public void readListFiles() throws Exception {

        //1.创建配置对象

        Configuration conf = new Configuration();

 

        //2.链接文件系统

        FileSystem fs = FileSystem.get(new URI("hdfs://bigdata111:9000"), conf, "root");

 

        //3.迭代器

        RemoteIterator<LocatedFileStatus> listFiles = fs.listFiles(new Path("/"), true);

 

        //4.遍历迭代器

        while (listFiles.hasNext()){

            //一个一个出

            LocatedFileStatus fileStatus = listFiles.next();

 

            //名字

            System.out.println("文件名:" + fileStatus.getPath().getName());

            //块大小

            System.out.println("大小:" + fileStatus.getBlockSize());

            //权限

            System.out.println("权限:" + fileStatus.getPermission());

            System.out.println(fileStatus.getLen());

 

 

            BlockLocation[] locations = fileStatus.getBlockLocations();

 

            for (BlockLocation bl:locations){

                System.out.println("block-offset:" + bl.getOffset());

                String[] hosts = bl.getHosts();

                for (String host:hosts){

                    System.out.println(host);

                }

            }

 

            System.out.println("------------------华丽的分割线----------------");

        }

3.2.8 HDFS文件和文件夹判断

    /**

     * 判断是否是个文件还是目录,然后打印

     * @throws Exception

     */

    @Test

    public void judge() throws Exception {

        //1.创建配置文件信息

        Configuration conf = new Configuration();

 

        //2.获取文件系统

        FileSystem fs = FileSystem.get(new URI("hdfs://bigdata111:9000"), conf, "root");

 

        //3.遍历所有的文件

        FileStatus[] liststatus = fs.listStatus(new Path("/Andy"));

        for(FileStatus status :liststatus)

        {

            //判断是否是文件

            if (status.isFile()){

                //ctrl + d:复制一行

                //ctrl + x 是剪切一行,可以用来当作是删除一行

                System.out.println("文件:" + status.getPath().getName());

            } else {

                System.out.println("目录:" + status.getPath().getName());

            }

        }

    }

3.3 通过IO流操作HDFS

3.3.1 HDFS文件上传

    /**

     * IO流方式上传

     *

     * @throws URISyntaxException

     * @throws FileNotFoundException

     * @throws InterruptedException

     */

    @Test

    public void putFileToHDFSIO() throws URISyntaxException, IOException, InterruptedException {

        //1.创建配置文件信息

        Configuration conf = new Configuration();

 

        //2.获取文件系统

        FileSystem fs = FileSystem.get(new URI("hdfs://bigdata111:9000"), conf, "root");

 

        //3.创建输入流

        FileInputStream fis = new FileInputStream(new File("F:\\date\\Sogou.txt"));

 

        //4.输出路径

        //注意:不能/Andy  记得后边写个名 比如:/Andy/Sogou.txt

        Path writePath = new Path("hdfs://bigdata111:9000/Andy/Sogou.txt");

        FSDataOutputStream fos = fs.create(writePath);

 

        //5.流对接

        //InputStream in    输入

        //OutputStream out  输出

        //int buffSize      缓冲区

        //boolean close     是否关闭流

        try {

            IOUtils.copyBytes(fis,fos,4 * 1024,false);

        } catch (IOException e) {

            e.printStackTrace();

        }finally {

            IOUtils.closeStream(fos);

            IOUtils.closeStream(fis);

            System.out.println("上传成功啦");

        }

    }

3.3.2 HDFS文件下载

/**

     * IO读取HDFS到控制台

     *

     * @throws URISyntaxException

     * @throws IOException

     * @throws InterruptedException

     */

    @Test

    public void getFileToHDFSIO() throws URISyntaxException, IOException, InterruptedException {

        //1.创建配置文件信息

        Configuration conf = new Configuration();

 

        //2.获取文件系统

        FileSystem fs = FileSystem.get(new URI("hdfs://bigdata111:9000"), conf, "root");

 

        //3.读取路径

        Path readPath = new Path("hdfs://bigdata111:9000/Andy/Sogou.txt");

 

        //4.输入

        FSDataInputStream fis = fs.open(readPath);

 

        //5.输出到控制台

        //InputStream in    输入

        //OutputStream out  输出

        //int buffSize      缓冲区

        //boolean close     是否关闭流

        IOUtils.copyBytes(fis,System.out,4 * 1024 ,true);

    }

3.3.3 定位文件读取

1下载第一块

/**

     * IO读取第一块的内容

     *

     * @throws Exception

     */

    @Test

    public void  readFlieSeek1() throws Exception {

        //1.创建配置文件信息

        Configuration conf = new Configuration();

 

        //2.获取文件系统

        FileSystem fs = FileSystem.get(new URI("hdfs://bigdata111:9000"), conf, "root");

 

        //3.输入

        Path path = new Path("hdfs://bigdata111:9000/Andy/hadoop-2.7.2.rar");

        FSDataInputStream fis = fs.open(path);

 

        //4.输出

        FileOutputStream fos = new FileOutputStream("F:\\date\\readFileSeek\\A1");

 

        //5.流对接

        byte[] buf = new byte[1024];

        for (int i = 0; i < 128 * 1024; i++) {

            fis.read(buf);

            fos.write(buf);

        }

 

        //6.关闭流

        IOUtils.closeStream(fos);

        IOUtils.closeStream(fis);

    }

2下载第二块

/**

     * IO读取第二块的内容

     *

     * @throws Exception

     */

    @Test

    public void readFlieSeek2() throws Exception {

        //1.创建配置文件信息

        Configuration conf = new Configuration();

 

        //2.获取文件系统

        FileSystem fs = FileSystem.get(new URI("hdfs://bigdata111:9000"), conf, "root");

 

        //3.输入

        Path path = new Path("hdfs://bigdata111:9000/Andy/hadoop-2.7.2.rar");

        FSDataInputStream fis = fs.open(path);

 

        //4.输出

        FileOutputStream fos = new FileOutputStream("F:\\date\\readFileSeek\\A2");

 

        //5.定位偏移量/offset/游标/读取进度 (目的:找到第一块的尾巴,第二块的开头)

        fis.seek(128 * 1024 * 1024);

 

        //6.流对接

        IOUtils.copyBytes(fis, fos, 1024);

 

        //7.关闭流

        IOUtils.closeStream(fos);

        IOUtils.closeStream(fis);

    }

3)合并文件

在window命令窗口中执行

type A2 >> A1  然后更改后缀为rar即可

HDFS的数据

4.1 HDFS写数据流程

4.1.1 剖析文件写入

 

 

1)客户端namenode请求上传文件,namenode检查目标文件是否已存在,父目录是否存在。

2namenode返回是否可以上传。

3)客户端请求第一个 block上传到哪几个datanode服务器上。

4namenode返回3datanode节点,分别为dn1、dn2、dn3。

5)客户端请求dn1上传数据,dn1收到请求会继续调用dn2,然后dn2调用dn3,将这个通信管道建立完成

6dn1、dn2、dn3逐级应答客户端

7)客户端开始往dn1上传第一个block(先从磁盘读取数据放到一个本地内存缓存),以packet为单位,dn1收到一个packet就会传给dn2,dn2传给dn3;dn1每传一个packet会放入一个应答队列等待应答

8)当一个block传输完成之后,客户端再次请求namenode上传第二个block的服务器。(重复执行3-7步)

 

  1. 客户端通过调用DistributedFileSystemcreate方法创建新文件。

 

  1. DistributedFileSystem通过RPC调用namenode去创建一个没有blocks关联的新文件,创建前, namenode会做各种校验,比如文件是否存在,客户端有无权限去创建等。如果校验通过, namenode就会记录下新文件,否则就会抛出IO异常。

 

  1. 前两步结束后,会返回FSDataOutputStream的对象,与读文件的时候相似, FSDataOutputStream被封装成DFSOutputStreamDFSOutputStream可以协调namenodedatanode。客户端开始写数据到DFSOutputStreamDFSOutputStream会把数据切成一个个小的packet,然后排成队 列data quene(数据队列)。

 

  1. DataStreamer会去处理接受data quene,它先询问namenode这个新的block最适合存储的在哪几个datanode里(比如重复数是3,那么就找到3个最适合的 datanode),把他们排成一个pipelineDataStreamerpacket按队列输出到管道的第一个datanode中,第一个 datanode又把packet输出到第二个datanode中,以此类推。

 

  1. DFSOutputStream还有一个对列叫ack quene,也是由packet组成,等待datanode的收到响应,当pipeline中的所有datanode都表示已经收到的时候,这时ack quene才会把对应的packet包移除掉。

如果在写的过程中某个datanode发生错误,会采取以下几步:

1) pipeline被关闭掉;

2) 为了防止防止丢包ack quene里的packet同步data quene里;

3) 把产生错误的datanode上当前在写但未完成的block删掉;

4) block剩下的部分被写到剩下的两个正常的datanode中;

5) namenode找到另外的datanode去创建这个块的复制。当然,这些操作对客户端来说是无感知的。

 

  1. 客户端完成写数据后调用close方法关闭写入流。

 

  1. DataStreamer把剩余得包都刷到pipeline里,然后等待ack信息,收到最后一个ack后,通知datanode把文件标视为已完成。

 

l 注意:客户端执行write操作后,写完的block才是可见的(:和下面的一致性所对应),正在写的block对客户端是不可见的,只有 调用sync方法,客户端才确保该文件的写操作已经全部完成,当客户端调用close方法时,会默认调用sync方法。是否需要手动调用取决你根据程序需 要在数据健壮性和吞吐率之间的权衡

4.1.2 网络拓扑概念

本地网络中,两个节点被称为“彼此近邻”是什么意思?海量数据处理中,其主要限制因素是节点之间数据的传输速率——带宽很稀缺。这里想法是将两个节点间的带宽作为距离的衡量标准。

节点距离:两个节点到达最近的共同祖先的距离总和。

例如,假设有数据中心d1机架r1中的节点n1节点可以表示为/d1/r1/n1利用这种标记,这里给出四种距离描述。

Distance(/d1/r1/n1, /d1/r1/n1)=0(同一节点上的进程

Distance(/d1/r1/n1, /d1/r1/n2)=2(同一机架上的不同节点

Distance(/d1/r1/n1, /d1/r3/n2)=4(同一数据中心不同机架上的节点

Distance(/d1/r1/n1, /d2/r4/n2)=6(不同数据中心的节点

 

大家算一算每两个节点之间距离

 

4.1.3 机架感知(副本节点选择)

1)官方ip地址

http://hadoop.apache.org/docs/r2.7.2/hadoop-project-dist/hadoop-common/RackAwareness.html

http://hadoop.apache.org/docs/r2.7.2/hadoop-project-dist/hadoop-hdfs/HdfsDesign.html#Data_Replication

2)低版本Hadoop副本节点选择

第一个副本client所处的节点上如果客户端在集群外,随机选一个。

二个副本和第一个副本位于不相同机架随机节点上。

三个副本和第二个副本位于相同机架节点随机。

 

3)高副本节点选择

第一个副本在client所处的节点上如果客户端在集群外,随机选一个。

二个本和第一个副本位于相同机架随机节点。

三个本位于不同机架,随机节点。

 

4.2 HDFS读数据流程

 

1)客户端向namenode请求下载文件,namenode通过查询元数据,找到文件块所在的datanode地址。

2)挑选一台datanode(就近原则,然后随机)服务器,请求读取数据

3datanode开始传输数据给客户端(从磁盘里面读取数据放入流,以packet为单位来做校验)。

4)客户端以packet为单位接收,先在本地缓存,然后写入目标文件。

 

 

  1. 首先调用FileSystem对象的open方法,其实是一个DistributedFileSystem的实例。
  2. DistributedFileSystem通过rpc获得文件的第一批blocklocations,同一个block按照重复数会返回多个locations,这些locations按照hadoop拓扑结构排序,距离客户端近的排在前面。
  3. 前两步会返回一个FSDataInputStream对象,该对象会被封装DFSInputStream对象,DFSInputStream可 以方便的管理datanodenamenode数据流。客户端调用read方法,DFSInputStream最会找出离客户端最近的datanode 并连接。
  4. 数据从datanode源源不断的流向客户端。
  5. 如果第一块的数据读完了,就会关闭指向第一块的datanode连接,接着读取下一块。这些操作对客户端来说是透明的,客户端的角度看来只是读一个持续不断的流。
  6. 如果第一批block都读完了, DFSInputStream就会去namenode拿下一批blocklocations,然后继续读,如果所有的块都读完,这时就会关闭掉所有的流。
  7. 如果在读数据的时候, DFSInputStreamdatanode的通讯发生异常,就会尝试正在读的block的排序第二近的datanode,并且会记录哪个 datanode发生错误,剩余的blocks读的时候就会直接跳过该datanodeDFSInputStream也会检查block数据校验和,如果发现一个坏的block,就会先报告到namenode节点,然后 DFSInputStream在其他的datanode上读该block的镜像。
  8. 该设计就是客户端直接连接datanode来检索数据并且namenode来负责为每一个block提供最优的datanodenamenode仅仅处理block location的请求,这些信息都加载在namenode的内存中,hdfs通过datanode集群可以承受大量客户端的并发访问。

4.3 一致性模型

1debug调试如下代码

@Test

public void writeFile() throws Exception{

// 1 创建配置信息对象

Configuration configuration = new Configuration();

fs = FileSystem.get(configuration);

 

// 2 创建文件输出流

Path path = new Path("F:\\date\\H.txt");

FSDataOutputStream fos = fs.create(path);

 

// 3 写数据

fos.write("hello Andy".getBytes());

        // 4 一致性刷新

fos.hflush();

 

fos.close();

}

2)总结

写入数据时,如果希望数据被其他client立即可见,调用如下方法

FSDataOutputStream. hflush (); //清理客户端缓冲区数据,被其他client立即可见

NameNode工作机制

5.1 NameNode&Secondary NameNode工作机制

 

 

1)第一阶段:namenode启动

1)第一次启动namenode格式化后创建fsimage和edits文件。如果不是第一次启动,直接加载编辑日志(edits)和镜像文件(fsimage)到内存

2客户端对元数据进行增删改的请求

3namenode记录操作日志,更新滚动日志

4namenode在内存中对数据进行增删改查

2)第二阶段:Secondary NameNode工作

1Secondary NameNode询问namenode是否需要checkpoint直接带回namenode是否检查结果。

2Secondary NameNode请求执行checkpoint。

3namenode滚动正在写的edits日志

4)将滚动前的编辑日志和镜像文件拷贝到Secondary NameNode

5Secondary NameNode加载编辑日志和镜像文件到内存,并合并。

6生成新的镜像文件fsimage.chkpoint

7拷贝fsimage.chkpoint到namenode

8namenodefsimage.chkpoint重新命名成fsimage

3chkpoint检查时间参数设置

1)通常情况下,SecondaryNameNode每隔一小时执行一次

[hdfs-default.xml]

<property>

  <name>dfs.namenode.checkpoint.period</name>

  <value>3600</value>

</property>

2)一分钟检查一次操作次数,当操作次数达到1百万时,SecondaryNameNode执行一次。

<property>

  <name>dfs.namenode.checkpoint.txns</name>

  <value>1000000</value>

<description>操作动作次数</description>

</property>

 

<property>

  <name>dfs.namenode.checkpoint.check.period</name>

  <value>60</value>

<description> 1分钟检查一次操作次数</description>

</property>

5.2 镜像文件和编辑日志文件

1概念

namenode被格式化之后,将在/opt/module/hadoop-2.8.4/data/dfs/name/current目录中产生如下文件,注只能在NameNode所在的节点才能找到此文件

可以执行find . -name edits* 来查找文件

edits_0000000000000000000

fsimage_0000000000000000000.md5

seen_txid

VERSION

1Fsimage文件:HDFS文件系统元数据的一个永久性的检查点,其中包含HDFS文件系统的所有目录和文件idnode的序列化信息。 

2Edits文件:存放HDFS文件系统的所有更新操作的路径,文件系统客户端执行的所有写操作首先会被记录到edits文件中。 

3seen_txid文件保存的是一个数字,就是最后一个edits_的数字

4每次Namenode启动的时候都会将fsimage文件读入内存,并从00001开始到seen_txid中记录的数字依次执行每个edits里面的更新操作,保证内存中的元数据信息是最新的、同步的,可以看成Namenode启动的时候就将fsimageedits文件进行了合并

2oiv查看fsimage文件

1查看oiv和oev命令

[itstar@bigdata111 current]$ hdfs

oiv                  apply the offline fsimage viewer to an fsimage

oev                  apply the offline edits viewer to an edits file

2)基本语法

hdfs oiv -p 文件类型 -i镜像文件 -o 转换后文件输出路径

3)案例实操

[itstar@bigdata111 current]$ pwd

/opt/module/hadoop-2.8.4/data/dfs/name/current

 

[itstar@bigdata111 current]$ hdfs oiv -p XML -i fsimage_0000000000000000316 -o /opt/fsimage.xml

 

[itstar@bigdata111 current]$ cat /opt/module/hadoop-2.8.4/fsimage.xml

将显示xml文件内容拷贝到IDEA中创建的xml文件中,并格式化

 

3oev查看edits文件

(1)基本语法

hdfs oev -p 文件类型 -i编辑日志 -o 转换后文件输出路径

-p –processor <arg>   指定转换类型: binary (二进制格式), xml (默认,XML格式),stats

-i –inputFile <arg>     输入edits文件,如果是xml后缀,表示XML格式,其他表示二进制

-o –outputFile <arg> 输出文件,如果存在,则会覆盖

(2)案例实操

[itstar@bigdata111 current]$ hdfs oev -p XML -i edits_0000000000000000135-0000000000000000135 -o /opt/module/hadoop-2.8.4/edits.xml -p stats

[itstar@bigdata111 current]$ cat /opt/module/hadoop-2.8.4/edits.xml

 

每个RECORD记录了一次操作,比如图中的

OP_ADD代表添加文件操作OP_MKDIR代表创建目录操作。里面还记录了

文件路径(PATH

修改时间(MTIME

添加时间(ATIME

客户端名称(CLIENT_NAME

客户端地址(CLIENT_MACHINE

权限(PERMISSION_STATUS)等非常有用的信息

 

将显示xml文件内容拷贝到IDEA中创建的xml文件中,并格式化

5.3 滚动编辑日志

正常情况HDFS文件系统有更新操作,就会滚动编辑日志可以用命令强制滚动编辑日志。

1)滚动编辑日志(前提必须启动集群)

[itstar@bigdata111 current]$ hdfs dfsadmin -rollEdits

 

举例:原文件名edits_inprogress_0000000000000000321

执行以下命令后

[root@bigdata111 current]# hdfs dfsadmin -rollEdits

Successfully rolled edit logs.

New segment starts at txid 323

edits_inprogress_0000000000000000321 => edits_inprogress_0000000000000000323

2)镜像文件什么时候产生

Namenode启动时加载镜像文件和编辑日志

5.4 namenode版本

1查看namenode版本号

在/opt/module/hadoop-2.8.4/data/dfs/name/current这个目录下查看VERSION

namespaceID=1778616660

clusterID=CID-bc165781-d10a-46b2-9b6f-3beb1d988fe0

cTime=1552918200296

storageType=NAME_NODE

blockpoolID=BP-274621862-192.168.1.111-1552918200296

layoutVersion=-63

2)namenode版本号具体解释

1namespaceIDHDFS,会有多个Namenode,所以不同NamenodenamespaceID是不同的,分别管理一组blockpoolID

2clusterID集群id,全局唯一

3cTime属性标记了namenode存储系统的创建时间,对于刚刚格式化的存储系统,这个属性为0但是在文件系统升级之后,该值会更新到新的时间戳。

4storageType属性说明该存储目录包含的是namenode的数据结构。

5blockpoolID一个block pool id标识一个block pool,并且是跨集群的全局唯一。当一个新的Namespace被创建的时候(format过程的一部分)会创建并持久化一个唯一ID。在创建过程构建全局唯一的BlockPoolID比人为的配置更可靠一些。NNBlockPoolID持久化到磁盘中,在后续的启动过程中,会再次load并使用。

6layoutVersion一个负整数。通常只有HDFS增加新特性时才会更新这个版本号。

7storageID (存储ID):是DataNodeID,不唯一

5.5 SecondaryNameNode目录结构

Secondary NameNode用来监控HDFS状态的辅助后台程序,每隔一段时间获取HDFS元数据的快照。

在/opt/module/hadoop-2.8.4/data/dfs/namesecondary/current这个目录中查看SecondaryNameNode目录结构。

edits_0000000000000000001-0000000000000000002

fsimage_0000000000000000002

fsimage_0000000000000000002.md5

VERSION

SecondaryNameNode的namesecondary/current目录和主namenodecurrent目录的布局相同。

好处:在主namenode发生故障时(假设没有及时备份数据),可以SecondaryNameNode恢复数据

方法一:将SecondaryNameNode中数据拷贝到namenode存储数据的目录;

方法二:使用-importCheckpoint选项启动namenode守护进程,从而将SecondaryNameNode中数据拷贝到namenode目录

1)案例实操(一)

模拟namenode故障,并采用方法一,恢复namenode数据

1kill -9 namenode进程

2删除namenode存储的数据(/opt/module/hadoop-2.8.4/data/dfs/name)

rm -rf /opt/module/hadoop-2.8.4/data/dfs/name/*

 

注:此时hadoop-daemon.sh stop namenode关闭NN,

然后hadoop-daemon.sh start namenode重启NN,发现50070页面启动不了

3拷贝SecondaryNameNode中数据到原namenode存储数据目录

cp -r /opt/module/hadoop-2.8.4/data/dfs/namesecondary/* /opt/module/hadoop-2.8.4/data/dfs/name/

4重新启动namenode

sbin/hadoop-daemon.sh start namenode

2)案例实操(二)

模拟namenode故障,并采用方法,恢复namenode数据

0)修改hdfs-site.xml中配置,value的单位是秒,默认3600,即1小时,仅配置一台即可

<property>

  <name>dfs.namenode.checkpoint.period</name>

  <value>120</value>

</property>

 

<property>

  <name>dfs.namenode.name.dir</name>

  <value>/opt/module/hadoop-2.8.4/data/dfs/name</value>

</property>

1kill -9 namenode进程

2删除namenode存储的数据(/opt/module/hadoop-2.8.4/data/dfs/name)

rm -rf /opt/module/hadoop-2.8.4/data/dfs/name/*

3)如果SecondaryNameNode不和Namenode在一个主机节点上,需要将SecondaryNameNode存储数据的目录拷贝到Namenode存储数据的平级目录。

[itstar@bigdata111 dfs]$ pwd

/opt/module/hadoop-2.8.4/data/dfs

[itstar@bigdata111 dfs]$ ls

data  name  namesecondary

(4)导入检查点数据(等待一会ctrl+c结束掉)

bin/hdfs namenode -importCheckpoint

(5)启动namenode

sbin/hadoop-daemon.sh start namenode

(6)如果提示文件锁了,可以删除in_use.lock

rm -rf /opt/module/hadoop-2.8.4/data/dfs/namesecondary/in_use.lock

5.6 集群安全模式操作

1)概述

Namenode启动时,首先将映像文件(fsimage载入内存,并执行编辑日志(edits的各项操作。一旦内存中成功建立文件系统元数据的映像,则创建一个新的fsimage文件和一个空的编辑日志。此时,namenode开始监听datanode请求。但是此刻,namenode运行在安全模式,即namenode文件系统对于客户端来说是只读的。

系统中的数据块的位置并不是由namenode维护的,而是以块列表的形式存储在datanode中。系统的正常操作期间,namenode会在内存中保留所有块位置的映射信息。在安全模式下,各个datanode向namenode发送最新的块列表信息namenode了解到足够的块位置信息之后,即可高效运行文件系统。

如果满足“最小副本条件”,namenode会在30钟之后就退出安全模式。所谓最小副本条件指的是在整个文件系统中99.9%的块满足最小副本级别(默认值:dfs.replication.min=1启动一个刚刚格式化的HDFS集群时,因为系统中还没有任何块,所以namenode不会进入安全模式。

2)基本语法

集群处于安全模式,不能执行重要操作(操作)集群启动完成后,自动退出安全模式。

(1)bin/hdfs dfsadmin -safemode get (功能描述:查看安全模式状态

2bin/hdfs dfsadmin -safemode enter   (功能描述:进入安全模式状态

3bin/hdfs dfsadmin -safemode leave (功能描述:离开安全模式状态

4bin/hdfs dfsadmin -safemode wait (功能描述:等待安全模式状态

3)案例

模拟等待安全模式

1)先进入安全模式

bin/hdfs dfsadmin -safemode enter

2)执行下面的脚本

编辑一个脚本(注:必须已设置环境变量,要不就写绝对路径)

#!bin/bash

hdfs dfsadmin -safemode wait

hadoop fs -put /opt/BBB /

3)再打开一个窗口,执行

bin/hdfs dfsadmin -safemode leave

5.7 Namenode目录配置

1namenode的本地目录可以配置成多个,每个目录存放内容相同,增加了可靠性

2具体配置如下:

hdfs-site.xml

<property>

    <name>dfs.namenode.name.dir</name>

<value>file:///${hadoop.tmp.dir}/dfs/name1,file:///${hadoop.tmp.dir}/dfs/name2</value>

</property>

  1. 停止集群 删除data 和 logs  rm -rf data/* logs/*
  2. hdfs namenode -format
  3. start-dfs.sh
  4. 去展示

https://blog.csdn.net/qq_39657909/article/details/85553525

实验总结:

思考1如果在非Namenode节点、进行格式化(hdfs namenode -format)

是否和在NN节点上同样会生成name1和name2目录呢?

    答:只要配置了以上得配置,在该节点下同样会生成name1name2

具体解释:

格式化做了哪些事情?

NameNode节点上,有两个最重要的路径,分别被用来存储元数据信息和操作日志,而这两个路径来自于配置文件,它们对应的属性分别是dfs.name.dir和dfs.name.edits.dir,同时,它们默认的路径均是/tmp/hadoop/dfs/name。格式化时,NameNode会清空两个目录下的所有文件,之后,格式化会在目录dfs.name.dir下创建文件

hadoop.tmp.dir 这个配置,会让dfs.name.dir和dfs.name.edits.dir会让两个目录的文件生成在一个目录里

 

思考2NN上如果生成了name1和name2,那么他和NN上生成得有没有差别?

答:有区别、NN节点上会产生新得edits_XXX,非NN不会fsimage会更新,而非NN不会,只会产生一个仅初始化得到得fsimage,不会生成edits,更不会发生日志滚动。

DataNode工作机制

6.1 NameNode & DataNode工作机制

 

1一个数据块在datanode上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据校验和,以及时间戳

2DataNode启动后向namenode注册,通过后,周期性(1小时namenode上报所有的块信息。

3心跳是每3一次,心跳返回结果带有namenode给该datanode的命令如复制块数据到另一台机器,或删除某个数据块如果超过10分钟没有收到某个datanode的心跳,则认为该节点不可用。

4集群运行中可以安全加入和退出一些机器

6.2 数据完整性

1当DataNode读取block的时候,它会计算checksum校验和

2如果计算后的checksum,与block创建时值不一样,说明block已经损坏。

3client读取其他DataNode上的block.

4datanode在其文件创建后周期验证checksum校验和

6.3 掉线时限参数设置

datanode进程死亡或者网络故障造成datanode无法与namenode通信,namenode不会立即把该节点判定为死亡,要经过一段时间,这段时间暂称作超时时长。HDFS默认的超时时长为10分钟+30。如果定义超时时间为timeout,则超时时长的计算公式为:

timeout  = 2 * dfs.namenode.heartbeat.recheck-interval + 10 * dfs.heartbeat.interval

而默认的dfs.namenode.heartbeat.recheck-interval 大小为5分钟,dfs.heartbeat.interval默认为3秒。

需要注意的是hdfs-site.xml 配置文件中的heartbeat.recheck.interval的单位为毫秒dfs.heartbeat.interval的单位为秒。

<property>

    <name>dfs.namenode.heartbeat.recheck-interval</name>

    <value>300000</value>

</property>

<property>

    <name> dfs.heartbeat.interval </name>

    <value>3</value>

</property>

6.4 DataNode的目录结构

和namenode不同的是,datanode的存储目录是初始阶段自动创建的,不需要额外格式化。

1)在/opt/module/hadoop-2.8.4/data/dfs/data/current这个目录下查看版本号

[itstar@bigdata111 current]$ cat VERSION

storageID=DS-1b998a1d-71a3-43d5-82dc-c0ff3294921b

clusterID=CID-1f2bf8d1-5ad2-4202-af1c-6713ab381175

cTime=0

datanodeUuid=970b2daf-63b8-4e17-a514-d81741392165

storageType=DATA_NODE

layoutVersion=-56

2)具体解释

1storageID:存储id

2clusterID集群id,全局唯一

3cTime属性标记了datanode存储系统的创建时间,对于刚刚格式化的存储系统,这个属性为0但是在文件系统升级之后,该值会更新到新的时间戳。

4datanodeUuiddatanode的唯一识别码

5storageType:存储类型

6layoutVersion一个负整数。通常只有HDFS增加新特性时才会更新这个版本号。

3)在/opt/module/hadoop-2.8.4/data/dfs/data/current/BP-97847618-192.168.10.102-1493726072779/current这个目录下查看该数据的版本号

[itstar@bigdata111 current]$ cat VERSION

#Mon May 08 16:30:19 CST 2017

namespaceID=1933630176

cTime=0

blockpoolID=BP-97847618-192.168.10.102-1493726072779

layoutVersion=-56

4)具体解释

1namespaceID:datanode首次访问namenode的时候从namenode处获取的storageID每个datanode来说是唯一的(但对于单个datanode中所有存储目录来说则是相同的),namenode可用这个属性来区分不同datanode

2cTime属性标记了datanode存储系统的创建时间,对于刚刚格式化的存储系统,这个属性为0但是在文件系统升级之后,该值会更新到新的时间戳。

3blockpoolID一个block pool id标识一个block pool,并且是跨集群的全局唯一。当一个新的Namespace被创建的时候(format过程的一部分)会创建并持久化一个唯一ID。在创建过程构建全局唯一的BlockPoolID比人为的配置更可靠一些。NNBlockPoolID持久化到磁盘中,在后续的启动过程中,会再次load并使用。

4layoutVersion一个负整数。通常只有HDFS增加新特性时才会更新这个版本号。

6.5 Datanode目录配置

1datanode也可以配置成多个目录,每个目录存储的数据不一样。:数据不是副本。

2)具体配置如下:

hdfs-site.xml

<property>

        <name>dfs.datanode.data.dir</name>

      <value>file:///${hadoop.tmp.dir}/dfs/data1,file:///${hadoop.tmp.dir}/dfs/data2</value>

</property>

 

HDFS其他功能

7.1 集群间数据拷贝

1scp实现两个远程主机之间的文件复制

scp -r hello.txt root@bigdata111:/user/itstar/hello.txt // push

scp -r root@bigdata112:/user/itstar/hello.txt  hello.txt // pull

scp -r root@bigdata112:/opt/module/hadoop-2.8.4/LICENSE.txt root@bigdata113:/opt/module/hadoop-2.8.4/LICENSE.txt   

//是通过本地主机中转实现两个远程主机的文件复制;如果在两个远程主机之间ssh没有配置的情况下可以使用该方式。

2采用discp命令实现两个hadoop集群之间的递归数据复制(:不用设置其他,直接写IP)

bin/hadoop distcp hdfs://192.168.1.51:9000/LICENSE.txt hdfs://192.168.1.111:9000/HAHA

7.2 Hadoop存档

1)理论概述

每个文件均按块存储,每个块的元数据存储在namenode的内存中,因此hadoop存储小文件会非常低效。因为大量的小文件会耗尽namenode中的大部分内存。但注意,存储小文件所需要的磁盘容量和存储这些文件原始内容所需要的磁盘空间相比也不会增多。例如一个1MB的文件以大小为128MB的块存储,使用的是1MB磁盘空间,而不是128MB

Hadoop存档文件或HAR文件,是一个更高效的文件存档工具,它将文件存入HDFS块,在减少namenode内存使用的同时,允许对文件进行透明的访问。具体来,Hadoop存档文件可以用作MapReduce的输入。

https://www.cnblogs.com/staryea/p/8603112.html

2)案例实操

1需要启动yarn进程

start-yarn.sh

2归档文件

归档成一个叫做xxx.har的文件夹,该文件夹下有相应的数据文件。Xx.har目录是一个整体,该目录看成是一个归档文件即可。

用法:hadoop archive -archiveName  归档名称 -p 父目录 [-r <复制因子>]  原路径(可以多个)  目的路径

bin/ hadoop archive -archiveName foo.har -p /Andy -r 3 a b c /

3)查看归档

hadoop fs -lsr /user/my/myhar.har

hadoop fs -lsr har:///myhar.har

 

4)解归档文件

取消存档:hadoop fs -cp har:/// user/my/myhar.har /* /user/itstar

并行解压缩:hadoop distcp har:/foo.har /001

7.3 快照管理

快照相当于对目录做一个备份不会立即复制所有文件,而是指向同一个文件。当写入发生时,才会产生新文件。

1)基本语法

1hdfs dfsadmin -allowSnapshot 路径   (功能描述:开启指定目录的快照功能

(2)hdfs dfsadmin -disallowSnapshot 路径 (功能描述:禁用定目录的快照功能,默认是禁用

3hdfs dfs -createSnapshot 路径        (功能描述:目录创建快照

(4)hdfs dfs -createSnapshot 路径 名称   (功能描述:指定名称创建快照

5hdfs dfs -renameSnapshot 路径 旧名称 名称 (功能描述:重命名快照

(6)hdfs lsSnapshottableDir         (功能描述:列出当前用户所有快照目录

(7)hdfs snapshotDiff 路径1 路径2 (功能描述:比较两个快照目录的不同之处

8hdfs dfs -deleteSnapshot <path> <snapshotName>  (功能描述:删除快照

2案例实操

1)开启/禁用指定目录的快照功能

hdfs dfsadmin -allowSnapshot /user/itstar/data

hdfs dfsadmin -disallowSnapshot /user/itstar/data

2)对目录创建快照

hdfs dfs -createSnapshot /user/itstar/data // 目录创建快照

通过web访问hdfs://bigdata111:9000/user/itstar/data/.snapshot/s…..// 快照和源文件使用相同数据块

hdfs dfs -lsr /user/itstar/data/.snapshot/

3)指定名称创建快照

hdfs dfs -createSnapshot /user/itstar/data miao170508

4)重命名快照(注:快照是只读的,无法修改名)

√) dfs -renameSnapshot /Andy/ andy bndy

注:路径只是你创建得名字/Andy,不要带后边得/Andy/.snapshot/,不然会出现

renameSnapshot: Modification on a read-only snapshot is disallowed

5)列出当前用户所有可快照目录

hdfs lsSnapshottableDir

6)比较两个快照目录的不同之处

hdfs snapshotDiff /user/itstar/data/  .  .snapshot/itstar170508

7)恢复快照

  1. 自定义创建一个快照名:hdfs dfs -createSnapshot /HAHA1 miaomiao
  2. 展示原文件包含内容:Hadoop fs -ls /HAHA1
  3. 里面有五个文件、删除其中1~2

/HAHA1/.snapshot/miaomiao1

  1. 回复快照:hdfs dfs -cp /HAHA1/.snapshot/miaomiao1 /miaomiao

8)删除快照

hdfs dfs -deleteSnaphost /001名字

 

7.4 回收站

1默认回收站

默认fs.trash.interval=00表示禁用回收站,可以设置删除文件的存活时间

默认fs.trash.checkpoint.interval=0,检查回收站的间隔时间

要求fs.trash.checkpoint.interval<=fs.trash.interval。

 

2)启用回收站

修改core-site.xml,配置垃圾回收时间1分钟。

<property>

    <name>fs.trash.interval</name>

    <value>1</value>

</property>

3)查看回收站

回收集群中的;路径:/user/itstar/.Trash/….

4)修改访问垃圾回收站用户名称

进入垃圾回收站用户名称,默认是dr.who,修改为itstar用户

[core-site.xml]

<property>

  <name>hadoop.http.staticuser.user</name>

  <value>itstar</value>

</property>

5)通过程序删除的文件不会经过回收站,需要调用moveToTrash()进入回收站

Trash trash = New Trash(conf);

trash.moveToTrash(path);

6)恢复回收站数据

hadoop fs -mv /user/itstar/.Trash/Current/user/itstar/input    /user/itstar/input

7)清空回收站

hdfs dfs -expunge

HDFS HA高可用

8.1 HA概述

1)所谓HA(high available),即高可用(7*24小时不中断服务)

2)实现高可用最关键策略是消除单点故障。HA严格来说应该分成各个组件的HA机制HDFSHAYARNHA

3Hadoop2.0之前,在HDFS集群中NameNode存在单点故障(SPOF

4)NameNode主要在以下两个方面影响HDFS集群

NameNode机器发生意外,如宕机,集群将无法使用,直到管理员重启

NameNode机器需要升级,包括软件、硬件升级,此时集群也将无法使用

HDFS HA功能通过配置Active/Standby两个nameNodes实现在集群中对NameNode的热备来解决上述问题。如果出现故障,如机器崩溃或机器需要升级维护,这时可通过此种方式将NameNode很快的切换到另外一台机器。

8.2 HDFS-HA工作机制

1)通过双namenode消除单点故障

8.2.1 HDFS-HA工作要点

1)元数据管理方式需要改变:

内存中各自保存一份元数据;

Edits日志只有Active状态的namenode节点可以做写操作;

两个namenode都可以读取edits;

共享的edits放在一个共享存储中管理(qjournal和NFS两个主流实现);

2)需要一个状态管理功能模块

实现了一个zkfailover,常驻在每一个namenode所在的节点,每一个zkfailover负责监控自己所在namenode节点,利用zk进行状态标识,当需要进行状态切换时,由zkfailover来负责切换,切换时需要防止brain split(脑裂)现象的发生。

3必须保证两个NameNode之间能够ssh无密码登录

4)隔离Fence同一时刻仅仅有一个NameNode对外提供服务

8.2.2 HDFS-HA自动故障转移工作机制

自动故障转移为HDFS部署增加了两个新组件:ZooKeeperZKFailoverControllerZKFC)进程。ZooKeeper是维护少量协调数据,通知客户端这些数据的改变和监视客户端故障的高可用服务。HA的自动故障转移依赖于ZooKeeper的以下功能:

1故障检测:集群中的每个NameNodeZooKeeper中维护了一个持久会话,如果机器崩溃,ZooKeeper中的会话将终止,ZooKeeper通知另一个NameNode需要触发故障转移。

2现役NameNode选择:ZooKeeper提供了一个简单的机制用于唯一的选择一个节点为active状态。如果目前现役NameNode崩溃,另一个节点可能从ZooKeeper获得特殊的排外锁以表明它应该成为现役NameNode

ZKFC是自动故障转移中的另一个新组件,是ZooKeeper的客户端,也监视和管理NameNode的状态。每个运行NameNode的主机也运行了一个ZKFC进程,ZKFC负责:

1健康监测:ZKFC使用一个健康检查命令定期地ping与之在相同主机的NameNode,只要该NameNode及时地回复健康状态,ZKFC认为该节点是健康的。如果该节点崩溃,冻结或进入不健康状态,健康监测器标识该节点为非健康的。

2ZooKeeper会话管理:当本地NameNode是健康的,ZKFC保持一个在ZooKeeper中打开的会话。如果本地NameNode处于active状态,ZKFC也保持一个特殊的znode锁,该锁使用了ZooKeeper对短暂节点的支持,如果会话终止,锁节点将自动删除。

3基于ZooKeeper的选择:如果本地NameNode是健康的,且ZKFC发现没有其它的节点当前持有znode锁,它将为自己获取该锁。如果成功,则它已经赢得了选择,并负责运行故障转移进程以使它的本地NameNodeactive

 

8.4 HDFS-HA集群配置

8.4.1 环境准备

1)修改IP

2)修改主机名及主机名和IP地址的映射

3)关闭防火墙

4ssh免密登录

5)安装JDK,配置环境变量等

8.4.2 规划集群

bigdata111   bigdata112    bigdata113

NameNode NameNode

JournalNode JournalNode JournalNode

DataNode DataNode DataNode

ZK ZK ZK

ResourceManager

NodeManager NodeManager NodeManager

8.4.3 配置Zookeeper集群

0)集群规划

在bigdata111、bigdata112和bigdata113三个节点上部署Zookeeper。

1解压安装

1)解压zookeeper安装包到/opt/module/目录下

[itstar@bigdata111 software]$ tar -zxvf zookeeper-3.4.10.tar.gz -C /opt/module/

2)在/opt/module/zookeeper-3.4.10/这个目录下创建zkData

mkdir -p zkData

3)重命名/opt/module/zookeeper-3.4.10/conf这个目录下的zoo_sample.cfg为zoo.cfg

mv zoo_sample.cfg zoo.cfg

2)配置zoo.cfg文件

1)具体配置

dataDir=/opt/module/zookeeper-3.4.10/zkData

增加如下配置

#######################cluster##########################

server.1=bigdata111:2888:3888

server.2=bigdata112:2888:3888

server.3=bigdata113:2888:3888

2)配置参数解读

Server.A=B:C:D。

A是一个数字,表示这个是第几号服务器;

B是这个服务器的ip地址;

C是这个服务器与集群中的Leader服务器交换信息的端口;

D是万一集群中的Leader服务器挂了,需要一个端口来重新进行选举,选出一个新的Leader,而这个端口就是用来执行选举时服务器相互通信的端口。

集群模式下配置一个文件myid,这个文件在dataDir目录下,这个文件里面有一个数据就是A的值,Zookeeper启动时读取此文件,拿到里面数据与zoo.cfg里面的配置信息比较从而判断到底是哪个server

3)集群操作

1/opt/module/zookeeper-3.4.10/zkData目录下创建一个myid的文件

touch myid

添加myid文件,注意一定要在linux里面创建notepad++里面很可能乱码

2编辑myid文件

vi myid

文件中添加与server的编号:如2

3)拷贝配置好的zookeeper到其他机器上

scp -r zookeeper-3.4.10/ root@bigdata112.itstar.com:/opt/app/

scp -r zookeeper-3.4.10/ root@bigdata113.itstar.com:/opt/app/

分别修改myid文件中内容为34

4分别启动zookeeper

[root@bigdata111 zookeeper-3.4.10]# bin/zkServer.sh start

[root@bigdata112 zookeeper-3.4.10]# bin/zkServer.sh start

[root@bigdata113 zookeeper-3.4.10]# bin/zkServer.sh start

5查看状态

[root@bigdata111 zookeeper-3.4.10]# bin/zkServer.sh status

JMX enabled by default

Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg

Mode: follower

[root@bigdata112 zookeeper-3.4.10]# bin/zkServer.sh status

JMX enabled by default

Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg

Mode: leader

[root@bigdata113 zookeeper-3.4.5]# bin/zkServer.sh status

JMX enabled by default

Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg

Mode: follower

8.4.4 配置HDFS-HA集群

1官方地址:http://hadoop.apache.org/

2在opt目录下创建一个ha文件夹

mkdir ha

3将/opt/app/下 hadoop-2.8.4拷贝/opt/ha目录

cp -r hadoop-2.8.4/ /opt/ha/

4配置hadoop-env.sh

export JAVA_HOME=/opt/module/jdk1.8.0_144

5配置core-site.xml

<configuration>

<!-- 把两个NameNode)的地址组装成一个集群mycluster -->

<property>

<name>fs.defaultFS</name>

         <value>hdfs://mycluster</value>

</property>

 

<!-- 指定hadoop运行时产生文件的存储目录 -->

<property>

<name>hadoop.tmp.dir</name>

<value>/opt/HA/hadoop-2.8.4/data</value>

</property>

</configuration>

6配置hdfs-site.xml

<configuration>

<!-- 完全分布式集群名称 -->

<property>

<name>dfs.nameservices</name>

<value>mycluster</value>

</property>

 

<!-- 集群中NameNode节点都有哪些 -->

<property>

<name>dfs.ha.namenodes.mycluster</name>

<value>nn1,nn2</value>

</property>

 

<!-- nn1RPC通信地址 -->

<property>

<name>dfs.namenode.rpc-address.mycluster.nn1</name>

<value>bigdata111:9000</value>

</property>

 

<!-- nn2RPC通信地址 -->

<property>

<name>dfs.namenode.rpc-address.mycluster.nn2</name>

<value>bigdata112:9000</value>

</property>

 

<!-- nn1http通信地址 -->

<property>

<name>dfs.namenode.http-address.mycluster.nn1</name>

<value>bigdata111:50070</value>

</property>

 

<!-- nn2http通信地址 -->

<property>

<name>dfs.namenode.http-address.mycluster.nn2</name>

<value>bigdata112:50070</value>

</property>

 

<!-- 指定NameNode元数据在JournalNode上的存放位置 -->

<property>

<name>dfs.namenode.shared.edits.dir</name>

 <value>qjournal://bigdata111:8485;bigdata112:8485;bigdata113:8485/mycluster</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>

 

<!-- 声明journalnode服务器存储目录-->

<property>

<name>dfs.journalnode.edits.dir</name>

<value>/opt/HA/hadoop-2.8.4/data/jn</value>

</property>

 

<!-- 关闭权限检查-->

<property>

<name>dfs.permissions.enable</name>

<value>false</value>

</property>

 

<!-- 访问代理类:clientmyclusteractive配置失败自动切换实现方式-->

<property>

   <name>dfs.client.failover.proxy.provider.mycluster</name>

<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>

</property>

</configuration>

        <!--secondary NameNode的地址,端口号是50090-->

        <property>

                <name>dfs.namenode.secondary.http-address</name>

                <value>bigdata112:50090</value>

        </property>

7)拷贝配置好的hadoop环境到其他节点

注意需要scp到其他节点

8.4.5 启动HDFS-HA集群

1在各个JournalNode节点上,输入以下命令启动journalnode服务:

Journalnode主要是用来做数据之间共享的。

sbin/hadoop-daemon.sh start journalnode

2)在[nn1],对其进行格式化,并启动:

bin/hdfs namenode -format

sbin/hadoop-daemon.sh start namenode

3)在[nn2],同步nn1的元数据信息:

bin/hdfs namenode -bootstrapStandby

4)启动[nn2]

sbin/hadoop-daemon.sh start namenode

5查看web页面显示

 

 

6)[nn1],启动所有datanode

sbin/hadoop-daemons.sh start datanode

7查看是否Active

bin/hdfs haadmin -getServiceState nn1

8)将[nn1]切换Active

切换为Active:bin/hdfs haadmin -transitionToActive nn1

切换为Standby:bin/hdfs haadmin -transitionToStandby nn1

8.4.6 配置HDFS-HA自动故障转移

1)具体配置

1)在hdfs-site.xml中增加

<property>

<name>dfs.ha.automatic-failover.enabled</name>

<value>true</value>

</property>

2)在core-site.xml文件中增加

<property>

<name>ha.zookeeper.quorum</name>

<value>bigdata111:2181,bigdata112:2181,bigdata113:2181</value>

</property>

2)启动

1)关闭所有HDFS服务:

sbin/stop-dfs.sh

2)启动Zookeeper集群:

bin/zkServer.sh start

3)初始化HAZookeeper状态

bin/hdfs zkfc -formatZK

4)启动HDFS服务:

sbin/start-dfs.sh

5)在各个NameNode节点上启动DFSZK Failover Controller,先在哪台机器启动,哪个机器的NameNode就是Active NameNode

sbin/hadoop-daemon.sh start zkfc

3)验证

1)将Active NameNode进程kill

kill -9 namenode的进程id

2)将Active NameNode机器断开网络

service network stop

8.5 YARN-HA配置

8.5.1 YARN-HA工作机制

1)官方文档:

http://hadoop.apache.org/docs/r2.7.2/hadoop-yarn/hadoop-yarn-site/ResourceManagerHA.html

2YARN-HA工作机制

 

8.5.2 配置YARN-HA集群

0)环境准备

1)修改IP

2)修改主机名及主机名和IP地址的映射

3)关闭防火墙

4ssh免密登录

5)安装JDK,配置环境变量等

6)配置Zookeeper集群

1规划集群

bigdata111   bigdata112    bigdata113

NameNode NameNode

JournalNode JournalNode JournalNode

DataNode DataNode DataNode

ZK ZK ZK

ResourceManager ResourceManager

NodeManager NodeManager NodeManager

2)具体配置

1yarn-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>

 

    <property>

        <name>yarn.resourcemanager.ha.rm-ids</name>

        <value>rm1,rm2</value>

    </property>

 

    <property>

        <name>yarn.resourcemanager.hostname.rm1</name>

        <value>bigdata111</value>

    </property>

 

    <property>

        <name>yarn.resourcemanager.hostname.rm2</name>

        <value>bigdata112</value>

    </property>

 

    <!--指定zookeeper集群的地址-->

    <property>

        <name>yarn.resourcemanager.zk-address</name>

        <value>bigdata111:2181,bigdata112:2181,bigdata113: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.ZKRMStateStore</value>

</property>

 

</configuration>

2)同步更新其他节点配置信息

3启动hdfs 

1在各个JournalNode节点上,输入以下命令启动journalnode服务:

sbin/hadoop-daemon.sh start journalnode

2)在[nn1],对其进行格式化,并启动:

bin/hdfs namenode -format

sbin/hadoop-daemon.sh start namenode

3)在[nn2],同步nn1的元数据信息:

bin/hdfs namenode -bootstrapStandby

4)启动[nn2]

sbin/hadoop-daemon.sh start namenode

5启动所有datanode

sbin/hadoop-daemons.sh start datanode

6)将[nn1]切换Active

bin/hdfs haadmin -transitionToActive nn1

4)启动yarn

1)在bigdata111中执行:

sbin/start-yarn.sh

2)在bigdata112中执行:

sbin/yarn-daemon.sh start resourcemanager

3)查看服务状态

bin/yarn rmadmin -getServiceState rm1

 

posted @ 2019-07-26 02:10  jareny  阅读(552)  评论(0编辑  收藏  举报