Hadoop之HDFS基础

一。 HDFS概念

1.1 概念

    HDFS是一个分布式文件系统,用于存储文件,经过目录树来定位文件,适合一次写入,屡次读出的场景,且不支持文件的修改。适合用来作数据分析,并不适合用来作网盘应用。html

1.2 组成

1)HDFS集群包括,NameNode和DataNode以及Secondary Namenode。java

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

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

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

1.3 HDFS 文件块大小

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

    HDFS的块比磁盘的块大,其目的是为了最小化寻址开销,且传输一个由多个块组成的文件的时间取决于磁盘传输速率。缓存

    若是寻址时间约为10ms,而传输速率为100MB/s,为了使寻址时间仅占传输时间的1%,咱们要将块大小设置约为100MB。默认的块大小实际为64MB,可是不少状况下HDFS使用128MB的块设置。安全

    块的大小:10ms*100*100M/s = 100M服务器

二 。HFDS命令行操做

1)基本语法网络

    hadoop fs 具体命令

2)参数大全

3)经常使用命令实操

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

    (2)-ls: 显示目录信息

  (3)-mkdir:在hdfs上建立目录

         hadoop fs  -mkdir  -p  /aaa/bbb/cc/dd

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

        hadoop  fs  - moveFromLocal  /home/hadoop/a.txt  /aaa/bbb/cc/dd

  (5)-moveToLocal:从hdfs剪切粘贴到本地

        hadoop  fs  - moveToLocal   /aaa/bbb/cc/dd  /home/hadoop/a.txt

  (6)--appendToFile  :追加一个文件到已经存在的文件末尾

        hadoop  fs  -appendToFile  ./hello.txt  /hello.txt

  (7)-cat :显示文件内容

        hadoop  fs  -cat  /hello.txt

  (8)-tail:显示一个文件的末尾

         hadoop  fs  -tail  /weblog/access_log.1

  (9)-text:以字符形式打印一个文件的内容

        hadoop  fs  -text  /weblog/access_log.1

  (10)-chgrp 、-chmod、-chown:linux文件系统中的用法同样,修改文件所属权限

        hadoop  fs  -chmod  666  /hello.txt

        hadoop  fs  -chown  someuser:somegrp   /hello.txt

  (11)-copyFromLocal:从本地文件系统中拷贝文件到hdfs路径去

        hadoop  fs  -copyFromLocal  ./jdk.tar.gz  /aaa/

  (12)-copyToLocal:从hdfs拷贝到本地

        hadoop fs -copyToLocal /aaa/jdk.tar.gz

  (13)-cp :从hdfs的一个路径拷贝到hdfs的另外一个路径

        hadoop  fs  -cp  /aaa/jdk.tar.gz  /bbb/jdk.tar.gz.2

  (14)-mv:在hdfs目录中移动文件

        hadoop  fs  -mv  /aaa/jdk.tar.gz  /

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

        hadoop fs -get  /aaa/jdk.tar.gz

  (16)-getmerge  :合并下载多个文件,好比hdfs的目录 /aaa/下有多个文件:log.1, log.2,log.3,...

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

  (17)-put:等同于copyFromLocal

        hadoop  fs  -put  /aaa/jdk.tar.gz  /bbb/jdk.tar.gz.2

  (18)-rm:删除文件或文件夹

        hadoop fs -rm -r /aaa/bbb/

  (19)-rmdir:删除空目录

        hadoop  fs  -rmdir   /aaa/bbb/ccc

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

        hadoop  fs  -df  -h  /

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

        hadoop  fs  -du  -s  -h /aaa/*

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

        hadoop fs -count /aaa/

  (23)-setrep:设置hdfs中文件的副本数量

        hadoop fs -setrep 3 /aaa/jdk.tar.gz

        这里设置的副本数只是记录在namenode的元数据中,是否真的会有这么多副本,还得看datanode的数量。

三。HDFS客户端操做

3.1 一个完整的Java操做,在hdfs上建立目录

package com.hdfs;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.net.URI;

public class HDFSApp {
    public static final String HDFS_PATH ="hdfs://hadoop102:9000";

    Configuration configuration = null ;
    FileSystem fileSystem = null;

    @Before
    public void setUp() throws Exception {
        System.out.println("HDFSApp.setUp()");
        configuration = new Configuration();
        fileSystem = FileSystem.get(new URI(HDFS_PATH), configuration);
    }

    @After
    public void tearDown(){
        fileSystem = null;
        configuration = null;
        System.out.println("HDFSApp.tearDown()");
    }

    // 建立目录,不会覆盖已经存在的目录
    @Test
    public void mkdir() throws IOException {
        fileSystem.mkdirs(new Path("/hdfsApi/test"));
    }
}

能够查看到hdfs建立的目录

3.2 经过API操做HDFS

3.2.1 HDFS获取文件系统

1)详细代码

    @Test
    public void initHDFS() throws Exception{
        // 1 建立配置信息对象
        // new Configuration();的时候,它就会去加载jar包中的hdfs-default.xml
        // 而后再加载classpath下的hdfs-site.xml
        Configuration configuration = new Configuration();
        
        // 2 设置参数 
        // 参数优先级: 一、客户端代码中设置的值  二、classpath下的用户自定义配置文件 三、而后是服务器的默认配置
        //  configuration.set("fs.defaultFS", "hdfs://hadoop102:9000");
        configuration.set("dfs.replication", "3");
        
        // 3 获取文件系统
        FileSystem fs = FileSystem.get(configuration);
        
        // 4 打印文件系统
        System.out.println(fs.toString());
    }

2)将core-site.xml拷贝到项目的根目录下

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>

<configuration>
<!-- 指定HDFS中NameNode的地址 -->
    <property>
        <name>fs.defaultFS</name>
        <value>hdfs://hadoop102:9000</value>
    </property>

    <!-- 指定hadoop运行时产生文件的存储目录 -->
    <property>
        <name>hadoop.tmp.dir</name>
        <value>/opt/module/hadoop/data/tmp</value>
    </property>
</configuration>

3.2.2 HDFS文件上传

    @Test
    public void putFileToHDFS() throws Exception{
        // 1 建立配置信息对象
        Configuration configuration = new Configuration();
        
        FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9000"),configuration, "gh");
        
        // 2 建立要上传文件所在的本地路径
        Path src = new Path("e:/hello.txt");
        
        // 3 建立要上传到hdfs的目标路径
        Path dst = new Path("hdfs://hadoop102:9000/user/gh/hello.txt");
        
        // 4 拷贝文件
        fs.copyFromLocalFile(src, dst);
        fs.close();    
}

3.2.3 HDFS文件下载

@Test
public void getFileFromHDFS() throws Exception{
        
    // 1 建立配置信息对象
    Configuration configuration = new Configuration();
        
    FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9000"),configuration, "gh");    
    
//    fs.copyToLocalFile(new Path("hdfs://hadoop102:9000/user/gh/hello.txt"), new Path("d:/hello.txt"));
    // boolean delSrc 指是否将原文件删除
    // Path src 指要下载的文件路径
    // Path dst 指将文件下载到的路径
    // boolean useRawLocalFileSystem 是否开启文件效验
    // 2 下载文件
    fs.copyToLocalFile(false, new Path("hdfs://hadoop102:9000/user/gh/hello.txt"), new Path("e:/hellocopy.txt"), true);
    fs.close();
}

3.2.4 HDFS目录建立

    @Test
    public void mkdirAtHDFS() throws Exception{
        // 1 建立配置信息对象
        Configuration configuration = new Configuration();
        
        FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9000"),configuration, "gh");    
        
        //2 建立目录
        fs.mkdirs(new Path("hdfs://hadoop102:9000/user/gh/output"));
    }

3.2.5 HDFS文件夹删除

    @Test
    public void deleteAtHDFS() throws Exception{
        // 1 建立配置信息对象
        Configuration configuration = new Configuration();
        
        FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9000"),configuration, "gh");    
        
        //2 删除文件夹 ,若是是非空文件夹,参数2必须给值true
        fs.delete(new Path("hdfs://hadoop102:9000/user/gh/output"), true);
    }

3.2.6 HDFS文件名更改

    @Test
    public void renameAtHDFS() throws Exception{
        // 1 建立配置信息对象
        Configuration configuration = new Configuration();
        
        FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9000"),configuration, "gh");
        
        //2 重命名文件或文件夹
        fs.rename(new Path("hdfs://hadoop102:9000/user/gh/hello.txt"), new Path("hdfs://hadoop102:9000/user/gh/hellonihao.txt"));
    }

3.2.7 HDFS文件详情查看

@Test
public void readListFiles() throws Exception {
    // 1 建立配置信息对象
    Configuration configuration = new Configuration();
        
    FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9000"),configuration, "gh");
        
    // 思考:为何返回迭代器,而不是List之类的容器
    RemoteIterator<LocatedFileStatus> listFiles = fs.listFiles(new Path("/"), true);

    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[] blockLocations = fileStatus.getBlockLocations();
            
        for (BlockLocation bl : blockLocations) {
                
            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文件夹查看

@Test
public void findAtHDFS() throws Exception, IllegalArgumentException, IOException{
        
    // 1 建立配置信息对象
    Configuration configuration = new Configuration();
        
    FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9000"),configuration, "gh");
        
    // 2 获取查询路径下的文件状态信息
    FileStatus[] listStatus = fs.listStatus(new Path("/"));

    // 3 遍历全部文件状态
    for (FileStatus status : listStatus) {
        if (status.isFile()) {
            System.out.println("f--" + status.getPath().getName());
        } else {
            System.out.println("d--" + status.getPath().getName());
        }
    }
}

3.3 经过IO流操做HDFS

3.3.1 HDFS文件上传

    @Test
    public void putFileToHDFS() throws Exception{
        // 1 建立配置信息对象
        Configuration configuration = new Configuration();
        
        FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9000"),configuration, "gh");
        
        // 2 建立输入流
        FileInputStream inStream = new FileInputStream(new File("e:/hello.txt"));
        
        // 3 获取输出路径
        String putFileName = "hdfs://hadoop102:9000/user/gh/hello1.txt";
        Path writePath = new Path(putFileName);

        // 4 建立输出流
        FSDataOutputStream outStream = fs.create(writePath);

        // 5 流对接
        try{
            IOUtils.copyBytes(inStream, outStream, 4096, false);
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            IOUtils.closeStream(inStream);
            IOUtils.closeStream(outStream);
        }
    }

3.3.2 HDFS文件下载

    @Test
    public void getFileToHDFS() throws Exception{
        // 1 建立配置信息对象
        Configuration configuration = new Configuration();
        
        FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9000"),configuration, "gh");
        
        // 2 获取读取文件路径
        String filename = "hdfs://hadoop102:9000/user/gh/hello1.txt";
        
        // 3 建立读取path
        Path readPath = new Path(filename);
        
        // 4 建立输入流
        FSDataInputStream inStream = fs.open(readPath);
        
        // 5 流对接输出到控制台
        try{
            IOUtils.copyBytes(inStream, System.out, 4096, false);
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            IOUtils.closeStream(inStream);
        }
    }

3.3.3 定位文件读取

1)下载第一块

@Test
// 定位下载第一块内容
public void readFileSeek1() throws Exception {

    // 1 建立配置信息对象
    Configuration configuration = new Configuration();

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

    // 2 获取输入流路径
    Path path = new Path("hdfs://hadoop102:9000/user/gh/tmp/hadoop.tar.gz");

    // 3 打开输入流
    FSDataInputStream fis = fs.open(path);

    // 4 建立输出流
    FileOutputStream fos = new FileOutputStream("e:/hadoop.tar.gz.part1");

    // 5 流对接
    byte[] buf = new byte[1024];
    for (int i = 0; i < 128 * 1024; i++) {
        fis.read(buf);
        fos.write(buf);
    }

    // 6 关闭流
    IOUtils.closeStream(fis);
    IOUtils.closeStream(fos);
    }

2)下载第二块

    @Test
    // 定位下载第二块内容
    public void readFileSeek2() throws Exception{
        
        // 1 建立配置信息对象
        Configuration configuration = new Configuration();

        FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:9000"), configuration, "gh");
        
        // 2 获取输入流路径
        Path path = new Path("hdfs://hadoop102:9000/user/gh/tmp/hadoop.tar.gz");
        
        // 3 打开输入流
        FSDataInputStream fis = fs.open(path);
        
        // 4 建立输出流
        FileOutputStream fos = new FileOutputStream("e:/hadoop.tar.gz.part2");
        
        // 5 定位偏移量(第二块的首位)
        fis.seek(1024 * 1024 * 128);
        
        // 6 流对接
        IOUtils.copyBytes(fis, fos, 1024);
        
        // 7 关闭流
        IOUtils.closeStream(fis);
        IOUtils.closeStream(fos);
    }

3)合并文件

    在window命令窗口中执行

    type hadoop.tar.gz.part2 >> hadoop.tar.gz.part1

四。HDFS的数据流

4.1 HDFS写数据流程

4.1.1 剖析文件写入

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

2)namenode返回是否能够上传。

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

4)namenode返回3个datanode节点,分别为dn一、dn二、dn3。

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

6)dn一、dn二、dn3逐级应答客户端

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

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

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.3/hadoop-project-dist/hadoop-common/RackAwareness.html

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

2)低版本Hadoop1.x副本节点选择

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

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

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

3)Hadoop2.x副本节点选择

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

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

       第三个副本位于不一样机架,随机节点。

4.2 HDFS读数据流程

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

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

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

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

4.3 一致性模型

1)debug调试以下代码

@Test
    public void writeFile() throws Exception{
        // 1 建立配置信息对象
        Configuration configuration = new Configuration();
        fs = FileSystem.get(configuration);
        
        // 2 建立文件输出流
        Path path = new Path("hdfs://hadoop102:9000/user/gh/hello.txt");
        FSDataOutputStream fos = fs.create(path);
        
        // 3 写数据
        fos.write("hello".getBytes());
        // 4 一致性刷新
        fos.hflush();
        
        fos.close();
    }

2)总结

        写入数据时,若是但愿数据被其余client当即可见,调用以下方法

        FsDataOutputStream. hflush ();           //清理客户端缓冲区数据,被其余client当即可见

五。NameNode工做机制

 5.1 NameNode&Secondary NameNode工做机制

1)第一阶段:namenode启动

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

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

        (3)namenode记录操做日志,更新滚动日志。

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

2)第二阶段:Secondary NameNode工做

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

       (2)Secondary NameNode请求执行checkpoint。

       (3)namenode滚动正在写的edits日志

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

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

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

       (7)拷贝fsimage.chkpoint到namenode

       (8)namenode将fsimage.chkpoint从新命名成fsimage

4)chkpoint检查时间参数设置

        (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被格式化以后,将在设置的存放目录 ---name/current目录中产生以下文件(hdfs-site.xml里面设置存放目录)

edits_0000000000000000000
fsimage_0000000000000000000.md5
seen_txid
VERSION

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

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

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

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

2)oiv查看fsimage文件

    (1)查看oiv和oev命令

       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)案例

         将显示的xml文件内容拷贝到idea或者eclipse中,并格式化。

3)oev查看edits文件

    (1)基本语法

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

   (2)案例

     将显示的xml文件内容拷贝到idea或者eclipse中,并格式化。

5.3 滚动编辑日志

    正常状况HDFS文件系统有更新操做时,就会滚动编辑日志。也能够用命令强制滚动编辑日志。

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

    hdfs dfsadmin -rollEdits

    2)镜像文件何时产生

    Namenode启动时加载镜像文件

5.4 namenode版本号

1)查看namenode版本号

    在----/name/current这个目录下查看VERSION

2)namenode版本号具体解释

    (1)namespaceID在HDFS上,会有多个Namenode,因此不一样Namenode的namespaceID是不一样的,分别管理一组blockpoolID。

    (2)clusterID集群id,全局惟一

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

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

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

    (6)layoutVersion是一个负整数。一般只有HDFS增长新特性时才会更新这个版本号。

5.5 SecondaryNameNode目录结构

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

     在----/namesecondary/current这个目录中查看SecondaryNameNode目录结构。

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

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

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

    方法二:使用-importCheckpoint选项启动namenode守护进程,从而将SecondaryNameNode用做新的主namenode。

1)案例(一):

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

    (1)kill -9 namenode进程

    (2)删除namenode存储的数据

 

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

 

    (4)从新启动namenode

    能够查看到原来的数据被还原了

    2)案例(二):

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

    首先须要在hdfs-site.xml中加入nameNode的存储路径。

    <property>
          <name>dfs.namenode.name.dir</name>
          <value>/data/hadoop/tmp/dfs/name</value>
    </property>

  (1)kill -9 namenode进程

  (2)删除namenode存储的数据

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

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

  (5)启动namenode

  (6)若是提示文件锁了,能够删除SecondaryNameNode存储目录里面的 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        (功能描述:查看安全模式状态)

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

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

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

3)案例

  模拟等待安全模式

  1)先进入安全模式

  2)执行下面的命令

  3)在另外一个窗口中对hdfs进行写操做

  4)离开安全模式

5.7 Namenode多目录配置

1)namenode的本地目录能够配置成多个,且每一个目录存放内容相同,增长了可靠性。

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>

六。DataNode工做机制

6.1 DataNode工做机制

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

  2)DataNode启动后向namenode注册,经过后,周期性(1小时)的向namenode上报全部的块信息。

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

  4)集群运行中能够安全加入和退出一些机器

6.2 数据完整性

1)当DataNode读取block的时候,它会计算checksum

2)若是计算后的checksum,与block建立时值不同,说明block已经损坏。

3)client读取其余DataNode上的block.

4)datanode在其文件建立后周期验证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)在----/tmp/dfs/data/current这个目录下查看版本号

  2)具体解释

         (1)storageID:存储id号

         (2)clusterID集群id,全局惟一

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

         (4)datanodeUuid:datanode的惟一识别码

         (5)storageType:存储类型

         (6)layoutVersion是一个负整数。一般只有HDFS增长新特性时才会更新这个版本号。

  3)在-----tmp/dfs/data/current/BP-639183006-10.20.0.130-1555500554508/current这个目录下查看该数据块的版本号

 

  4)具体解释

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

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

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

  (4)layoutVersion是一个负整数。一般只有HDFS增长新特性时才会更新这个版本号。

6.5 服役新数据节点

0)需求:

  在原有集群基础上动态添加新的数据节点。

  略

6.6 退役旧数据节点

  在原有集群基础上动态删除旧的数据节点。

  略

6.7 Datanode多目录配置

1)datanode也能够配置成多个目录,每一个目录存储的数据不同。即:数据不是副本。

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 集群间数据拷贝

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

       scp -r hello.txt root@hadoop103:/hello.txt             // 推 push

       scp -r root@hadoop103:/hello.txt  hello.txt           // 拉 pull

       scp -r root@hadoop103:/hello.txt root@hadoop104:/   //是经过本地主机中转实现两个远程主机的文件复制;若是在两个远程主机之间ssh没有配置的状况下可使用该方式。

2)采用discp命令实现两个hadoop集群之间的递归数据复制

  hadoop distcp hdfs://haoop102:9000/hello.txt hdfs://hadoop103:9000/hello.txt

7.2 Hadoop存档

1)理论概述

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

  Hadoop存档文件或HAR文件,是一个更高效的文件存档工具,它将文件存入HDFS块,在减小namenode内存使用的同时,容许对文件进行透明的访问。具体说来,Hadoop存档文件能够用做MapReduce的输入。

2)案例

(1)须要启动yarn进程

       start-yarn.sh

(2)归档文件

       归档成一个叫作xxx.har的文件夹,该文件夹下有相应的数据文件。Xx.har目录是一个总体,该目录当作是一个归档文件便可。

[root@master001 dfs]# hadoop archive -archiveName myhar.har -p /hdfsApi /my

3)查看归档

4)解归档文件

[root@master001 dfs]# hadoop fs -cp har:///my/myhar.har/* /ghh

7.3 快照管理

  快照至关于对目录作一个备份。并不会当即复制全部文件,而是指向同一个文件。当写入发生时,才会产生新文件。

1)基本语法

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

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

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

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

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

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

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

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

2)案例

  略

7.4 回收站

八。HDFS HA高可用

相关文章
相关标签/搜索