Performance 如何在Spark Streaming应用程序中异步写入行以加速批处理执行?
我有一个spark工作,需要在每个微批处理中编写SQL查询的输出。写操作的性能非常昂贵,导致批处理执行时间超过批处理间隔 我正在寻找提高write性能的方法Performance 如何在Spark Streaming应用程序中异步写入行以加速批处理执行?,performance,apache-spark,apache-spark-sql,spark-streaming,Performance,Apache Spark,Apache Spark Sql,Spark Streaming,我有一个spark工作,需要在每个微批处理中编写SQL查询的输出。写操作的性能非常昂贵,导致批处理执行时间超过批处理间隔 我正在寻找提高write性能的方法 在单独的线程中异步执行写操作(如下图所示)是一个好的选择吗 这会因为Spark本身以分布式方式执行而导致任何副作用吗 是否有其他/更好的方法加快写作速度 // Create a fixed thread pool to execute asynchronous tasks val executorService = Executors.ne
// Create a fixed thread pool to execute asynchronous tasks
val executorService = Executors.newFixedThreadPool(2)
dstream.foreachRDD { rdd =>
import org.apache.spark.sql._
val spark = SparkSession.builder.config(rdd.sparkContext.getConf).getOrCreate
import spark.implicits._
import spark.sql
val records = rdd.toDF("record")
records.createOrReplaceTempView("records")
val result = spark.sql("select * from records")
// Submit a asynchronous task to write
executorService.submit {
new Runnable {
override def run(): Unit = {
result.write.parquet(output)
}
}
}
}
SparkContext
是线程安全的,可促进此类查询执行
是否有其他/更好的方法加快写作速度
// Create a fixed thread pool to execute asynchronous tasks
val executorService = Executors.newFixedThreadPool(2)
dstream.foreachRDD { rdd =>
import org.apache.spark.sql._
val spark = SparkSession.builder.config(rdd.sparkContext.getConf).getOrCreate
import spark.implicits._
import spark.sql
val records = rdd.toDF("record")
records.createOrReplaceTempView("records")
val result = spark.sql("select * from records")
// Submit a asynchronous task to write
executorService.submit {
new Runnable {
override def run(): Unit = {
result.write.parquet(output)
}
}
}
}
对!!这是理解何时使用其他(以上)选项的关键。默认情况下,Spark应用程序以FIFO调度模式运行
引述:
默认情况下,Spark的调度程序以FIFO方式运行作业。每个作业分为“阶段”(例如,映射和缩减阶段),第一个作业在所有可用资源上获得优先级,而其阶段有任务要启动,然后第二个作业获得优先级,等等。如果队列前端的作业不需要使用整个集群,则以后的作业可以立即开始运行,但是,如果队列最前面的作业很大,则后面的作业可能会显著延迟
从Spark 0.8开始,还可以配置作业之间的公平共享。在公平共享下,Spark以“循环”方式在作业之间分配任务,以便所有作业获得大致相等的集群资源份额。这意味着在长作业运行时提交的短作业可以立即开始接收资源,并且仍然可以获得良好的响应时间,而无需等待长作业完成。此模式最适合多用户设置
这意味着要为异步并行执行多个写入留出空间,您应该将Spark应用程序配置为使用公平调度模式(使用Spark.scheduler.mode
属性)
您必须将所谓的“分区”执行器资源(CPU和内存)配置到池中,您可以使用spark.scheduler.pool
属性将这些资源分配给作业
引述:
在没有任何干预的情况下,新提交的作业将进入默认池,但是可以通过向提交作业的线程中的SparkContext添加spark.scheduler.pool
“本地属性”来设置作业池
1-在单独的线程中异步执行写操作(如下图所示)是一个好选项吗? 不,理解这个问题的关键是问“谁在写”。写入操作是由为集群中的执行器上的作业分配的资源完成的。将write命令放置在异步线程池上,就像向具有固定员工的办公室添加新的办公室管理器一样。考虑到两名经理必须共用同一名员工,他们是否能够比一名经理做更多的工作?嗯,一个合理的答案是“只有当第一个经理没有给他们足够的工作,所以有一些自由的能力” 回到我们的集群,我们正在处理一个写操作,这对IO来说是一个沉重的负担。并行化写作业将导致IO资源争用,使每个独立作业更长。起初,我们的工作看起来可能比“单一管理者版本”更好,但麻烦最终会降临到我们身上。 我制作了一张图表,试图说明它是如何工作的。请注意,并行作业所花费的时间将与它们在时间轴中并发的时间量成比例增加 一旦我们达到工作开始延迟的程度,我们就有了一份不稳定的工作,最终会失败 2-这会因为Spark本身以分布式方式执行而导致任何副作用吗? 我能想到的一些影响:
- 可能更高的集群负载和IO争用
- 作业在线程池队列而不是Spark流队列上排队。我们失去了通过Spark UI和监控API监控工作的能力,因为延迟是“隐藏的”,从Spark流的角度来看一切都很好
- 如果要附加到拼花地板文件,请经常创建新文件。随着时间的推移,追加成本越来越高
- 增加批处理间隔或使用窗口操作写入较大的拼花地板块。拼花地板喜欢大锉刀
- 调整数据的分区和分布=>确保Spark可以并行写入
- 增加群集资源,必要时添加更多节点
- 使用更快的存储