我正在创建一个uber jar spark应用程序,我将其提交给EMR 4.3集群,我正在配置4个r3.xlarge实例,一个是主服务器,另外三个是核心服务器 .

我从控制台预安装了hadoop 2.7.1,ganglia 3.7.2 spark 1.6和hive 1.0.0 .

我正在运行以下命令:

spark-submit \
--deploy-mode cluster \
--executor-memory 4g \
--executor-cores 2 \
--num-executors 4 
--driver-memory 4g 
--driver-cores 2  
--conf "spark.driver.maxResultSize=2g" 
--conf "spark.hadoop.spark.sql.parquet.output.committer.class=org.apache.spark.sql.parquet.DirectParquetOutputCommitter"  
--conf "spark.shuffle.memoryFraction=0.2" 
--class com.jackar.spark.Main spark-app.jar args

我意识到我没有充分利用集群,但此时我并没有完全尝试调整(或者也许这就是我应该做的事情?) . 我的基础工作有以下几点:

1)从s3读取代表两个数据集的镶木地板文件,在Dataframes上运行registerTempTable,然后在每个数据集上运行cacheTable . 它们每个内存大约300 MB . (注意:我使用EMRs s3://协议以及s3a://尝试过这个)

2)使用spark sql运行聚合(即sums和group bys) .

3)将结果写为s3作为镶木地板文件 .

当我查看Spark UI时,作业运行得很好,并且它们需要的时间与我预期的一样长 . 问题是,在写入-cla-to-parquet-in-s3作业完成后(“作业”选项卡),有一段时间没有其他作业排队 .

如果我然后转到Spark UI中的SQL选项卡,我会注意到“作业”选项卡表示已完成的同一作业存在“正在运行的查询” . 当我单击并查看该查询的DAG时,我注意到DAG似乎已经被评估了 .

DAG visualisation

但是,此查询需要几分钟,有时会导致整个spark应用程序重新启动并最终失败...

Spark UI: SQL tab

我开始做一些调查,看看我是否可以找出问题,因为在我的Databricks试验中,这项工作的执行速度非常快,DAG与EMR相同(如预期的那样) . 但是,当我不知道为什么我没有在EMR中看到类似的性能时,我无法证明使用Databricks是合理的 .

也许这是我的JVM参数?例如垃圾收集?是时候检查执行程序日志了 .

2016-02-23T18:25:48.598+0000: [GC2016-02-23T18:25:48.598+0000: [ParNew: 299156K->30449K(306688K), 0.0255600 secs] 1586767K->1329022K(4160256K), 0.0256610 secs] [Times: user=0.05 sys=0.00, real=0.03 secs] 
2016-02-23T18:25:50.422+0000: [GC2016-02-23T18:25:50.422+0000: [ParNew: 303089K->32739K(306688K), 0.0263780 secs] 1601662K->1342494K(4160256K), 0.0264830 secs] [Times: user=0.07 sys=0.01, real=0.02 secs] 
2016-02-23T18:25:52.223+0000: [GC2016-02-23T18:25:52.223+0000: [ParNew: 305379K->29373K(306688K), 0.0297360 secs] 1615134K->1348874K(4160256K), 0.0298410 secs] [Times: user=0.08 sys=0.00, real=0.03 secs] 
2016-02-23T18:25:54.247+0000: [GC2016-02-23T18:25:54.247+0000: [ParNew: 302013K->28521K(306688K), 0.0220650 secs] 1621514K->1358123K(4160256K), 0.0221690 secs] [Times: user=0.06 sys=0.01, real=0.02 secs] 
2016-02-23T18:25:57.994+0000: [GC2016-02-23T18:25:57.994+0000: [ParNew: 301161K->23609K(306688K), 0.0278800 secs] 1630763K->1364319K(4160256K), 0.0279460 secs] [Times: user=0.07 sys=0.01, real=0.03 secs]

好的 . 这看起来不太好 . Parnew stops the world并且它每隔几秒发生一次 .

下一步,查看Databricks上的Spark UI,看看gc配置是否与EMR不同 . 我发现了一些有趣的东西 . Databricks将spark.executor.extraJavaOptions设置为:

-XX:ReservedCodeCacheSize=256m 
-XX:+UseCodeCacheFlushing 
-javaagent:/databricks/DatabricksAgent.jar 
-XX:+PrintFlagsFinal 
-XX:+PrintGCDateStamps 
-verbose:gc 
-XX:+PrintGCDetails 
-XX:+HeapDumpOnOutOfMemoryError 
-Ddatabricks.serviceName=spark-executor-1

嘿,我不是gc专家,我在我的待办事项列表中添加了“学习调整gc”,但我在这里看到的不仅仅是执行者的gc params . DatabricksAgent.jar做了什么 - 这有帮助吗?我不确定,所以我强制我的spark工作使用 Actuator 的java选项减去databricks特定的东西:

--conf spark.executor.extraJavaOptions="-XX:ReservedCodeCacheSize=256m -XX:+UseCodeCacheFlushing -XX:+PrintFlagsFinal -XX:+PrintGCDateStamps -verbose:gc -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError"

这不会改变“运行查询”行为 - 它仍然需要永远 - 但我确实得到了PSYoungGen而不是Parnew(频率仍然是每隔几秒钟):

2016-02-23T19:40:58.645+0000: [GC [PSYoungGen: 515040K->12789K(996352K)] 1695803K->1193777K(3792896K), 0.0203380 secs] [Times: user=0.03 sys=0.01, real=0.02 secs] 
2016-02-23T19:57:50.463+0000: [GC [PSYoungGen: 588789K->13391K(977920K)] 1769777K->1196033K(3774464K), 0.0237240 secs] [Times: user=0.04 sys=0.00, real=0.02 secs]

如果你已经读完了,我推荐你 . 我知道这篇文章有多长 .

我发现的另一个症状是,当查询运行时,stderr和stdout处于停顿状态,并且在任何执行程序(包括驱动程序)上都没有添加新的日志行 .

16/02/23 19:41:23 INFO ContextCleaner: Cleaned shuffle 5
16/02/23 19:57:32 INFO DynamicPartitionWriterContainer: Job job_201602231940_0000 committed.

同样的~17分钟差距在Spark UI中被考虑为正在运行的查询......任何想法是怎么回事?

最后,在将几个aggs写入S3(比如10%)之后,这个工作往往会重新启动,然后最终火花应用程序失败 .

我不确定这个问题是否与EMR在YARN上运行而Databricks在独立集群上运行或者它完全不相关的事实有关 .

我在查看纱线日志后最终得到的失败如下:

java.io.FileNotFoundException: No such file or directory: s3a://bucket_file_stuff/_temporary/0/task_201602232109_0020_m_000000/

任何建议都非常感谢 . 我会随便添加笔记 . 谢谢!