Hadoop从入门到进阶 HDFS常用命令&&JAVA整合HDFS&&HDFS核心流程(二)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_34125999/article/details/102763125

1 常用的客户端命令

1.1、上传文件

cd /usr/local/hadoop-2.8.5/bin
#把jdk上传到hadoop根目录,hdfs默认按128M切割数据并且存3副本,可以进入datanode存数据的地方查看当前文件切割
./hadoop fs -put /usr/local/jdk-8u144-linux-x64.tar.gz /

#如果想要修改备份文件数量和切文件的大小
cd /usr/local/hadoop-2.8.5/etc/hadoop
vim hdfs-site.xml
<property>
    <name>dfs.blocksize</name>
    <value>64m</value>
</property>
<property>
    <name>dfs.replication</name>
    <value>2</value>
</property>

在这里插入图片描述
在这里插入图片描述

1.2、查看文件

#查找文件
./hadoop fs -ls /
#查看文件大小
./hadoop fs -du -s -h  /jdk-8u144-linux-x64.tar.gz

在这里插入图片描述

1.3、取文件

./hadoop fs -get /jdk-8u144-linux-x64.tar.gz /usr/local/

在这里插入图片描述

2 windows环境配置

2.1 不配置报错

java.io.FileNotFoundException: java.io.FileNotFoundException: HADOOP_HOME and hadoop.home.dir are unset. -see https://wiki.apache.org/hadoop/WindowsProblems
        at org.apache.hadoop.util.Shell.fileNotFoundException(Shell.java:528) ~[hadoop-common-2.8.4.jar:na]
        at org.apache.hadoop.util.Shell.getHadoopHomeDir(Shell.java:549) ~[hadoop-common-2.8.4.jar:na]
        at org.apache.hadoop.util.Shell.getQualifiedBin(Shell.java:572) ~[hadoop-common-2.8.4.jar:na]
        at org.apache.hadoop.util.Shell.<clinit>(Shell.java:669) ~[hadoop-common-2.8.4.jar:na]
        at org.apache.hadoop.util.StringUtils.<clinit>(StringUtils.java:79) [hadoop-common-2.8.4.jar:na]

2.2 下载windows的hadoop

在这里插入图片描述

2.3 环境变量

在这里插入图片描述

2.4 编辑PATH

在这里插入图片描述

2.5、重启Ecplice或IDEA

3 JAVA 整合HDFS

3.1 pom文件

<!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-common -->
<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-common</artifactId>
    <version>2.8.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-hdfs -->
<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-hdfs</artifactId>
    <version>2.8.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-hdfs-client -->
<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-hdfs-client</artifactId>
    <version>2.8.5</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.6</version>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.8.1</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>

3.2 常用API

