浅谈HDFS的文件读取与写入

HDFS文件读取:

  • 数据读取的步骤:
  1. 客户端通过FileSystem对象(抽象类,一般通过这个来调用方法),open()方法打开需要读取的文件,HDFS中用DistributedFileSystem实现FileSystem的open()方法,通过远程调用(RPC)调用namenode,namenode告诉它存放该块复本的datanode地址
  2. datanode通过网络拓扑找到距离客户端最近的datanode并排序
  3. open()方法返回一个FSDataInputStream对象,客户端对FSDataInputStream的read()用来找到对应的最佳datanode,通过反复调用read()将结果告诉给客户端,到达块的末端时断开datanode之间的连接,再去找下一块的最佳datanode
  4. 最后,客户端调用FSDataInputStream close()完成数据读取
  • 客户端读取HDFS文件系统中的数据图:
    在这里插入图片描述
  • 用API写个简单的文件读取例子
    @Test
    public void openTest() throws Exception {
        FSDataInputStream in = fileSystem.open(new Path("/hdfsapi/test/aa.txt"));
        //讲读出的数据输出到控制台上
        IOUtils.copyBytes(in,System.out,1024);
        //关闭数据流
        IOUtils.closeStream(in);
    }

Hadoop中的网络距离:

默认情况下,所有节点再同一数据中心的同一机架上。
图中数据中心是date center,机架是rack,节点是node,d代表两结点之间的网络距离。

1)同一节点上的进程: d(/dc1/rack1/node1 , /dc1/rack1/node1) = 0
2)同一机架上的不同节点: d(/dc1/rack1/node1 , /dc1/rack1/node2) = 2
3)同一数据中心的不同机架上的节点: d(/dc1/rack1/node1 , /dc1/rack2/node3) = 4
4)不同数据中心的节点: d(/dc1/rack1/node1 , /dc2/rack3/node4) = 6
在这里插入图片描述

  • 读取数据过程出现错误的处理:
    如果在读取数据过程中DFSInputStream(封装的FSDataInputStream,负责namenode和datanode之间的通信)与datanode通信时遇到错误,会从这个块的另一个最邻近datanode读取数据,同时记住故障datanode。DFSInputStream会是试图从其他datanode读取其复本,也将损坏块通知给namenode。

文件写入

  • 数据写入的步骤:
  1. 客户端通过FileSystem对象(抽象类),DistributedFileSystem对象实现的create()方法新建文件,新建文件时需要确认客户端有权限以及文件是否已经存在,如果存在就会返回IOException异常
  2. 创建文件成功后返回FSDataOutputStream对象,客户端通过调用write()向datanode执行写入操作,连接DataNode时DFSOutputStream(FSDataOutputStream封装后,负责namenode和datanode之间的通信)。把数据分为一个个数据包并写入内部队列,叫“数据队列”(data queue),这一步由DataStreamer完成,它还负责选出合适存储数据复本的一组datanode,并告诉namenode分配所需的新的数据块
  3. 假设复本系数为3,则一个管线中有三个节点,DataStreamer将数据包流式传输到管线中第一个datanode,datanode存储数据包并将它发送到管线中的第二个datanode,按照同样的方法发送到最后一个datanode中
  4. 最后一个datanode再向前一个datanode发送确认回执,叫“确认队列”(ack queue)并讲确认队列返回给DFSOutputStream,直至收到所有datanode确认回执
  5. 客户端调用FSDataInputStream close(),完成数据写入
  6. 再完成数据写入前,namenode需要确认(complete)文件写入已完成,等待数据块最小量的复制
    在这里插入图片描述
  • 文件写入的例子
@Test
    public void outputTest() throws Exception {
        InputStream input = new BufferedInputStream(new FileInputStream(new File("E:\\ComputerQQDownload\\jdk-8u192-linux-x64.tar.gz")));

        FSDataOutputStream out = fileSystem.create(new Path("/hdfsapi/test/jdk.tgz"), new Progressable() {
            @Override
            public void progress() {
                System.out.print(">");
            }
        });

        IOUtils.copyBytes(input, out, 4096);
        out.close();
        input.close();
    }

复本怎么存

  • 第一个复本时随机的存放再机架上的某一个节点
  • 第二个复本是存放在同一数据中心的不同机架上的某一节点上,这个过程叫离架
  • 第三个复本与第二个存放在同一机架上的某一节点上
    在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_40311709/article/details/89415260