Hadoop 基础之 HDFS 入门

5,240 阅读4分钟

前言

本文主要介绍了 HDFS 的体系架构以及其执行流程,并给出了读写操作的编程实例,希望对 HDFS 有个初步的认识。

简介

HDFS (Hadoop Distributed File System) 是一个运行在商业 PC 上的分布式文件系统,其设计思想源自于 Google 2003 年发布的论文 The Google File System 。HDFS的主要目的是为了解决大规模数据存储和管理的问题。

体系架构

上图表明 HDFS 是一个标准的 master/slave 架构,主要由三个部分构成:

  1. NameNode(master 节点)
    • 元数据(MetaData)的管理,其中元数据由文件路径名数据块ID以及存储位置等信息构成
    • 管理 HDFS 的名字空间。
  2. SecondaryNameNode
    • 定期合并 NameNode 的 edit logs(对文件系统的改动序列) 到 fsimage(对整个文件系统的快照),并拷贝修改后的 fsimage 到 NameNode。
    • 提供一个 NameNode 的检查点(切忌认为是 NameNode 的备份),可用于 NameNode 的故障恢复。
  3. DataNode(slave 节点)
    • 提供文件存储和进行数据块操作。
    • 周期性的向 NameNode 汇报块信息。

这里对图中出现的一些概念进行说明:

  1. Replication(副本)

    为了保证数据的高可用,HDFS 会对写入的数据进行冗余存储,默认情况下会保存 3 份。

  2. Blocks

    Block 是最基本的存储和操作单位(默认情况下为 128M),这里的 Block 不是指物理 Block ,而是指文件系统的 Block,其大小一般是物理 Block 的整数倍。

执行流程

读文件

读文件的过程可以概括为:

  1. Client 向 NameNode 发起请求获取文件数据块位置信息
  2. Client 按照数据块距 Client 的远近依次进行连接然后读取数据

写文件

写文件的过程可以概括为:

  1. Client 向 NameNode 发起写文件的请求获得可写的 DataNode 列表等信息
  2. Client 根据 HDFS 设定的分块大小对文件进行分块
  3. Client 和 NameNode 分配的 DataNode 构成 pipeline 并进行数据写入
  4. 写入完成之后,NameNode 接收来自 DataNode 的消息进行元数据的更新

常用命令

文件操作

  1. 列出文件

    hdfs dfs -ls <path>
    
  2. 创建目录

    hdfs dfs -mkdir <path>
    
  3. 上传文件

    hdfs dfs -put <localsrc> <dst>
    
  4. 输出文件内容

    hdfs dfs -cat <src>
    
  5. 文件复制到本地

    hdfs dfs -get <src> <localdst>
    
  6. 删除文件和目录

    hdfs dfs -rm <src>
    hdfs dfs -rmdir <dir>
    

管理

  1. 查看统计信息

    hdfs dfsadmin -report
    
  2. 进入和退出安全模式(该模式不允许文件系统有任何修改)

    hdfs dfsadmin -safemode enter
    hdfs dfsadmin -safemode leave
    

编程实例

  1. IDEA 新建 Maven 项目

    在这里插入图片描述

    勾选相关选项后,点击 next 填入项目相关信息即可

  2. pom.xml 中添加依赖

    <dependencies>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-common</artifactId>
            <version>2.9.2</version> //根据 Hadoop 版本进行选择
        </dependency>
    
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-hdfs</artifactId>
            <version>2.9.2</version>
        </dependency>
    
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client</artifactId>
            <version>2.9.2</version>
        </dependency>
    </dependencies>
    
    
  3. 读写文件

    创建 Sample 类编写相应的读写函数

    • Sample 类

      import org.apache.hadoop.conf.Configuration;
      import org.apache.hadoop.fs.FSDataInputStream;
      import org.apache.hadoop.fs.FSDataOutputStream;
      import org.apache.hadoop.fs.FileSystem;
      import org.apache.hadoop.fs.Path;
      
      import java.io.*;
      
      /**
       * @author ikroal
       */
      public class Sample {
          //默认的 HDFS 地址
          private static final String DEFAULT_FS = "hdfs://localhost:9000";
          private static final String PATH = DEFAULT_FS + "/tmp/demo.txt";
          private static final String DEFAULT_FILE = "demo.txt";
      
          public static void main(String[] args) {
              Configuration conf = new Configuration();
              FileSystem fs = null;
              conf.set("fs.defaultFS", DEFAULT_FS); //配置 HDFS 地址
      
              try {
                  fs = FileSystem.get(conf);
                  write(fs, DEFAULT_FILE, PATH);
                  read(fs, PATH);
              } catch (IOException e) {
                  e.printStackTrace();
              } finally {
                  try {
                      if (fs != null) {
                          fs.close();
                      }
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
              }
          }
      }
      
    • write 函数

      /**
      * 进行文件写入
      * @param inputPath 待写入文件路径
      * @param outPath HDFS 的写入路径
      */
      public static void write(FileSystem fileSystem, String inputPath, String outPath) {
          FSDataOutputStream outputStream = null;
          FileInputStream inputStream = null;
          try {
              outputStream = fileSystem.create(new Path(outPath)); //获得 HDFS 的写入流
              inputStream = new FileInputStream(inputPath); //读取本地文件
              int data;
              while ((data = inputStream.read()) != -1) { //写入操作
                  outputStream.write(data);
              }
          } catch (IOException e) {
              e.printStackTrace();
          } finally {
              try {
                  if (outputStream != null) {
                      outputStream.close();
                  }
                  if (inputStream != null) {
                      inputStream.close();
                  }
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      }
      
    • read 函数

      /**
      * 进行文件读取
      * @param path HDFS 上待读取文件路径
      */
      public static void read(FileSystem fileSystem, String path) {
          FSDataInputStream inputStream = null;
          BufferedReader reader = null;
          try {
              inputStream = fileSystem.open(new Path(path)); //获取 HDFS 读取流
              reader = new BufferedReader(new InputStreamReader(inputStream));
              String content;
              while ((content = reader.readLine()) != null) { //读取并输出到控制台
                  System.out.println(content);
              }
          } catch (IOException e) {
              e.printStackTrace();
          } finally {
              try {
                  if (inputStream != null) {
                      inputStream.close();
                  }
                  if (reader != null) {
                      reader.close();
                  }
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      }
      
  4. 在工程文件夹的根目录下创建计划上传的文件(这里是 demo.txt),填入 Hello World!

  5. 启动 Hadoop 然后运行程序查看结果

    通过 http://localhost:50070/explorer.html#/ 可以查看写入结果

    控制台则会输出上传文件的内容

Thanks

  1. 初步掌握HDFS的架构及原理
  2. 深入理解HDFS:Hadoop分布式文件系统
  3. HDFS读写流程(史上最精炼详细)
  4. Hadoop学习之路(十一)HDFS的读写详解