it-roy-ru.com

Почему так много задач в моей искровой работе? Получение 200 заданий по умолчанию

У меня есть работа spark, которая берет файл с 8 записями из hdfs, выполняет простое агрегирование и сохраняет его обратно в hdfs. Я замечаю, что когда я делаю это, у меня сотни задач. 

Я также не уверен, почему есть несколько рабочих мест для этого? Я думал, что работа больше похожа на действие. Я могу предположить, почему, но, насколько я понимаю, внутри этого кода это должна быть одна работа, и она должна быть разбита на этапы, а не несколько работ. Почему это не просто разбить его на этапы, почему это разбивается на рабочие места?

Что касается задач «200 плюс», так как объем данных и количество узлов незначительны, не имеет смысла, что для каждой строки данных существует примерно 25 задач, когда есть только одна агрегация и пара фильтров. Почему бы не иметь одну задачу на раздел на атомарную операцию?

Вот соответствующий код скалы - 

import org.Apache.spark.sql._
import org.Apache.spark.sql.types._
import org.Apache.spark.SparkContext._
import org.Apache.spark.SparkConf

object TestProj {object TestProj {
  def main(args: Array[String]) {

    /* set the application name in the SparkConf object */
    val appConf = new SparkConf().setAppName("Test Proj")

    /* env settings that I don't need to set in REPL*/
    val sc = new SparkContext(appConf)
    val sqlContext = new SQLContext(sc)
    import sqlContext.implicits._

    val rdd1 = sc.textFile("hdfs://node002:8020/flat_files/miscellaneous/ex.txt")

     /*the below rdd will have schema defined in Record class*/
     val rddCase =  sc.textFile("hdfs://node002:8020/flat_files/miscellaneous/ex.txt")
      .map(x=>x.split(" "))    //file record into array of strings based spaces
      .map(x=>Record(
        x(0).toInt,
        x(1).asInstanceOf[String],
        x(2).asInstanceOf[String],
        x(3).toInt))


    /* the below dataframe groups on first letter of first name and counts it*/
    val aggDF = rddCase.toDF()
      .groupBy($"firstName".substr(1,1).alias("firstLetter"))
      .count
      .orderBy($"firstLetter")

    /* save to hdfs*/ 
 aggDF.write.format("parquet").mode("append").save("/raw/miscellaneous/ex_out_agg")

  }

    case class Record(id: Int
      , firstName: String
      , lastName: String
      , quantity:Int)

}

Ниже приведен снимок экрана после нажатия на приложение  enter image description here

Ниже приведены этапы, показываемые при просмотре конкретной «вакансии» с идентификатором 0  enter image description here

Ниже находится первая часть экрана при нажатии на сцену с более чем 200 задачами

 enter image description here

Это вторая часть экрана внутри сцены  enter image description here

Ниже находится после нажатия на вкладку "Исполнители"  enter image description here

По запросу, вот этапы для идентификатора задания 1

 enter image description here

Вот подробности для этапа в задании № 1 с 200 задачами

 enter image description here

16
big_mike_boiii

Это классический вопрос Spark. 

Две задачи, используемые для чтения (Stage Id 0 на втором рисунке), - это настройка defaultMinPartitions, которая установлена ​​на 2. Вы можете получить этот параметр, прочитав значение в REPL sc.defaultMinPartitions. Он также должен отображаться в пользовательском интерфейсе Spark в разделе «Среда». 

Вы можете взглянуть на code из github, чтобы увидеть, что это именно то, что происходит. Если вы хотите, чтобы при чтении использовалось больше разделов, просто добавьте его в качестве параметра, например, sc.textFile("a.txt", 20).

Теперь интересная часть происходит из 200 разделов, которые идут на втором этапе (Id стадии 1 на втором рисунке). Что ж, каждый раз, когда происходит случайное перемешивание, Spark должен решить, сколько разделов будет иметь случайный образ RDD. Как вы можете себе представить, по умолчанию 200. 

Вы можете изменить это, используя:

sqlContext.setConf("spark.sql.shuffle.partitions", "4”)

Если вы запустите свой код с этой конфигурацией, вы увидите, что 200 разделов больше не будет. Как установить этот параметр является искусством. Может быть, выберите 2x количество ядер, которые у вас есть (или что-то еще). 

Я думаю, что в Spark 2.0 есть способ автоматически определить лучшее количество разделов для случайных СДР. С нетерпением жду этого!

Наконец, количество заданий, которые вы получаете, зависит от того, сколько действий RDD было получено в результате оптимизированного кода Dataframe. Если вы читаете спецификации Spark, там написано, что каждое действие RDD будет запускать одно задание. Когда в вашем действии используется Dataframe или SparkSQL, оптимизатор Catalyst определит план выполнения и сгенерирует некоторый код на основе RDD для его выполнения. Трудно сказать точно, почему он использует два действия в вашем случае. Возможно, вам придется взглянуть на оптимизированный план запроса, чтобы увидеть, что именно делает. 

25
marios

У меня похожая проблема. Но в моем сценарии параллелизуемая коллекция содержит меньше элементов, чем количество задач, запланированных Spark (иногда это вызывает странное поведение spark). Используя принудительный номер раздела, я смог решить эту проблему.

Это было что-то вроде этого:

collection = range(10) # In the real scenario it was a complex collection
sc.parallelize(collection).map(lambda e: e + 1) # also a more complex operation in the real scenario

Затем я увидел в журнале Spark:

INFO YarnClusterScheduler: Adding task set 0.0 with 512 tasks
1
Enrique Altuna