【大数据存储与管理】分布式文件系统HDFS:06 HDFS的数据读写过程

【大数据存储与管理】分布式文件系统HDFS:06 HDFS的数据读写过程

【作者主页】Francek Chen
【专栏介绍】 ⌈ ⌈ ⌈大数据技术原理与应用 ⌋ ⌋ ⌋专栏系统介绍大数据的相关知识,分为大数据基础篇、大数据存储与管理篇、大数据处理与分析篇、大数据应用篇。内容包含大数据概述、大数据处理架构Hadoop、分布式文件系统HDFS、分布式数据库HBase、NoSQL数据库、云数据库、MapReduce、Hadoop再探讨、数据仓库Hive、Spark、流计算、Flink、图计算、数据可视化,以及大数据在互联网领域、生物医学领域的应用和大数据的其他应用。
【GitCode】专栏资源保存在我的GitCode仓库:https://gitcode.com/Morse_Chen/BigData_principle_application

文章目录


在介绍 HDFS 的数据读写过程之前,需要简单介绍一下相关的类。FileSystem 是一个通用文件系统的抽象基类,可以被分布式文件系统继承,所有可能使用 Hadoop 文件系统的代码都要使用到这个类。Hadoop 为 FileSystem 这个抽象类提供了多种具体的实现,DistributedFileSystem 就是 FileSystem 在 HDFS 中的实现。FileSystem 的 open()方法返回的是一个输入流 FSDataInputStream 对象,在 HDFS 中具体的输入流就是 DFSInputStream;FileSystem 中的 create()方法返回的是一个输出流 FSDataOutputStream 对象,在 HDFS 中具体的输出流就是 DFSOutputStream。

一、读数据的过程

