描述一下HDFS读数据的完整流程
HDFS(Hadoop Distributed File System)的读数据流程是一个经典的分布式系统交互过程。整个流程的设计核心是:“控制流(元数据)走 NameNode,数据流走 DataNode”,以此来减轻单点 NameNode 的压力。
以下是 HDFS 读取数据的完整流程,按步骤详细分解:
核心组件角色
- Client(客户端):发起读请求,拼接最终数据。
- NameNode(NN):管理元数据,知道文件被切分成了哪些 Block,以及这些 Block 存在哪些 DataNode 上。
- DataNode(DN):实际存储数据块(Block)的节点。
完整图文步骤解析
第一步:客户端发起打开文件请求
- 客户端应用程序调用
FileSystem对象的open()方法(在 HDFS 中通常是DistributedFileSystem实例)来打开目标文件。
第二步:NameNode 解析并返回区块位置(获取元数据)
DistributedFileSystem通过 RPC(远程过程调用) 联系 NameNode。- NameNode 收到请求后,会进行一系列检查:
- 检查该文件是否存在。
- 检查客户端是否有权限读取该文件。
- 检查通过后,NameNode 会查询元数据,获取该文件前几个 Block 的存储位置(也就是哪些 DataNode 上有这些 Block 的副本)。
- 距离排序:NameNode 返回的 DataNode 列表并非随机,而是根据网络拓扑结构(机架感知计算),按距离客户端由近到远进行排序。如果客户端本身就是一个 DataNode,那么优先返回本地的副本位置(这就是常说的“数据本地化”)。
- NameNode 向客户端返回一个支持文件定位的输入流对象
FSDataInputStream(其底层包装了DFSInputStream对象),供客户端读取数据。
第三步:客户端连接 DataNode 准备读取
- 客户端调用输入流
FSDataInputStream的read()方法。 DFSInputStream会找出距离最近的 DataNode(针对第一个 Block),并与之建立 socket 连接。
第四步:数据流式传输(核心读取过程)
- 数据开始从 DataNode 源源不断地流式(Stream)传输到客户端。
- 客户端以数据包(Packet)为单位接收数据,并校验数据的完整性(Checksum)。
- 当这个 Block 的数据读取完毕后,
DFSInputStream会关闭与这个 DataNode 的连接。
第五步:循环读取后续 Block
- 客户端继续读取下一个 Block。
DFSInputStream会寻找下一个 Block 的最佳 DataNode,并重复步骤 3 和 4。 - 分批获取元数据:如果在第二步中,NameNode 只返回了文件部分 Block 的位置(文件很大的情况),当客户端读完这些 Block 后,
DFSInputStream会向 NameNode 发起第二次 RPC 请求,获取下一批 Block 的位置信息,然后继续读取。 - 在整个过程中,对于客户端的代码来说,它感觉就像是在读取一个连续的本地大文件,底层的跨网络、跨节点切换对用户是透明的。
第六步:关闭连接
- 当文件所有数据读取完毕后,客户端调用
FSDataInputStream的close()方法,关闭输入流,释放资源。
流程图解(简易版)
plaintext
Client NameNode DataNode
| | |
|--- 1. open(filePath) --------------->| |
| | (检查权限/文件存在性) |
|<-- 2. 返回 Block 位置列表 (按距离排序)-| |
| | |
|--- 3. read() / 连接最近的 DN ---------------------------------------------->|
| | |
|<-- 4. 流式传输数据块 (Block 1) ---------------------------------------------|
| | |
|--- 5. 连接最近的 DN 读取下一个 Block -------------------------------------->|
|<-- 6. 流式传输数据块 (Block 2) ---------------------------------------------|
| | |
| (若元数据耗尽,再次向NN请求后续Block) | |
|--- 7. 请求后续 Block 位置 ---------->| |
|<-- 8. 返回后续 Block 位置 -----------| |
| | |
|--- 9. close() -----------------------|--------------------------------------|
关键机制与容错处理(面试高频考点)
在实际读取过程中,网络和节点不可能总是完美的,HDFS 设计了完善的容错机制:
节点故障(DataNode 宕机或网络不通):
- 如果客户端在读取过程中与某个 DataNode 通信中断,或者连接失败。
- 客户端会把这个有故障的 DataNode 记录下来(防止后续再去请求它)。
- 客户端会从该 Block 的副本列表中取出下一个距离最近的 DataNode 进行连接并继续读取。
数据损坏(Checksum 校验失败):
- HDFS 的 DataNode 在存储 Block 时会同时存储校验和(Checksum)。
- 客户端在读取数据时会进行本地校验。如果发现读取的数据和校验和不匹配,说明数据已损坏。
- 客户端会向 NameNode 汇报这个损坏的 Block,以便 NameNode 后续安排重新复制健康副本。
- 同时,客户端会默默地去连接该 Block 的另一个健康副本节点读取数据,整个过程对上层应用不报错。
短路读取(Short-Circuit Local Read):
- 优化机制:如果客户端正好与包含该数据的 DataNode 运行在同一台物理机器上。
- 客户端将不再通过 TCP Socket 穿透网络栈去读取,而是绕过 DataNode 进程,直接读取本地操作系统文件系统上的数据文件。这极大地提高了读取性能。
右滑查看面试常问