精简版
HDFS读数据的精简流程如下:
- 应用程序通过Hadoop客户端向HDFS发送读取数据的请求。
- Namenode根据请求中指定的文件名和偏移量来查询元数据以确定所需数据块的位置信息(数据块所在的数据节点(DataNode)的网络位置)并返回给客户端。
- 客户端收到数据块的位置信息后与对应的DataNode节点(就近原则)建立通信连接,发送读取数据的请求。
- DataNode节点将数据块的内容划分为若干数据包(Packet),并通过网络传输给客户端。
客户端接收到数据包后,将它们按照正确的顺序进行重组,得到完整的数据块。
详细版
在调用open()方法的时候会有文件存在性和权限的校验。
- 客户端通过调用FileSystem对象的open()方法来打开希望读取的文件。对于HDFS来说,这个对象是DistributedFileSystem的一个实例。
- DistributedFileSystem使用远程过程调用(RPC)来调用Namenode,以确定文件起始块的位置。Namenode返回存有该块副本的DataNode地址,并根据它们与客户端的距离进行排序。
- DistributedFileSystem返回一个FSDataInputStream对象给客户端,用于读取数据。FSDataInputStream类封装了DFSInputStream对象,该对象管理着DataNode和Namenode的I/O。
- 客户端通过对输入流调用read()方法来读取数据。DFSInputStream连接距离最近的文件中第一个块所在的DataNode,并通过反复调用read()方法将数据从DataNode传输到客户端。
- 当到达块的末端时,DFSInputStream关闭与该DataNode的连接,并寻找下一个块的最佳DataNode。这个过程对于客户端是透明的,它一直在读取一个连续的流。
- 客户端完成读取后,对FSDataInputStream调用close()方法。
重点说明:在读取数据的过程中,如果DFSInputStream在与DataNode通信时遇到错误,会尝试从该块的其他最邻近DataNode读取数据。它还会记住故障的DataNode,以避免重复读取该节点上的块。DFSInputStream还会通过校验和确认从DataNode发来的数据是否完整,如果发现有损坏的块,会尝试从其他DataNode读取其副本,并将损坏的块通知给Namenode。