#配置文件官网
https://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-hdfs/hdfs-default.xml
public class HdfsClientDemo {
    Configuration conf = null;
    FileSystem fs = null;
    @Before
    public void hdfsInitial() throws Exception {
        //1、创建hdfs的配置文件
        conf = new Configuration();
        // 指定本客户端上传文件到hdfs时需要保存的副本数为:2
        conf.set("dfs.replication", "2");
        // 指定本客户端上传文件到hdfs时切块的规格大小:64M
        conf.set("dfs.blocksize", "64m");
        //2、创建客户端,namenodeurl,配置文件,身份
        fs = FileSystem.get(new URI("hdfs://192.168.0.38:9000"), conf, "root");
    }
    /**
     * 测试上上传文件
     */
    @Test
    public void testUpload() {
        try {
            fs.copyFromLocalFile(new Path("F:\\linux_tar\\hbase\\hbase-1.2.1-bin.tar.gz"), new Path("/hbase/"));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fs != null) {
                try {
                    fs.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    /**
     * 在hdfs中创建文件夹
     */
    @Test
    public void testMkdir() {
        try {
            fs.mkdirs(new Path("/test"));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fs != null) {
                try {
                    fs.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    /**
     * 从HDFS中下载文件到客户端本地磁盘
     */
    @Test
    public void testGet() {
        try {
            fs.copyToLocalFile(new Path("/test"), new Path("f:/"));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fs != null) {
                try {
                    fs.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    /**
     * 查询hdfs指定目录下的文件信息
     */
    @Test
    public void testLs() {
        // 只查询文件的信息,不返回文件夹的信息
        RemoteIterator<LocatedFileStatus> iter = null;
        try {
            iter = fs.listFiles(new Path("/"), true);
            while (iter.hasNext()) {
                LocatedFileStatus status = iter.next();
                System.out.println("文件全路径:" + status.getPath());
                System.out.println("块大小:" + status.getBlockSize());
                System.out.println("文件长度:" + status.getLen());
                System.out.println("副本数量:" + status.getReplication());
                System.out.println("块信息:" + Arrays.toString(status.getBlockLocations()));
                System.out.println("--------------------------------");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fs != null) {
                try {
                    fs.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    /**
     * 在hdfs中删除文件或文件夹
     */
    @Test
    public void testRm() {
        try {
            fs.delete(new Path("/jdk-8u144-linux-x64.tar.gz"), true);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fs != null) {
                try {
                    fs.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    /**
     * 查询hdfs指定目录下的文件和文件夹信息
     */
    @Test
    public void testSelect() {
        try {
            FileStatus[] listStatus = fs.listStatus(new Path("/"));
            for (FileStatus status : listStatus) {
                System.out.println("文件全路径:" + status.getPath());
                System.out.println(status.isDirectory() ? "这是文件夹" : "这是文件");
                System.out.println("块大小:" + status.getBlockSize());
                System.out.println("文件长度:" + status.getLen());
                System.out.println("副本数量:" + status.getReplication());
                System.out.println("--------------------------------");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fs != null) {
                try {
                    fs.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

4 HDFS元数据管理机制

fsimage 镜像文件:是元数据的一个持久化的检查点,包含 Hadoop 文件系统中的所有目录和文件元数据信息,但不包含文件块位置的信息。文件块位置信息只存储在内存中,是在 datanode 加入集群的时候,namenode 询问 datanode 得到的,并且间断的更新。

Edits 编辑日志:存放的是 Hadoop 文件系统的所有更改操作(文件创建,删除或修改)的日志,文件系统客户端执行的更改操作首先会被记录到 edits 文件中。

fsimage 和 edits 文件都是经过序列化的,在 NameNode 启动的时候,它会将 fsimage文件中的内容加载到内存中,之后再执行 edits 文件中的各项操作,使得内存中的元数据和实际的同步,存在内存中的元数据支持客户端的读操作,也是最完整的元数据。

secondary namenode:SecondNamenode其实只是一个简单的元数据备份进程,它会定期(缺省是1小时)把edits文件的内容合并到fsimage文件,同时保存最新的元数据副本在SecondNamenode进程所在机器的文件系统里。

checkpoint : 会定期从namenode上下载fsimage镜像和新生成的edits日志,然后加载fsimage镜像到内存中,然后顺序解析edits文件,对内存中的元数据对象进行修改(整合)
整合完成后,将内存元数据序列化成一个新的fsimage,并将这个fsimage镜像文件上传给namenode。(checkpoint第一次需要下载fsimage,以后就不需要了)

vim hdfs-site.xml
<!--这两个条件任何一个被满足了,就触发一次检查点创建。-->
<!--1小时-->
<property>
  <name>dfs.namenode.checkpoint.period</name>
  <value>3600</value>
</property>

<!--操作100w次-->
<property>
    <name>dfs.namenode.checkpoint.txns</name>
    <value>1000000</value>
</property>

<!--默认1分钟检查一次是否触发checkpoint条件-->
<property>
    <name>dfs.namenode.checkpoint.check.period</name>
    <value>60</value>
</property>

5 读写数据流程

5.1 写数据流程

1)客户端请求namnenode,写文件目录+文件。
2)name判断当前目录是否存在,如果存在告知可写,如果不存在抛出异常。
3)客户端请求namenode写入BLOCK。
4)namenode返回3个datanode(几个备份就返回几个datanode,假如d1,d2,d3)。
5)挑选最近的datanode建立传输数据的链接(d1),d1会请求d2(建立数据链接),d2会请求d3(建立数据链接),最终返回给客户端数据链接建立成功。
6)客户端通过流把数据传输给d1,d1一边进行数据写出一边把数据传给d2,d2会一边把数据写入一边把数据传给d3。
7)传第二个BLOCK

5.2 读数据流程

1)客户端请求namenode
2)namenode返回元数据信息(例如d1,d2,d3)
3)客户端选择最近的datanode建立连接,读取文件。

猜你喜欢

转载自blog.csdn.net/qq_34125999/article/details/102763125
今日推荐