从驱动程序同时运行几个spark任务

时间:2017-09-16 09:08:41

标签: apache-spark

想象一下,我们有3个客户,我们希望并行地为每个客户做同样的工作。

def doSparkJob(customerId: String) = {
  spark
    .read.json(s"$customerId/file.json")
    .map(...)
    .reduceByKey(...)
    .write
    .partitionBy("id")
    .parquet("output/")
}

我们同时这样做(来自火花司机):

val jobs: Future[(Unit, Unit, Unit)] = for {
  f1 <- Future { doSparkJob("customer1") }
  f2 <- Future { doSparkJob("customer1") }
  f3 <- Future { doSparkJob("customer1") }
} yield (f1, f2, f3)

Await.ready(jobs, 5.hours)

我是否理解这是不好的做法?许多火花工作将从执行者推出彼此的背景,并且将出现许多溢出数据到光盘。如何通过并行作业管理执行任务的火花?当我们有一个驱动程序的3个并发作业和只有3个具有一个核心的执行程序时,如何出现shuffle。

我想,一个好的方法应该是这样的: 我们一起为所有客户groupByKey读取所有数据并做我们想做的事情。

1 个答案:

答案 0 :(得分:2)

  

我是否理解这是不好的做法?

不一定。很大程度上取决于上下文,Spark实现了它自己的AsyncRDDActions集来解决这样的场景(尽管没有Dataset等价物。)

在最简单的情况下,使用静态分配,由于缺乏资源,Spark很可能会按顺序安排所有作业。除非另外配置,否则这是所描述配置的最可能结果。请记住,Spark可以使用FAIR调度程序进行应用程序内调度,以在多个并发作业之间共享有限的资源。请参阅Scheduling Within an Application

如果资源量足以同时启动多个作业,则各个作业之间可能存在竞争,尤其是IO和内存密集型作业。如果所有作业都使用相同的资源(尤其是数据库),则Spark可能会导致限制和后续失败或超时。运行多个作业的不太严重的影响可能会增加缓存驱逐。

总体而言,当您在顺序执行和并发执行之间选择时,需要考虑多个因素,包括但不限于可用资源(Spark集群和外部服务),API的选择(RDD往往比SQL更贪婪,因此需要一些低级管理)和运营商的选择。即使作业是顺序的,您仍然可以决定使用异步来提高驱动程序利用率并减少延迟。这对Spark SQL和复杂的执行计划(Spark SQL中的常见瓶颈)特别有用。通过这种方式,Spark可以处理新的执行计划,同时执行其他任务。