如何按一定顺序处理多个纱线作业?

时间:2017-05-04 20:45:22

标签: scala apache-spark yarn

我以下列方式提交多个火花工作 -

someCollection.foreach(m => {
    ..some code
    sparkSubmitClass.run(m.name)
    .. some code
})

其中sparkSubmitClass.run()方法基本上使用具有$ SPARK_HOME / bin / spark-submit和其他相关参数的shell脚本。

问题在于此代码一次性提交所有火花作业。我想要实现的是 - 提交一份工作,然后只有在较早的工作完成时提交另一份工作。这是因为someCollection是有序的,下一个作业依赖于前一个作业创建的数据。

sparkSubmitClass.run()位于以下行 -

def run(appName: String)(implicit executionContext: ExecutionContext) = {
val command = s"sparkJob.sh $appName"
val processBuilder = Process(command)
val pio = new ProcessIO(_ => (),
  stdout => {
    scala.io.Source.fromInputStream(stdout)
      .getLines.foreach(str => log.info(s"spark-submit: Application 
       Name=$appName stdout='${str.replace("'", "\\'")}'"))
  },
  stderr => {
    val lines = scala.io.Source.fromInputStream(stderr).getLines().toBuffer
    lines.foreach(str => log.info(s"spark-submit: Application Name=$appName 
        stderr='${str.replace("'", "\\'")}'"))
    lines.flatMap(parseLineForApplicationUrl).headOption.foreach(appId => 
     appId)
  })

  val process = processBuilder.run(pio)
  val exitVal = process.exitValue() //returns 0 as soon as application is 
  submitted
}

sparkJob.sh基本上是 -

MAIN_CLASS="com.SomeClassHavingRDDAndHiveOperations"
APPNAME=$1

JAVA_OPTS="-XX:MaxDirectMemorySize=$WORKER_DIRECT_MEM_SIZE -
XX:+HeapDumpOnOutOfMemoryError -Djava.net.preferIPv4Stack=true"

SPARK_HOME="/usr/lib/spark"
cmd='$SPARK_HOME/bin/spark-submit --class $MAIN_CLASS 
--name ${APPNAME}
--conf "spark.yarn.submit.waitAppCompletion=false"
--conf "spark.io.compression.codec=snappy"
--conf "spark.kryo.unsafe=true"
--conf "spark.kryoserializer.buffer.max=1024m"
--conf "spark.serializer=org.apache.spark.serializer.KryoSerializer"
--driver-java-options "-XX:MaxMetaspaceSize=$WORKER_PERM_SIZE $JAVA_OPTS"
$appdir/SomeJar.jar $APPNAME'

eval $cmd

有关如何构建此类订购的任何想法?

1 个答案:

答案 0 :(得分:1)

而不是编写bash scripts并调用每个作业并浪费io /读写阶段,而不是在代码中根据需要循环作业。
这里有一些提示供你遵循:
首先,您必须确保拥有interface,然后对要按顺序处理的每个interface实施class,以便您可以使用method开始每个工作。 (在此示例中,方法为进程,界面为 JobInterface
然后,您需要使用所需的顺序将所有class-names-with-package写入一个文件中。假设该文件为orderedJobs(您不需要提及扩展名)

package1.Class1
package1.Class2
package2.Class3
....

读取并解析该文件。我假设它在resouces文件夹中,你可以过滤你不想要的行

val classCall = Source.fromInputStream(getClass.getResourceAsStream(<locationOforderedJobs>)).getLines().filter(!_.startsWith("#"))

为每个类循环foreach并调用定义的公共方法(process

classCall.foreach(job => {
    processJob(job).process(<you can pass arguments>)
}

processJobfuntion,您可以在其中实例化每个类

def processJob(name: String): JobInterface = {
    val action = Class.forName("<package path from source root>"+className).newInstance()
    action.asInstanceOf[JobInterface]
  }

通过这种方式,您可以减少io /读写时间浪费,通过在内存中存储其他作业的有用数据来提高火花处理效率,缩短处理时间等等...... <登记/> 我希望它有所帮助