基准测试 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 代码中有趣的性能变化的主要内容,如果未能解决你的问题,请参考以下文章

基准测试期间有趣的 MySQL 行为

关于MySQL的基准测试

在不使用操作的情况下对 Spark 进行基准测试

Mysql基准测试详细解说(根据慕课网:《打造扛得住Mysql数据库架构》视频课程实时笔录)

[前端工坊]微基准测试工具JMH 使用

golang基准测试详解