HDFS 在文件的增删查操作上封装的很好,我们只要写几行代码就可以解决问题,这操作每个大数据开发者都会。不过,作为一个程序员(其他职业也应如此),我认为应该培养自己的核心竞争力,会一点别人不会的东西,而不是局限于 API 的使用上,将底层原理搞通才能越走越远。那我们就开始吧!本篇主要阐述 HDFS 读取文件的流程。
整个流程分为以下几个步骤:
- 获取文件系统 FileSystem,在 HDFS,不同的文件系统有不同的实现类,HDFS 使用的是分布是文件系统,其实现类为
DistributedFileSystem
。 - 这个 FileSystem 通过 RPC 调用元数据节点的服务,获取文件的块信息,每一个块数据都有一定数量的副本,返回结果根据数据节点与客户端的距离进行排序,节省 map reduce 操作的时间,这个方法返回一个 FSDataInputStream 对象。
- 调用 FSDataInputStream 的 read 方法,FSDataInputStream 连接保存第一个块数据的节点,读取块文件。第一个块文件读取完成之后,连接下一个块数据的节点。
- 传输完成之后调用 close 方法结束读取文件的过程。
在读取的时候,如果客户端在与数据节点通信时遇到错误,那么它就去尝试对这个块数据来说下一个最近的块。它也会记住那个故障的数据节点,以保证不会再对之后的块进行徒劳无益的尝试。整个流程可以用这张图来表示:
读取文件的代码如下。通过对照上面的流程,就可以更好的理解代码的含义。这里再说明一下,为了获取 FileSystem 对象,我们需要获取服务器的文件系统类型,这个类型可以通过 Configuration 对象设置,也可以通过 core-site.xml 进行配置,如果这两个地方都没有进行设置的话,那么默认返回 FileSystem 的实例是 LocalFileSystem 对象,即本地的文件系统。
public void download() throws IOException{
Configuration conf = new Configuration();
conf.set("fs.defaultFS","hdfs://localhost:9000/");
FileSystem fs = FileSystem.get(conf);
Path src = new Path("hdfs://localhost:9000/xxx.gz");
FSDataInputStream in = fs.open(src);
FileOutputStream os = new FileOutputStream("xxx.gz");
IOUtils.copy(in, os);
}
读源码可以让我们在 debug 时更快的定位到错误的来源,了整体流程可以让我们更好的去分析源码,这种思维跟我在 发现了一种不错的学习方法 中阐述的一致,对于想要学习的知识有一个宏观的认识,再根据需要对于各个部分进行深入,继续坚持下去,希望自己早日转到大数据行业,filghting !