importjava.io.BufferedReader;importjava.io.InputStreamReader;importorg.apache.hadoop.conf.Configuration;importorg.apache.hadoop.fs.FSDataInputStream;importorg.apache.hadoop.fs.FileSystem;importorg.apache.hadoop.fs.Path;publicclassChapter3{publicstaticvoidmain(String[] args){try{Configuration conf =newConfiguration(); conf.set("fs.defaultFS","hdfs://localhost:9000"); conf.set("fs.hdfs.impl","org.apache.hadoop.hdfs.DistributedFileSystem");FileSystem fs =FileSystem.get(conf);Path file =newPath("test");FSDataInputStream getIt = fs.open(file);BufferedReader d =newBufferedReader(newInputStreamReader(getIt));String content = d.readLine();// 读取文件一行System.out.println(content); d.close();// 关闭文件 fs.close();// 关闭hdfs}catch(Exception e){ e.printStackTrace();}}}
Configuration conf =newConfiguration(); conf.set("fs.defaultFS","hdfs://localhost:9000"); conf.set("fs.hdfs.impl","org.apache.hadoop.hdfs.DistributedFileSystem");FileSystem fs =FileSystem.get(conf);FSDataInputStream in = fs.open(newPath(uri));FSDataOutputStream out = fs.create(newPath(uri));

客户端连续调用 open()、read()、close()读取数据时,HDFS 内部的执行过程如下图1。

在这里插入图片描述

图1 HDFS读数据的过程

  1. 客户端通过 FileSystem.open() 打开文件,相应地,在 HDFS 中 DistributedFileSystem 具体实现了 FileSystem。因此,调用 open() 方法后,DistributedFileSystem 会创建输入流 FSData InputStream,对于 HDFS 而言,具体的输入流就是 DFSInputStream。
  2. 在 DFSInputStream 的构造函数中,输入流通过 ClientProtocal.getBlockLocations() 远程调用名称节点,获得文件开始部分数据块的保存位置。对于该数据块,名称节点返回保存该数据块的所有数据节点的地址,同时根据距离客户端的远近对数据节点进行排序;然后,DistributedFileSystem 会利用 DFSInputStream 来实例化 FSDataInputStream,并返回给客户端,同时返回数据块的数据节点地址。
  3. 获得输入流 FSDataInputStream 后,客户端调用 read() 方法开始读取数据。输入流根据前面的排序结果,选择距离客户端最近的数据节点建立连接并读取数据。
  4. 数据从该数据节点读到客户端;当该数据块读取完毕时,FSDataInputStream 关闭和该数据节点的连接。
  5. 输入流通过 getBlockLocations() 方法查找下一个数据块(如果客户端缓存中已经包含了该数据块的位置信息,就不需要调用该方法)。
  6. 找到该数据块的最佳数据节点,读取数据。
  7. 当客户端读取完数据的时候,调用 FSDataInputStream 的 close() 方法,关闭输入流。需要注意的是,在读取数据的过程中,如果客户端与数据节点通信时出现错误,就会尝试连接包含此数据块的下一个数据节点。

二、写数据的过程

importorg.apache.hadoop.conf.Configuration;importorg.apache.hadoop.fs.FSDataOutputStream;importorg.apache.hadoop.fs.FileSystem;importorg.apache.hadoop.fs.Path;publicclassChapter3{publicstaticvoidmain(String[] args){try{Configuration conf =newConfiguration(); conf.set("fs.defaultFS","hdfs://localhost:9000"); conf.set("fs.hdfs.impl","org.apache.hadoop.hdfs.DistributedFileSystem");FileSystem fs =FileSystem.get(conf);byte[] buff ="Hello world".getBytes();// 要写入的内容String filename ="test";// 要写入的文件名FSDataOutputStream os = fs.create(newPath(filename)); os.write(buff,0, buff.length);System.out.println("Create:"+ filename); os.close(); fs.close();}catch(Exception e){ e.printStackTrace();}}}

客户端向 HDFS 写数据是一个复杂的过程,这里介绍一下在不发生任何异常的情况下,客户端连续调用 create()、write() 和 close() 时,HDFS 内部的执行过程见图2。

在这里插入图片描述

图2 HDFS写数据的过程

  1. 客户端通过 FileSystem.create() 创建文件,相应地,在 HDFS 中 Distributed FileSystem 具体实现了 FileSystem。因此,调用 create() 方法后,DistributedFileSystem 会创建输出流 FSDataOutputStream,对于 HDFS 而言,具体的输出流就是 DFSOutputStream。
  2. 然后,DistributedFileSystem 通过 RPC 远程调用名称节点,在文件系统的命名空间中创建一个新的文件。名称节点会执行一些检查,比如文件是否已经存在,客户端是否有权限创建文件等。检查通过之后,名称节点会构造一个新文件,并添加文件信息。远程方法调用结束后,DistributedFileSystem 会利用 DFSOutputStream 来实例化 FSDataOutputStream,并返回给客户端,客户端使用这个输出流写入数据。
  3. 获得输出流 FSDataOutputStream 以后,客户端调用输出流的 write() 方法向 HDFS 中对应的文件写入数据。
  4. 客户端向输出流 FSDataOutputStream 中写入的数据会首先被分成一个个的分包,这些分包被放入 DFSOutputStream 对象的内部队列。输出流 FSDataOutputStream 会向名称节点申请保存文件和副本数据块的若干个数据节点,这些数据节点形成一个数据流管道。队列中的分包最后被打包成数据包,发往数据流管道中的第 1 个数据节点,第 1 个数据节点将数据包发送给第 2 个数据节点,第 2 个数据节点将数据包发送给第 3 个数据节点,这样,数据包会流经管道上的各个数据节点。
  5. 因为各个数据节点位于不同的机器上,数据需要通过网络发送。因此,为了保证所有数据节点的数据都是准确的,接收到数据的数据节点要向发送者发送“确认包”(ACK Packet)。确认包沿着数据流管道逆流而上,从数据流管道依次经过各个数据节点并最终发往客户端,当客户端收到应答时,它将对应的分包从内部队列移除。不断执行 3~5 步,直到数据全部写完。
  6. 客户端调用 close() 方法关闭输出流,此时开始,客户端不会再向输出流中写入数据,所以,当 DFSOutputStream 对象内部队列中的分包都收到应答以后,就可以使用 ClientProtocol.complete() 方法通知名称节点关闭文件,完成一次正常的写文件过程。

小结

HDFS 读写数据时,读数据通过 FileSystem.open() 创建DFSInputStream,获取数据块位置,选择最近数据节点读取,读完关闭连接并查找下一数据块;写数据则通过 FileSystem.create() 创建 DFSOutputStream,远程调用名称节点创建文件,写入数据时分包放入队列,形成数据流管道传输,数据节点发送确认包,全部写完客户端调用 close() 关闭输出流,通知名称节点关闭文件,从而完成 HDFS 数据正常读写过程。

欢迎 点赞👍 | 收藏⭐ | 评论✍ | 关注🤗

Read more

数据结构:⼆叉树(1)

数据结构:⼆叉树(1)

目录 前言  树部分知识: 一.树的概念和结构 二.树的一些相关术语和定义  三.树的实现结构(了解部分) 四、树的应用场景 二叉树部分知识讲解: 一.二叉树概念与结构 二.特殊二叉树类型 1.满二叉树 2.完全二叉树 3.性质补充 三、⼆叉树存储结构 顺序结构: 编辑应用: 链式结构: 四、堆的概念与结构 1.实现顺序结构⼆叉树: 2.堆的概念与结构 (重点) 3.堆的实现 五、堆的实现代码部分 1.堆的初始化:(本次实现选取大堆为例) 2.堆的销毁: 3.堆的插入数据 : 4.堆打印值 : 六、

By Ne0inhk
Flutter 三方库 libsignal 的鸿蒙化适配指南 - 实现 Signal 协议加密通信、双大鼠(Double Ratchet)算法与前向安全性保障

Flutter 三方库 libsignal 的鸿蒙化适配指南 - 实现 Signal 协议加密通信、双大鼠(Double Ratchet)算法与前向安全性保障

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 libsignal 的鸿蒙化适配指南 - 实现 Signal 协议加密通信、双大鼠(Double Ratchet)算法与前向安全性保障 前言 在 Flutter for OpenHarmony 的高度安全通信领域,Signal 协议是目前全球公认的即时通讯加密标准。libsignal 是 Signal 协议的核心 Dart 实现。它能够为鸿蒙应用提供从身份认证到会话加密的全套解决方案,确保每一个字节的通信都具备前向安全性(Forward Secrecy)。本文将深入解析如何在鸿蒙端利用该库构建极致安全的加密通信能力。 一、原理解析 / 概念介绍 1.1 基础原理 Signal 协议的核心在于“双大鼠(Double Ratchet)”算法。它结合了 Diffie-Hellman

By Ne0inhk

优选算法——位运算

👇作者其它专栏 《数据结构与算法》《算法》《C++起始之路》 1.前要知识 《位操作符的妙用》 2.相关题解 2.1判定字符是否唯一 算法思路: 利用【位图】的思想,每一个【比特位】代表一个【字符】,一个int类型的变量的32位足够表示所有的小写字母。比特位里若为0,表示这个字符没有出现过;若为1,表示该字符出现过。 可以用一个【整数】来充当【哈希表】。 class Solution { public: bool isUnique(string astr) { //利用鸽巢原理优化 if(astr.size()>26) return false; int bitmap=0; for(auto i:

By Ne0inhk
无中生有——无监督学习的原理、算法与结构发现

无中生有——无监督学习的原理、算法与结构发现

“世界上绝大多数数据都没有标签。 真正的智能,不是在已知答案中选择,而是在混沌中发现秩序。” ——无监督学习的哲学 一、为什么需要无监督学习? 在前七章中,我们系统学习了监督学习(Supervised Learning)的核心范式:给定输入 x\mathbf{x}x 和对应标签 yyy,学习映射 f:x↦yf: \mathbf{x} \mapsto yf:x↦y。无论是线性回归、决策树,还是神经网络,都依赖于标注数据这一稀缺资源。 然而,现实世界的数据绝大多数是未标注的: * 用户浏览日志(只有行为,没有“好/坏”标签); * 医学影像(只有图像,没有诊断结论); * 社交网络(只有连接关系,没有群体划分); * 传感器时序(只有数值流,没有异常标记)

By Ne0inhk