基准测试 Spark 代码中有趣的性能变化
Posted
技术标签:
【中文标题】基准测试 Spark 代码中有趣的性能变化【英文标题】:Interesting performance variation in benchmarking Spark code 【发布时间】:2016-12-10 18:53:09 【问题描述】:我正在计算在 Spark 上完成特定工作需要多长时间,在这种情况下,保存输出 RDD 需要多长时间。 RDD 的保存涉及对其进行压缩。
奇怪的是,与第二次执行完全相同的代码相比,第一次执行代码总是更慢。这怎么可能?
Spark 程序如下所示:
JavaPairRDD<String, String> semisorted = wordsAndChar.sortByKey();
//First run
long startTime1 = System.currentTimeMillis();
semisorted.saveAsTextFile("testData.txt" + "_output1", org.apache.hadoop.io.compress.DefaultCodec.class);
long runTime1 = System.currentTimeMillis() - startTime1;
//Second run
long startTime2 = System.currentTimeMillis();
semisorted.saveAsTextFile("testData.txt" + "_output2", org.apache.hadoop.io.compress.DefaultCodec.class);
long runTime2 = System.currentTimeMillis() - startTime2;
sc.stop();
spark-submit --master local[1] --class com.john.Test my.jar /user/john/testData.txt /user/john/testData_output
输出是:
runTime1 = 126 秒
runTime2 = 82 秒
两个(完全相同的)工作怎么会有如此大的差异?
【问题讨论】:
RDD 是惰性的。第一次运行可能会缓存在内存中以供第二次和后续运行使用 另外,在一台机器上运行两次并不是什么基准 @cricket_007, “两次运行”,因为第一次运行时间太长。我什至跑了 3 次以上。在每种情况下,第一次运行都是最慢的。这只是“测试”——在与某人的机器进行比较之前,需要一台机器的可靠数字。 我不知道你创建了wordsAndChar
。你是缓存还是持久化?如果在运行之间取消持久化并重新创建 RDD,会发生什么?
【参考方案1】:
这两个工作不一样。任何 shuffle 操作,包括 sortByKey
,都会创建用作隐式缓存点的 shuffle 文件。
当您执行第一个作业时,它会执行完全随机播放和所有前面的操作。
当您执行第二个作业时,它可以读取 shuffle 文件并仅执行最后一个阶段。
您应该看到与此行为相对应的skipped stages in the Spark UI。
这里还有另一个变化来源,但它的影响应该更小。 Spark 中许多与上下文相关的对象都是延迟初始化的。这些将在第一个作业期间初始化。
一般来说,如果你想监控性能,你可以使用:
用于手动检查的 Spark UI。 Spark REST API(/applications/[app-id]/stages/[stage-id]
特别有用)或TaskListener
以获取详细统计信息。
您还应该:
执行多次运行并调整结果以更正初始化过程。unpersist
对象(如果需要)。
避免可能的混杂因素(例如,由同一应用程序执行的多个作业不是独立的,可能会受到缓存逐出或 GC 等多种因素的影响)。
【讨论】:
因此,如果这是 Spark 中的固有行为,那么在作业之间,假设我想准确计算和比较这两段代码的执行时间。怎么做?想象一下,我没有使用DefaultCodec
,而是使用了SnappyCodec
。以上是关于基准测试 Spark 代码中有趣的性能变化的主要内容,如果未能解决你的问题,请参考以下文章