获取任务节点上执行程序的核心数的方法?

时间:2017-07-20 04:59:12

标签: multithreading scala apache-spark distributed-computing

E.g。我需要获得所有可用执行程序及其各自的多线程容量的列表(不是总多线程容量,sc.defaultParallelism已经处理过)。

由于此参数与实现有关(YARN和spark-standalone具有不同的分配核心策略)和情境(由于动态分配和长期作业运行,它可能会波动)。我不能用其他方法估计这个。有没有办法在分布式转换中使用Spark API检索此信息? (例如,TaskContext,SparkEnv)

UPDATE 至于Spark 1.6,我尝试了以下方法:

1)运行包含多个分区的一阶段作业(>> defaultParallelism)并计算每个executorID的独特threadID数量:

val n = sc.defaultParallelism * 16
sc.parallelize(n, n).map(v => SparkEnv.get.executorID -> Thread.currentThread().getID)
.groupByKey()
.mapValue(_.distinct)
.collect()

然而,这会导致估计高于实际多线程容量,因为每个Spark执行程序都使用过度配置的线程池。

2)类似于1,除了n = defaultParallesim,并且在每个任务中我都添加了延迟以防止资源协商器出现不平衡的分片(快速节点完成它的任务并在慢节点启动之前请求更多运行):

val n = sc.defaultParallelism
sc.parallelize(n, n).map{
  v =>
    Thread.sleep(5000)
    SparkEnv.get.executorID -> Thread.currentThread().getID
}
.groupByKey()
.mapValue(_.distinct)
.collect()

它在大多数情况下都有效,但速度远远超过必要的速度,可能会被非常不平衡的集群或任务推测所打破。

3)我没有尝试过:使用java反射来读取BlockManager.numUsableCores,这显然不是一个稳定的解决方案,内部实现可能随时改变。

请告诉我你是否找到了更好的东西。

2 个答案:

答案 0 :(得分:1)

Spark rest API非常简单。您必须获得应用程序ID:

val applicationId = spark.sparkContext.applicationId

ui网址:

val baseUrl = spark.sparkContext.uiWebUrl

和查询:

val url = baseUrl.map { url => 
  s"${url}/api/v1/applications/${applicationId}/executors"
}

使用Apache HTTP库(已经在Spark依赖项中,改编自https://alvinalexander.com/scala/scala-rest-client-apache-httpclient-restful-clients):

import org.apache.http.impl.client.DefaultHttpClient
import org.apache.http.client.methods.HttpGet
import scala.util.Try

val client = new DefaultHttpClient()

val response = url
  .flatMap(url => Try{client.execute(new HttpGet(url))}.toOption)
  .flatMap(response => Try{
    val s = response.getEntity().getContent()
    val json = scala.io.Source.fromInputStream(s).getLines.mkString
    s.close
    json
  }.toOption)

和json4s:

import org.json4s._
import org.json4s.jackson.JsonMethods._
implicit val formats = DefaultFormats

case class ExecutorInfo(hostPort: String, totalCores: Int)

val executors: Option[List[ExecutorInfo]] = response.flatMap(json => Try {
  parse(json).extract[List[ExecutorInfo]]
}.toOption)

只要您保留应用程序ID和ui URL并将ui端口打开到外部连接,您就可以从任何任务中执行相同的操作。

答案 1 :(得分:1)

我会尝试以类似于Web UI的方式实现SparkListenerThis code可能会有所帮助。