我目前正在尝试写一个map-reduce作业,其中输入数据不在HDFS中,并且无法加载到HDFS中,基本上是因为使用数据的程序无法使用HDFS中的数据,并且有太多的数据要复制到HDFS中,每个节点至少1TB。
所以我在集群的4个节点上各有4个目录。理想情况下,我希望我的映射器只是接收这4个本地目录的路径并读取它们,使用类似file:///var/mydata/…然后一个映射器可以处理每个目录。即总共16个映射器。
然而,为了能够做到这一点,我需要确保每个节点正好有4个映射器,并且正好有4个映射器被分配到该机器的本地路径。这些路径是静态的,因此可以硬编码到我的fileinputformat和recordreader中,但是我如何保证给定的分割最终出现在具有已知主机名的给定节点上呢?如果是在HDFS中,我可以使用FileInputFormat的变体将isSplittable设置为false, hadoop会处理它,但由于所有数据都是本地的,这会导致问题。
基本上,我想要的是能够抓取集群中每个节点上的本地目录结构一次,处理这些目录中的sstable集合并发出行(在mapper上),并将结果(在reduce步骤中)减少到HDFS以进行进一步的批量处理。
我注意到inputsplit提供了一个getLocations函数,但我认为这并不能保证执行的位置,只会优化它,如果我尝试在每个映射器中使用file:///some_path,我需要确保准确的位置,否则我可能会反复读取一些目录,而其他根本不需要。
我知道有三种方法可以做到。
1)。只需将数据加载到HDFS,这是您不想做的。但是值得一试,因为它对将来的处理很有用
2)。你可以使用NLineInputFormat。在每个节点中使用输入文件的url创建四个不同的文件。
file://192.168.2.3/usr/rags/data/DFile1.xyz
.......
您将这些文件加载到HDFS中,并在这些文件上编写程序,以使用这些url访问数据数据并处理数据。如果您使用NLineInputFormat与1行。您将处理16个映射器,每个映射器处理一个独占文件。这里唯一的问题是,一个节点上的数据很有可能在另一个节点上处理,但是不会有任何重复的处理
3)。您可以通过分别使用url加载上述四个文件来进一步优化上述方法。在加载其中任何一个文件时,您可以删除其他三个节点,以确保文件准确地到达数据文件本地存在的节点。在加载时选择复制为1,这样块就不会被复制。这个过程将极大地增加所启动的映射处理本地文件的概率。
干杯破布