sc.wholeTextFiles + toDebugString甚至在执行操作之前需要很长时间

时间:2017-03-20 07:11:24

标签: apache-spark

下面是一个简单的代码段。

inputForCust是14762个文件,总计57M,平均文件大小为0.5K。这些文件是从通过NFS挂载的本地文件系统加载的。

val inputCustFiles = sc.wholeTextFiles(inputForCust, jobArgs.minPartitions)
println("This prints immediately")
inputCustFiles.toDebugString
println("This prints after 20 mins")
inputCustFiles.count
println("This prints after 10 mins")

注意:我们在整个文本文件之后进行了一些复杂的转换,并且时间是在reduceByKey中进行的!我已经简化了代码来重现问题。

我的问题是,为什么inputCustFiles.toDebugString花了这么多时间?

如果,inputCustFiles.count需要时间,我可以放心,它将利用集群处理能力。但是inputCustFiles.toDebugString阻止了驱动程序!!!

在20分钟的持续时间内,我发现火花UI中没有活动。

如果启用跟踪级别日志记录,请参阅以下行

[error] [17/03/17 23:23:27] [DEBUG] BlockManager: Getting local block broadcast_1
[error] [17/03/17 23:23:27] [DEBUG] BlockManager: Level for block broadcast_1 is StorageLevel(true, true, false, true, 1)
[error] [17/03/17 23:23:27] [DEBUG] BlockManager: Getting block broadcast_1 from memory
[error] [17/03/17 23:23:43] [TRACE] HeartbeatReceiver: Checking for hosts with no recent heartbeats in HeartbeatReceiver.
[error] [17/03/17 23:24:43] [TRACE] HeartbeatReceiver: Checking for hosts with no recent heartbeats in HeartbeatReceiver.
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

任何想法,如果我做错了什么或者这是火花的限制/错误/设计?

注意:

  • 我们正在使用1.6.2。
  • 如果输入文件的数量发生变化,toDebugString的时间会增加!!!

以下是驱动程序被阻止时的堆栈跟踪

java.io.FileInputStream.readBytes(Native Method)
java.io.FileInputStream.read(FileInputStream.java:255)
java.io.BufferedInputStream.read1(BufferedInputStream.java:284)
java.io.BufferedInputStream.read(BufferedInputStream.java:345)
sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
java.io.InputStreamReader.read(InputStreamReader.java:184)
java.io.BufferedReader.fill(BufferedReader.java:161)
java.io.BufferedReader.read1(BufferedReader.java:212)
java.io.BufferedReader.read(BufferedReader.java:286)
org.apache.hadoop.util.Shell$ShellCommandExecutor.parseExecResult(Shell.java:602)
org.apache.hadoop.util.Shell.runCommand(Shell.java:446)
org.apache.hadoop.util.Shell.run(Shell.java:379)
org.apache.hadoop.util.Shell$ShellCommandExecutor.execute(Shell.java:589)
org.apache.hadoop.util.Shell.execCommand(Shell.java:678)
org.apache.hadoop.util.Shell.execCommand(Shell.java:661)
org.apache.hadoop.fs.FileUtil.execCommand(FileUtil.java:1097)
org.apache.hadoop.fs.RawLocalFileSystem$RawLocalFileStatus.loadPermissionInfo(RawLocalFileSystem.java:567)
org.apache.hadoop.fs.RawLocalFileSystem$RawLocalFileStatus.getPermission(RawLocalFileSystem.java:542)
org.apache.hadoop.fs.LocatedFileStatus.<init>(LocatedFileStatus.java:42)
org.apache.hadoop.fs.FileSystem$4.next(FileSystem.java:1815)
org.apache.hadoop.fs.FileSystem$4.next(FileSystem.java:1797)
org.apache.hadoop.mapreduce.lib.input.FileInputFormat.listStatus(FileInputFormat.java:267)
org.apache.hadoop.mapreduce.lib.input.CombineFileInputFormat.getSplits(CombineFileInputFormat.java:217)
org.apache.spark.rdd.WholeTextFileRDD.getPartitions(WholeTextFileRDD.scala:49)
org.apache.spark.rdd.RDD$$anonfun$partitions$2.apply(RDD.scala:239)
org.apache.spark.rdd.RDD$$anonfun$partitions$2.apply(RDD.scala:237)
scala.Option.getOrElse(Option.scala:121)
org.apache.spark.rdd.RDD.partitions(RDD.scala:237)
org.apache.spark.rdd.MapPartitionsRDD.getPartitions(MapPartitionsRDD.scala:35)
org.apache.spark.rdd.RDD$$anonfun$partitions$2.apply(RDD.scala:239)
org.apache.spark.rdd.RDD$$anonfun$partitions$2.apply(RDD.scala:237)
scala.Option.getOrElse(Option.scala:121)
org.apache.spark.rdd.RDD.partitions(RDD.scala:237)
org.apache.spark.rdd.RDD.firstDebugString$1(RDD.scala:1747)
org.apache.spark.rdd.RDD.toDebugString(RDD.scala:1781)
oculus.storeonce.spark.Test$.main(Test.scala:11)
oculus.storeonce.spark.Test.main(Test.scala)

1 个答案:

答案 0 :(得分:1)

事实证明,spark驱动程序通过文件系统并获取大量元数据,因此它可以创建正确数量的适当大小的分区。由于文件系统(甚至HDFS)在处理小文件方面效率不高,因此扫描文件系统中的元数据会导致延迟!!!

为什么rdd.reduceByKey ...或者rdd.toDebugString正在调用操作而不是sc.wholeTextFiles / textFiles或rdd.map不是一个问题!!!

解决方案/解决方法是将数据托管在kafka / cassandra之类的内容中,或者将许多文件的内容合并到单个文件中。