Spark / Hadoop会抛出大型LZO文件的异常

时间:2014-08-11 16:37:15

标签: hadoop apache-spark elastic-map-reduce lzo

我在S3中存储的一些LZO压缩日志文件上运行EMR Spark作业。有几个日志文件存储在同一个文件夹中,例如:

...
s3://mylogfiles/2014-08-11-00111.lzo
s3://mylogfiles/2014-08-11-00112.lzo
...

在spark-shell中,我正在运行一个计算文件中行数的作业。如果我为每个文件单独计算行数,则没有问题,例如像这样:

// Works fine
...
sc.textFile("s3://mylogfiles/2014-08-11-00111.lzo").count()
sc.textFile("s3://mylogfiles/2014-08-11-00112.lzo").count()
...

如果我使用通配符加载带有单行的所有文件,我会得到两种例外。

// One-liner throws exceptions
sc.textFile("s3://mylogfiles/*.lzo").count()

例外情况是:

java.lang.InternalError: lzo1x_decompress_safe returned: -6
    at com.hadoop.compression.lzo.LzoDecompressor.decompressBytesDirect(Native Method)

java.io.IOException: Compressed length 1362309683 exceeds max block size 67108864 (probably corrupt file)
    at com.hadoop.compression.lzo.LzopInputStream.getCompressedData(LzopInputStream.java:291)

在我看来,解决方案是在最后一个例外情况下给出的文字暗示,但我不知道如何继续。 LZO文件允许的大小是有限制的,或者问题是什么?

我的问题是:我是否可以运行Spark查询来加载S3文件夹中的所有LZO压缩文件,而不会获得与I / O相关的异常?

每个文件有66个大约200MB的文件。

修改: 只有在使用Hadoop2核心库(ami 3.1.0)运行Spark时才会出现异常。当使用Hadoop1核心库(ami 2.4.5)运行时,一切正常。两个案例都使用Spark 1.0.1进行了测试。

3 个答案:

答案 0 :(得分:5)

kgeyti的回答很好,但是:

LzoTextInputFormat引入了性能损失,因为它检查每个LZO文件的.index文件。对于S3上的许多LZO文件来说,这可能会特别痛苦(由于数以千计的S3请求,我已经经历了几分钟的延迟)。

如果您事先知道您的LZO文件可拆分,那么更高效的解决方案是创建自定义的,不可拆分的输入格式:

import org.apache.hadoop.fs.Path
import org.apache.hadoop.mapreduce.JobContext
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat

class NonSplittableTextInputFormat extends TextInputFormat {
    override def isSplitable(context: JobContext, file: Path): Boolean = false
}

并阅读如下文件:

context.newAPIHadoopFile("s3://mylogfiles/*.lzo",
  classOf[NonSplittableTextInputFormat],
  classOf[org.apache.hadoop.io.LongWritable],
  classOf[org.apache.hadoop.io.Text])
.map(_._2.toString)

答案 1 :(得分:4)

昨天我们在一个EMR集群上部署了Hive,并且在S3中的一些LZO文件遇到了同样的问题,这些文件在没有任何问题的情况下被另一个非EMR集群占用。我注意到在日志中挖掘了一些内容后,地图任务以250MB块的形式读取了S3文件,尽管文件肯定是不可拆分

事实证明,参数 mapreduce.input.fileinputformat.split.maxsize 设置为250000000~250MB。这导致LZO从文件中打开流,最终打开了一个损坏的LZO块。

我将参数 mapreduce.input.fileinputformat.split.maxsize = 2000000000 设置为输入数据的最大文件大小,现在一切正常。

我不完全确定这与Spark的确切关系如何,但更改InputFormat可能有所帮助,这似乎是首先出现的问题,因为How Amazon EMR Hive Differs from Apache Hive已经提到过。

答案 2 :(得分:4)

我自己没有遇到过这个问题,但看起来.textFile期望文件可以拆分,就像Cedrik的Hive坚持使用CombineFileInputFormat的问题一样

您可以index your lzo files或尝试使用LzoTextInputFormat - 我有兴趣听听EMR上的效果是否更好:

sc.newAPIHadoopFile("s3://mylogfiles/*.lz", 
    classOf[com.hadoop.mapreduce.LzoTextInputFormat],
    classOf[org.apache.hadoop.io.LongWritable],
    classOf[org.apache.hadoop.io.Text])
  .map(_._2.toString) // if you just want a RDD[String] without writing a new InputFormat
  .count