使用 Apache Spark 2.x 的时候可能会遇到这种现象:虽然 Spark Jobs 已经全部完成了,但是程序却还在执行。比如我们使用 Spark SQL 去执行一些 SQL,这个 SQL 在最后生成了大量的文件。然后我们可以看到,这个 SQL 所有的 Spark Jobs 其实已经运行完成了,但是这个查询语句还在运行。通过日志,我们可以看到 driver 节点正在一个一个地将 tasks 生成的文件移动到最终表的目录下面,当我们作业生成的文件很多的情况下,就很容易产生这种现象。本文将给大家介绍一种方法来解决这个问题。、

Spark 2.x 用到了 Hadoop 2.x,其将生成的文件保存到 HDFS 的时候,最后会调用了 saveAsHadoopFile,而这个函数在里面用到了 FileOutputCommitter,如下:

def saveAsHadoopFile(
path: String,
keyClass: Class[_],
valueClass: Class[_],
outputFormatClass: Class[_ <: OutputFormat[_, _]],
conf: JobConf = new JobConf(self.context.hadoopConfiguration),
codec: Option[Class[_ <: CompressionCodec]] = None): Unit = self.withScope { ........ // Use configured output committer if already set
if (conf.getOutputCommitter == null) {
hadoopConf.setOutputCommitter(classOf[FileOutputCommitter])
} ........ }

问题就出在了 Hadoop 2.x 的 FileOutputCommitter 实现,FileOutputCommitter 里面有两个值得注意的方法:commitTask 和 commitJob。在 Hadoop 2.x 的FileOutputCommitter 实现里面,mapreduce.fileoutputcommitter.algorithm.version 参数控制着 commitTask 和 commitJob 的工作方式。具体代码如下:

public void commitTask(TaskAttemptContext context, Path taskAttemptPath)
throws IOException { ........ if (taskAttemptDirStatus != null) {
if (algorithmVersion == 1) {
Path committedTaskPath = getCommittedTaskPath(context);
if (fs.exists(committedTaskPath)) {
if (!fs.delete(committedTaskPath, true)) {
throw new IOException("Could not delete " + committedTaskPath);
}
}
if (!fs.rename(taskAttemptPath, committedTaskPath)) {
throw new IOException("Could not rename " + taskAttemptPath + " to "
+ committedTaskPath);
}
LOG.info("Saved output of task '" + attemptId + "' to " +
committedTaskPath);
} else {
// directly merge everything from taskAttemptPath to output directory
mergePaths(fs, taskAttemptDirStatus, outputPath);
LOG.info("Saved output of task '" + attemptId + "' to " +
outputPath);
}
} else {
LOG.warn("No Output found for " + attemptId);
}
} else {
LOG.warn("Output Path is null in commitTask()");
}
} public void commitJob(JobContext context) throws IOException {
........
jobCommitNotFinished = false;
........
} protected void commitJobInternal(JobContext context) throws IOException {
........
if (algorithmVersion == 1) {
for (FileStatus stat: getAllCommittedTaskPaths(context)) {
mergePaths(fs, stat, finalOutput);
}
}
........
}

大家可以看到 commitTask 方法里面,有个条件判断 algorithmVersion == 1,这个就是 mapreduce.fileoutputcommitter.algorithm.version 参数的值,默认为1;如果这个参数为1,那么在 Task 完成的时候,是将 Task 临时生成的数据移到 task 的对应目录下,然后再在 commitJob 的时候移到最终作业输出目录,而这个参数,在 Hadoop 2.x 的默认值就是 1!这也就是为什么我们看到 job 完成了,但是程序还在移动数据,从而导致整个作业尚未完成,而且最后是由 Spark 的 Driver 执行 commitJob 函数的,所以执行的慢也是有到底的。

而我们可以看到,如果我们将 mapreduce.fileoutputcommitter.algorithm.version 参数的值设置为 2,那么在 commitTask 执行的时候,就会调用 mergePaths 方法直接将 Task 生成的数据从 Task 临时目录移动到程序最后生成目录。而在执行 commitJob 的时候,直接就不用移动数据了,自然会比默认的值要快很多。

注意,其实在 Hadoop 2.7.0 之前版本,我们可以将 mapreduce.fileoutputcommitter.algorithm.version 参数设置为非1的值就可以实现这个目的,因为程序里面并没有限制这个值一定为2,。不过到了 Hadoop 2.7.0,mapreduce.fileoutputcommitter.algorithm.version 参数的值必须为1或2。

问题已经找到了,我们可以在程序里面解决这个问题。有以下几种方法:

  • 直接在 conf/spark-defaults.conf 里面设置 spark.hadoop.mapreduce.fileoutputcommitter.algorithm.version 2,这个是全局影响的。
  • 直接在 Spark 程序里面设置,spark.conf.set("mapreduce.fileoutputcommitter.algorithm.version", "2"),这个是作业级别的。
  • 如果你是使用 Dataset API 写数据到 HDFS,那么你可以这么设置 dataset.write.option("mapreduce.fileoutputcommitter.algorithm.version", "2")

不过如果你的 Hadoop 版本为 3.x,mapreduce.fileoutputcommitter.algorithm.version 参数的默认值已经设置为2了

因为这个参数对性能有一些影响,所以到了 Spark 2.2.0,这个参数已经记录在 Spark 配置文档里面了 configuration.html

