精心设计的机制中, HDFS的读数据流程是这样的, 先客户端经NameNode获取元数据, 而后从DataNode拉取数据块, 此过程涵盖RPC通信、流式传输、校验和验证等多个关键环节, 理解这套流程, 则能够助力我们定位性能瓶颈以及排查数据读取故障。客户端如何定位数据块位置于应用程序调用FileSystem.open()方法之际, 会去创建DistributedFileSystem实例, 接着借助DFSClient开启NameNode的RPC调用, NameNode返回的并非数据本质, 而是LocatedBlocks对象, 此对象里含有每个数据块所处的DataNode列表。在源码的层面上, DFSClient的open()这个方法, 会去调用namenode.getBlockLocations(), 其返回的LocatedBlock列表, 是按照块ID来进行排序的。客户端, 会依据网络拓扑状去选择最为靠近的副本, 默认情况下, 会优先去读取本地的DataNode, 其次才是同机架的节点。getBlockLocations方法在NameNode内部的实现, 会去检查文件的权限、块副本的位置以及block的租约状态。客户端在拿到LocatedBlocks之后, 会去创建DFSInputStream对象, 这个对象乃是读数据的核心入口, 它对当前的读取位置、块索引以及DataNode连接池进行维护。要是文件存在多块, 当DFSInputStream已然读取完当前块的时候, 便会自动切换至下一个块, 在切换之际会再次借助namenode去定位新块的DataNode列表。读数据时怎样处理网络和校验异常DFSInputStream的read()方法, 会去调用blockSeekTo(), 以此定位到目标块, 之后建立与DataNode的Socket连接。DataNode收到读请求后, 会启动BlockSender线程, 把数据块切分成packet包, 进行流式传输。而每个packet包含校验和以及数据段。读请求是由源码中DataXceiver的readBlock方法来负责处理的, 它会先对客户端身份进行验证, 之后调用BlockSender.sendBlock(), BlockSender会把数据块从磁盘读取到内存缓冲区, 接着进行分包发送, 每个packet的大小是按照dfs.bytes-per-checksum参数来控制的, 默认情况下512字节对应着一个校验和。要是在读取进程里DataNode出现宕机现象或者网络发生中断情况, DFSInputStream就会启动重试机制。它把当前DataNode标定为故障节点, 从LocatedBlocks当中选取下一个副本展开重试。重试逻辑是在readBlockBuffer方法里面达成的, 默认尝试最多重试10次。要是所有副本都不具备可用性, 就会抛出BlockMissingException。
HDFS读数据流程详解与源码一步步拆
发布时间:2026/5/27 6:36:44
精心设计的机制中, HDFS的读数据流程是这样的, 先客户端经NameNode获取元数据, 而后从DataNode拉取数据块, 此过程涵盖RPC通信、流式传输、校验和验证等多个关键环节, 理解这套流程, 则能够助力我们定位性能瓶颈以及排查数据读取故障。客户端如何定位数据块位置于应用程序调用FileSystem.open()方法之际, 会去创建DistributedFileSystem实例, 接着借助DFSClient开启NameNode的RPC调用, NameNode返回的并非数据本质, 而是LocatedBlocks对象, 此对象里含有每个数据块所处的DataNode列表。在源码的层面上, DFSClient的open()这个方法, 会去调用namenode.getBlockLocations(), 其返回的LocatedBlock列表, 是按照块ID来进行排序的。客户端, 会依据网络拓扑状去选择最为靠近的副本, 默认情况下, 会优先去读取本地的DataNode, 其次才是同机架的节点。getBlockLocations方法在NameNode内部的实现, 会去检查文件的权限、块副本的位置以及block的租约状态。客户端在拿到LocatedBlocks之后, 会去创建DFSInputStream对象, 这个对象乃是读数据的核心入口, 它对当前的读取位置、块索引以及DataNode连接池进行维护。要是文件存在多块, 当DFSInputStream已然读取完当前块的时候, 便会自动切换至下一个块, 在切换之际会再次借助namenode去定位新块的DataNode列表。读数据时怎样处理网络和校验异常DFSInputStream的read()方法, 会去调用blockSeekTo(), 以此定位到目标块, 之后建立与DataNode的Socket连接。DataNode收到读请求后, 会启动BlockSender线程, 把数据块切分成packet包, 进行流式传输。而每个packet包含校验和以及数据段。读请求是由源码中DataXceiver的readBlock方法来负责处理的, 它会先对客户端身份进行验证, 之后调用BlockSender.sendBlock(), BlockSender会把数据块从磁盘读取到内存缓冲区, 接着进行分包发送, 每个packet的大小是按照dfs.bytes-per-checksum参数来控制的, 默认情况下512字节对应着一个校验和。要是在读取进程里DataNode出现宕机现象或者网络发生中断情况, DFSInputStream就会启动重试机制。它把当前DataNode标定为故障节点, 从LocatedBlocks当中选取下一个副本展开重试。重试逻辑是在readBlockBuffer方法里面达成的, 默认尝试最多重试10次。要是所有副本都不具备可用性, 就会抛出BlockMissingException。