Hadoop权威指南_读书笔记_第3章 Hadoop分布式文件系统(下) HDFS的读取与写入流程[面试重点]

HDFS的读取与写入流程 [面试重点]

一、HDFS的读取流程

  • 1.先上一段简单代码,使用FileSystem读取HDFS文件

    // cc FileSystemDoubleCat Displays files from a Hadoop filesystem on standard output twice, by using seek
    import java.net.URI;
    
    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.fs.FSDataInputStream;
    import org.apache.hadoop.fs.FileSystem;
    import org.apache.hadoop.fs.Path;
    import org.apache.hadoop.io.IOUtils;
    
    // vv FileSystemDoubleCat
    public class FileSystemDoubleCat {
    
      public static void main(String[] args) throws Exception {
        String uri = args[0];
        
        //Configuration对象封装了客户端或服务器的配置,通过设置配置文件读取类路径来实现
        Configuration conf = new Configuration();
        
        //FileSystem是hadoop通用的文件系统api
        FileSystem fs = FileSystem.get(URI.create(uri), conf);
        FSDataInputStream in = null;
        try {
          //有了FileSystem实例后,通过调用open()方法获取文件的输入流
    	  //open()方法返回的是FSDataInputStream对象,不是标准的java.io类对象
          in = fs.呢个(new Path(uri));
          IOUtils.copyBytes(in, System.out, 4096, false);
          in.seek(0); // go back to the start of the file
          IOUtils.copyBytes(in, System.out, 4096, false);
        } finally {
          IOUtils.closeStream(in);
        }
      }
    }
    // ^^ FileSystemDoubleCat
    
  • 2. 客户端读取HDFS文件流程图如下:
    在这里插入图片描述

  • 3. 客户端读取HDFS文件流程详解

    • 客户端调用 FileSystem 对象的open() 方法 打开要读取的文件。对于HDFS来说,这个对象是DistributedFileSystem的一个实例(图中的步骤1)。
    • ②DistributedFileSystem 通过远程RPC请求调用namenode确定文件起始块的位置(步骤2) 对于每一个块,namenode返回存有该块的副本信息(datanode地址)。
    • ③DistributedFileSystem类返回一个FSDataInputStream对象(一个支持定位的输入流),给客户端读取数据。FSDataInputStream类封装了DFSInputStream对象,客户端对这个输入流调用read( )方法 (步骤3)。
    • DFSInputStream连接距离最近的文件中的第一个datanode。通过对数据流反复调用read()方法,将数据从datanode传输到客户端(步骤4)。
    • 到达块的末端时,DFSInputStream关闭与该datanode的连接,然后寻找下一个块的最佳datanode(步骤5) (注:一个文件比如200M 会分成两个块128M 和 62M,两个文件一般不会在同一个datanode上面存储,当读取完一个块的数据文件时,就要去读取另一个文件块的datanode)
    • ⑥一旦客户端完成读取所有数据,就对FSDataInputStream()调用close()方法(步骤6)
  • 4.网络拓扑

    • 两个节点"彼此近邻" 是什么意思?DFSInputStream连接距离最近的datanode,最近距离是怎么定义的?

    • 在海量数据处理中,主要限制因素是节点之间数据的传输速率——带宽很稀缺。这里将两个节点之间的带宽作为距离的衡量标准。 hadoop采用一个简单的方法:把网络看成一棵树,两个节点之间的距离 是 它们到最近共同祖先的距离总和

    • 针对以下场景,可用带宽依次减少:

      • 同一节点上面的进程
      • 同一机架上的不同节点
      • 同一数据中心不同机架
      • 不同数据中心的节点

      假如有数据中心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/r2/n3) = 4(同一数据中心不同机架)
      • distance(/d1/r1/n1, /d2/r3/n4) = 6(不同数据中心的节点)
        在这里插入图片描述
        在这里插入图片描述

二、HDFS的写入流程

  • 1.先上代码,将本地文件复制到Hadoop文件系统
    // cc FileCopyWithProgress Copies a local file to a Hadoop filesystem, and shows progress
    import java.io.BufferedInputStream;
    import java.io.FileInputStream;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.URI;
    
    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.fs.FileSystem;
    import org.apache.hadoop.fs.Path;
    import org.apache.hadoop.io.IOUtils;
    import org.apache.hadoop.util.Progressable;
    
    // vv FileCopyWithProgress
    public class FileCopyWithProgress {
      public static void main(String[] args) throws Exception {
        String localSrc = args[0];
        String dst = args[1];
        
        InputStream in = new BufferedInputStream(new FileInputStream(localSrc));
        
        Configuration conf = new Configuration();
        FileSystem fs = FileSystem.get(URI.create(dst), conf);
        //create()方法返回FSDataOutputStream
        OutputStream out = fs.create(new Path(dst), new Progressable() {
          public void progress() {
            System.out.print(".");
          }
        });
        
        IOUtils.copyBytes(in, out, 4096, true);
      }
    }
    // ^^ FileCopyWithProgress
    
  • 2.客户端将数据写入HDFS流程图
    客户端将数据写入HDFS
  • 客户端将数据写入HDFS流程图
    • ① 客户端通过对DistributedFileSystem 对象调用create()新建文件(步骤1)。

    • DistributedFileSystemnamenode 创建一个RPC调用,在文件的命名空间创建一个新文件,此时文件中还没有相应的数据块(步骤2)。namenode 会执行各种不同的检查,确保这个文件是不存在的以及客户端有新建该文件的权限。检查通过后,namenode 就会为新文件记录一条记录。

    • ③ DistributedFileSystem 向客户端返回一个FSDataOutputStream对象。由此客户端就可以开始写数据(步骤3)。FSDataOutputStream封装了DFSoutPutstream对象,负责处理处理datanode和namenode之间的通信。

    • ④ 客户端写入数据时,DFSOutPutStream 将数据分成一个个的数据包packet,并写入内部队列(数据队列 data queue)。DataStreamer处理数据队列,负责挑选合适存储副本的一组datanode并据此要求namenode分配新的数据块。这一组datanode构成一个管线pipeline(假设副本数为3),所以pipeline中有3个节点。 DataStreamer将数据包packet 通过pipeline中的第1个datanode,然后第1个datanode存储改数据包packet后,以同样的方式发给第2个datanode,第2个再发给第3个(步骤4)。

    • ⑤ DFSOutPutStream也维护这一个**“确认队列”(ack queue),来等待datanode的收到确认回执**。收到管道pipeline中所有的datanode确认消息后,该数据包才会从确认队列删除(步骤5)。

    • ⑥ 客户端完成数据的写入后,对数据流调用close()方法(步骤6)。

    • ⑦ close()方法会将剩余的所有数据写入datanode的线管pipeline中,并告知namenode其文件写入完成之前,等待确认(步骤7)。namenode已经知道文件由哪些块组成(因为Datastreamer 请求分配数据块),所以namenode在返回成功前只需要等待数据块进行最小量的复制。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值