Spark 2.x 在作业完成时却花费很长时间结束的更多相关文章

  1. Fragment放置后台很久(Home键退出很长时间),返回时出现Fragment重叠解决方案

    后来在google查到相关资料,原因是:当Fragment长久不使用,系统进行回收,FragmentActivity调用onSaveInstanceState保存Fragment对象.很长时间后,再次 ...

  2. Git Compare with base,比较大文件时,长时间等待,无法加载

    问题 当使用Git比较一个大文件(几十兆数量级)版本见差异时,会一直等待加载,且内存消耗很大,导致其他进程很难执行.任务管理器中,可以看到此时的TortoiseGitMerge吃掉3G左右的内存. 原 ...

  3. Spark学习之路(五)—— Spark运行模式与作业提交

    一.作业提交 1.1 spark-submit Spark所有模式均使用spark-submit命令提交作业,其格式如下: ./bin/spark-submit \ --class <main- ...

  4. Spark 系列(五)—— Spark 运行模式与作业提交

    一.作业提交 1.1 spark-submit Spark 所有模式均使用 spark-submit 命令提交作业,其格式如下: ./bin/spark-submit \ --class <ma ...

  5. 入门大数据---Spark部署模式与作业提交

    一.作业提交 1.1 spark-submit Spark 所有模式均使用 spark-submit 命令提交作业,其格式如下: ./bin/spark-submit \ --class <ma ...

  6. 导入spark程序的maven依赖包时,无法导入,报错Unable to import maven project: See logs for details

    问题:导入spark程序的maven依赖包时,无法导入,且报错:0:23 Unable to import maven project: See logs for details 2019-08-23 ...

  7. Spark为什么只有在调用action时才会触发任务执行呢(附算子优化和使用示例)?

    Spark算子主要划分为两类:transformation和action,并且只有action算子触发的时候才会真正执行任务.还记得之前的文章<Spark RDD详解>中提到,Spark ...

  8. jquery.datetimepicker.js 当鼠标离开时,不选中当前时间,以达到清空的目的

    validateOnBlur:true    当鼠标离开时,不选中当前时间,以达到清空的目的 使用方法:   // 时间设置         $('#BankProduct_sale_begin'). ...

  9. SpringBoot项目启动时链接数据库很慢

    SpringBoot项目启动时链接数据库很慢 springboot项目在启动时候,如下图所示,链接数据库很慢 解决方法:在mysql 的配置文件中 配置 skip-name-resolve

随机推荐

  1. 《精通iOS开发》书籍目录

    1.欢迎来到iOS和Swift世界 2.创建一个新项目 3.实现基本交互 4.更丰富的用户界面 5.自动旋转和自动调整大小 6.多视图应用 7.分页栏与选取器 8.表视图简介 9.导航控制器和表视图 ...

  2. linux上实现jmeter分布式压力测试(转)

    摘要:最近根据公司工作的需求,学习了一些压力测试的知识,目前,公司使用的是jmeter进行压力测试.下面就记录下近期的学习.我想将这次的博文分成三个部分:1.开始测试前的准备(测试环境的搭建)2.在一 ...

  3. (3)LoraWAN:链路控制、SF BW CR

    三.Introduction on LoRaWAN options 本文件描述了一种用于可为移动的或固定在一个固定位置的电池供电的终端设备而优化的LoRaWAN™网络协议.LORA™是一个由Semte ...

  4. Linux centosVMware vim 编辑模式、vim命令模式、vim实践

    一.编辑模式.命令模式 在一般模式下输入:或/可进入命令模式.在该模式下可进行走索某个字符或字符串,也可保存.替换.退出.显示行号等. /word:在光标之后查找一个字符串word,按n向后继续搜索 ...

  5. ch4 背景图像基础

    如果希望网站有一个好看的背景,只需将背景应用于主体元素,即在body上应用background-image,默认情况下浏览器水平和垂直的重复显示背景图像,让图像平铺在整个页面上,可以选择背景图像是垂直 ...

  6. BSD socket编程学习

    1.socket简介 BSD是实现TCP/IP协议通信的软件系统,socket是应用编程接口,为app提供使用TCP/IP协议通信的接口. 网络层IP提供点到点服务(IP地址标识),传输层TCP和UD ...

  7. 02.python实现排序算法

    一.列表排序 将无序列表变为有序列表 应用场景: 榜单,表格, 给二分查找用,给其他算法用 二.python实现三种简单排序算法 时间复杂度O(n^2), 空间O(1) 1.冒泡排序 思路: 列表每两 ...

  8. Spring JMSTemplate 与 JMS 原生API比较

    博客分类: JMS Spring 2.x   JMSUtil与Spring JmsTemplate的对比 Author:信仰 Date:2012-4-20 未完待续,截止日期2012-4-20 从以下 ...

  9. Ubuntu18.04 ElasticSearch7.3.2集群搭建(一)

    集群规划: Hostname Elasticsearch Kibana Marvel Marvel Client node01 √ √ √ √ node02 √ √ node03 √ √ node04 ...

  10. JuJu团队1月2号工作汇报

    JuJu团队1月2号工作汇报 JuJu   Scrum 团队成员 今日工作 剩余任务 困难 飞飞 -- 测试dataloader 无 婷婷 调试代码 提升acc 无 恩升 -- 测试dataloade ...