如何防止hadoop作业在损坏的输入文件上失败

时间:2013-02-17 10:41:33

标签: hadoop mapreduce cascading

我正在许多输入文件上运行hadoop作业。 但是如果其中一个文件被破坏,整个工作都会失败。

如何让作业忽略损坏的文件? 也许给我写一些计数器/错误日志,但不会失败整个工作

3 个答案:

答案 0 :(得分:7)

这取决于你的工作失败的地方 - 如果一行损坏,并且你的map方法中某处抛出了异常,那么你应该能够用try / catch包装你的map方法的主体而只是记录错误:

protected void map(LongWritable key, Text value, Context context) {
  try {
    // parse value to a long
    int val = Integer.parseInt(value.toString());

    // do something with key and val..
  } catch (NumberFormatException nfe) {
    // log error and continue
  }
}

但是如果您的InputFormat的RecordReader抛出错误,那么您需要修改映射器run(..)方法 - 默认实现如下:

public void run(Context context) {
  setup(context);
  while (context.nextKeyValue()) {
    map(context.getCurrentKey(), context.getCurrentValue(), context);
  }
  cleanup(context);
}

所以你可以修改它来尝试在context.nextKeyValue()调用上捕获异常,但你必须小心忽略读者抛出的任何错误 - 例如IOExeption可能不是'可跳过的'只是忽略错误。

如果您编写了自己的InputFormat / RecordReader,并且您有一个特定的异常表示记录失败但允许您跳过并继续解析,那么这样的事情可能会起作用:

public void run(Context context) {
  setup(context);
  while (true) {
    try {
      if (!context.nextKeyValue()) { 
        break;
      } else {
        map(context.getCurrentKey(), context.getCurrentValue(), context);
      }
    } catch (SkippableRecordException sre) {
      // log error
    }

  }
  cleanup(context);
}

但只是重新改写 - 你的RecordReader必须能够在出错时恢复,否则上面的代码可能会让你陷入无限循环。

针对您的具体情况 - 如果您只是想在第一次失败时忽略文件,那么您可以将run方法更新为更简单的方法:

public void run(Context context) {
  setup(context);
  try {
    while (context.nextKeyValue()) {
      map(context.getCurrentKey(), context.getCurrentValue(), context);
    }
    cleanup(context);
  } catch (Exception e) {
    // log error
  }
}

警告的最后一句话:

  • 你需要确保它不是你的映射器代码导致抛出异常,否则你会因为错误的原因而忽略文件
  • 非GZip压缩的GZip压缩文件在记录阅读器初始化时实际上会失败 - 所以上面不会捕获这种类型或错误(你需要编写自己的记录阅读器实现)。对于在创建记录阅读器期间引发的任何文件错误都是如此

答案 1 :(得分:2)

故障陷阱用于级联:

  

每当操作失败并抛出异常时,如果存在关联的陷阱,则会将违规的元组保存到陷阱Tap指定的资源中。这允许作业继续处理而不会丢失任何数据。

这实际上会让您的工作继续下去,让您稍后检查损坏的文件

如果您对流程定义语句中的级联有些熟悉:

    new FlowDef().addTrap( String branchName, Tap trap );

Failure Traps

答案 2 :(得分:0)

还有另一种可能的方式。您可以使用mapred.max.map.failures.percent配置选项。当然,解决这个问题的方法也可以隐藏在映射阶段发生的其他一些问题。