我試圖運行一個非常簡單的hadoop作業。它是對經典wordCount的修改,它不是對單詞進行計數,而是對文件中的行進行計數。我想用它來清理一堆我知道有重複的大日誌文件(每個大約70GB)。每一行都是一個「記錄」,因此我只想記錄一次記錄。Hadoop無法完成作業,因爲「設備上沒有剩餘空間」
我知道我的代碼是有效的,因爲它在我用小的普通文件運行時做了它應該做的事情。當我用大文件運行它時,Hadoop的行爲非常嚴格。首先,它在MAP階段正常開始工作,通常可以毫無問題地達到100%。然而,在處理REDUCE時,它永遠不會超過50%。它達到也許40%,然後再回到0%表現出一些異常「左設備上沒有空間」之後:
FSError: java.io.IOException: No space left on device
,然後嘗試做再次減少和,當它達到40%,降至再次爲0%等等。當然,它會在它決定結束而沒有成功之前做2到3次。
雖然這個例外的問題是它不能與磁盤上的實際空間相關聯。磁盤空間永遠不會滿。不是HDFS上的全局(全局)空間,也不是每個節點中的單個磁盤。我檢查fs狀態:
$ hadoop dfsadmin -report > report
此報告從不顯示實際節點達到100%。事實上,沒有一個節點接近那個。
我在每個節點中都有大約60GB的磁盤可用,而且我在一個有60個數據節點的集羣中運行它,這給我的總空間大於3TB。我正在處理的文件只有70GB。
從互聯網上看,我發現這可能與Hadoop在處理大量數據時創建太多文件有關。原始的wordCount代碼大大減少了數據(因爲單詞重複很多)。一個70GB的文件可以減少到只有7MB的輸出。但是,我期待的只是1/3減少,或者輸出大約20-30GB。
Unix類型的系統都帶有每個進程打開1024個文件的限制:
$ ulimit -n
1024
如果Hadoop是創造比這更多,這可能是一個問題。我要求系統管理員將該限制增加到65K,這就是現在的限制:
$ ulimit -n
65000
問題仍然存在。這可能是我需要進一步增加這個限制嗎?這裏還有其他事情嗎?
非常感謝您的幫助!
代碼在這裏:
package ...;
import java.io.IOException;
import java.util.StringTokenizer;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;
public class LineCountMR {
public static class MapperClass
extends Mapper<Object, Text, Text, IntWritable>{
private final static IntWritable one = new IntWritable(1);
private Text word = new Text();
private String token = new String();
public void map(Object key, Text value, Context context
) throws IOException, InterruptedException {
token = value.toString().replace(' ', '_');
word.set(token);
context.write(word, one);
}
}
public static class ReducerClass
extends Reducer<Text,IntWritable,Text,IntWritable> {
private IntWritable result = new IntWritable();
public void reduce(Text key, Iterable<IntWritable> values,
Context context
) throws IOException, InterruptedException {
int sum = 0;
for (IntWritable val : values) {
sum += val.get();
}
result.set(sum);
context.write(key, result);
}
}
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();;
if (args.length != 2) {
System.err.println("Parameters: <in> <out>");
System.exit(2);
}
Job job = new Job(conf, "line count MR");
job.setJarByClass(LineCountMR.class);
job.setMapperClass(MapperClass.class);
job.setCombinerClass(ReducerClass.class);
job.setReducerClass(ReducerClass.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
FileInputFormat.addInputPath(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}
你正在運行多少個reducer,你配置了壓縮映射輸出,你使用了一個組合器嗎?你記錄了大量的調試信息嗎?你可以發佈代碼嗎? –
通過任何機會,你可以看到你是否可以運行壓縮編解碼器來減少MR輸出的大小?這可以讓你確定這是否真的是空間問題。我遇到了一個問題,我正在對4.2GB的壓縮源文件運行我的工作,解壓縮爲120GB。由於MR輸出被解壓縮,它膨脹到230GB,因此我遇到了這個問題。你有什麼機會壓縮你的源文件? –
感謝您的回覆。這裏回答你的問題: 對於Chris White: 「你運行多少個reducer,你配置了壓縮映射輸出嗎,你使用了一個組合器嗎?你記錄了大量的調試信息嗎?你能發佈代碼嗎? ?」 關於減速器,我使用的是標準配置。我沒有設置更多的減速器。我想這是每個節點2個映射器和2個reducer,對不對?我不使用組合器。我應該在這種情況下使用它嗎?關於調試消息,不。我沒有記錄他們(至少我沒有設置任何調試模式或任何東西)。 – ekorso