Spark java.lang.OutOfMemoryError: пространство кучи Java

Мой кластер: 1 мастер, 11 подчиненных устройств, каждый node имеет 6 ГБ памяти.

Мои настройки:

spark.executor.memory=4g, Dspark.akka.frameSize=512

Вот проблема:

Сначала, я прочитал некоторые данные (2,19 ГБ) с HDFS на RDD:

val imageBundleRDD = sc.newAPIHadoopFile(...)

Второй, сделайте что-нибудь на этом RDD:

val res = imageBundleRDD.map(data => {
                               val desPoints = threeDReconstruction(data._2, bg)
                                 (data._1, desPoints)
                             })

Последний, вывод в HDFS:

res.saveAsNewAPIHadoopFile(...)

Когда я запускаю свою программу, он показывает:

.....
14/01/15 21:42:27 INFO cluster.ClusterTaskSetManager: Starting task 1.0:24 as TID 33 on executor 9: Salve7.Hadoop (NODE_LOCAL)
14/01/15 21:42:27 INFO cluster.ClusterTaskSetManager: Serialized task 1.0:24 as 30618515 bytes in 210 ms
14/01/15 21:42:27 INFO cluster.ClusterTaskSetManager: Starting task 1.0:36 as TID 34 on executor 2: Salve11.Hadoop (NODE_LOCAL)
14/01/15 21:42:28 INFO cluster.ClusterTaskSetManager: Serialized task 1.0:36 as 30618515 bytes in 449 ms
14/01/15 21:42:28 INFO cluster.ClusterTaskSetManager: Starting task 1.0:32 as TID 35 on executor 7: Salve4.Hadoop (NODE_LOCAL)
Uncaught error from thread [spark-akka.actor.default-dispatcher-3] shutting down JVM since 'akka.jvm-exit-on-fatal-error' is enabled for ActorSystem[spark]
java.lang.OutOfMemoryError: Java heap space

Слишком много задач?

PS: все в порядке, когда входные данные составляют около 225 МБ.

Как я могу решить эту проблему?

Ответ 1

У меня есть несколько предложений:

  • Если ваши узлы настроены на максимум 6 г для Spark (и немного уходят на другие процессы), используйте 6g, а не 4g, spark.executor.memory=6g. Убедитесь, что вы используете как можно больше памяти, проверив интерфейс (он скажет, сколько мемов вы используете)
  • Попробуйте использовать больше разделов, у вас должно быть 2 - 4 на процессор. IME, увеличивающее количество разделов, часто является самым простым способом сделать программу более стабильной (и часто быстрее). Для огромных объемов данных вам может понадобиться более 4-х процессоров, поэтому в некоторых случаях мне пришлось использовать 8000 разделов!
  • Уменьшите долю памяти, зарезервированную для кеширования, используя spark.storage.memoryFraction. Если вы не используете cache() или persist в своем коде, это может быть равно 0. По умолчанию это значение равно 0.6, что означает, что вы получаете только 0,4 * 4g памяти для своей кучи. IME, уменьшающий память, часто заставляет OOM уходить. ОБНОВЛЕНИЕ: Из искры 1.6, по-видимому, нам больше не нужно будет играть с этими значениями, искру определит их автоматически.
  • Аналогично выше, но доля памяти в случайном порядке. Если ваша работа не нуждается в большой памяти в случайном порядке, установите ее на более низкое значение (это может привести к переполнению ваших тасований на диск, которые могут иметь катастрофическое влияние на скорость). Иногда, когда это операция в случайном порядке, что OOMing вам нужно сделать наоборот, то есть установите ее на что-то большое, например 0,8, или убедитесь, что вы разрешаете перетасовку на диск (это значение по умолчанию с 1.0.0).
  • Следите за утечками памяти, это часто вызвано случайным закрытием объектов, которые вам не нужны в ваших lambdas. Способ диагностики заключается в том, чтобы следить за "задачей, сериализованной как XXX байты" в журналах, если XXX больше, чем несколько килобайт или более, чем МБ, может возникнуть утечка памяти. См. fooobar.com/questions/33365/...
  • Относительно выше; используйте широковещательные переменные, если вам действительно нужны большие объекты.
  • Если вы кешируете большие RDD и можете пожертвовать некоторым временем доступа, подумайте о сериализации RDD http://spark.apache.org/docs/latest/tuning.html#serialized-rdd-storage. Или даже кэширование их на диске (что иногда не так уж плохо, если вы используете SSD).
  • (Дополнительно). Связано с выше, избегайте String и сильно вложенных структур (например, Map и вложенных классов классов). Если возможно, попробуйте использовать только примитивные типы и индексировать все непримитивы, особенно если вы ожидаете много дубликатов. Выберите WrappedArray по вложенным структурам, когда это возможно. Или даже разверните свою собственную сериализацию - у вас будет самая большая информация о том, как эффективно поддерживать ваши данные в байтах, ИСПОЛЬЗОВАТЬ ЭТО!
  • (бит hacky). Снова при кешировании рассмотрите возможность использования Dataset для кэширования вашей структуры, поскольку она будет использовать более эффективную сериализацию. Это следует рассматривать как взлом по сравнению с предыдущим пунктом. Построение знаний вашего домена в вашем алгоритме/сериализации может свести к минимуму объем памяти/кеш-пространства на 100x или 1000x, тогда как все a Dataset, скорее всего, дадут 2x - 5x в памяти и 10x сжатый (паркет) на диске.

http://spark.apache.org/docs/1.2.1/configuration.html

EDIT: (Так что я могу сделать проще Google). Ниже также указывается следующая проблема:

java.lang.OutOfMemoryError : GC overhead limit exceeded

Ответ 2

Чтобы добавить к этому вариант использования, который часто не обсуждается, я буду представлять решение при отправке приложения Spark через spark-submit в локальном режиме.

В соответствии с gitbook Освоение Apache Spark Яцек Ласковски:

Вы можете запустить Spark в локальном режиме. В этом нераспределенном режиме развертывания с одним JVM Spark генерирует все компоненты исполнения - драйвер, исполнитель, бэкэнд и мастер - в той же JVM. Это единственный режим, когда драйвер используется для выполнения.

Таким образом, если вы испытываете ошибки OOM с помощью heap, достаточно скорректировать driver-memory, а не executor-memory.

Вот пример:

spark-1.6.1/bin/spark-submit
  --class "MyClass"
  --driver-memory 12g
  --master local[*] 
  target/scala-2.10/simple-project_2.10-1.0.jar 

Ответ 3

Посмотрите скрипты запуска, там установлен размер кучи Java, похоже, что вы не устанавливаете это перед запуском Spark работник.

# Set SPARK_MEM if it isn't already set since we also use it for this process
SPARK_MEM=${SPARK_MEM:-512m}
export SPARK_MEM

# Set JAVA_OPTS to be able to load native libraries and to set heap size
JAVA_OPTS="$OUR_JAVA_OPTS"
JAVA_OPTS="$JAVA_OPTS -Djava.library.path=$SPARK_LIBRARY_PATH"
JAVA_OPTS="$JAVA_OPTS -Xms$SPARK_MEM -Xmx$SPARK_MEM"

Вы можете найти документацию для развертывания скриптов здесь.

Ответ 4

Вам следует увеличить память драйвера. Думаю, в вашей папке $SPARK_HOME/conf вы должны найти файл spark-defaults.conf, отредактировать и установить spark.driver.memory 4000m в зависимости от памяти вашего хозяина. Это то, что исправило проблему для меня, и все работает плавно

Ответ 5

Вы должны настроить параметры памяти offHeap, как показано ниже:

val spark = SparkSession
     .builder()
     .master("local[*]")
     .config("spark.executor.memory", "70g")
     .config("spark.driver.memory", "50g")
     .config("spark.memory.offHeap.enabled",true)
     .config("spark.memory.offHeap.size","16g")   
     .appName("sampleCodeForReference")
     .getOrCreate()

Предоставьте память водителя и исполнителя в соответствии с доступностью оперативной памяти вашей машины. Вы можете увеличить размер offHeap, если вы все еще сталкиваетесь с проблемой OutofMemory.

Ответ 6

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

Но правда в том, что динамическое распределение ресурсов не устанавливает память драйвера и сохраняет ее по умолчанию, равную 1g.

Я решил эту проблему, установив spark.driver.memory в число, соответствующее памяти моего драйвера (для оперативной памяти 32 ГБ я установил 18 ГБ)

Вы можете установить его, используя команду spark submit:

spark-submit --conf spark.driver.memory=18gb ....cont

Очень важное примечание, это свойство не будет учитываться, если вы установите его из кода, в соответствии с документацией spark:

Свойства Spark в основном можно разделить на два вида: один относится к развертыванию, например "spark.driver.memory", "spark.executor.instances", на этот тип свойств нельзя повлиять при программной настройке через SparkConf во время выполнения или поведение зависит от того, какой менеджер кластера и режим развертывания вы выберете, поэтому было бы предложено установить его через конфигурационный файл или параметры командной строки spark-submit; другой в основном связан с управлением во время выполнения Spark, например "spark.task.maxFailures", этот тип свойств может быть установлен любым способом.

Ответ 7

В широком смысле, искры памяти JVM Executor можно разделить на две части. Spark memory и User memory. Это контролируется свойством spark.memory.fraction - значение находится между 0 и 1. При работе с изображениями или при интенсивной обработке памяти в искровых приложениях рассмотрите возможность уменьшения значения spark.memory.fraction. Это сделает больше памяти доступной для вашей работы приложения. Spark может разливаться, поэтому он будет работать с меньшим объемом памяти.

Вторая часть проблемы - разделение работы. Если возможно, разделите свои данные на более мелкие куски. Для меньших данных, возможно, требуется меньше памяти. Но если это невозможно, вы жертвоприносите на память. Обычно один исполнитель будет запускать несколько ядер. Общая память исполнителей должна быть достаточной для удовлетворения требований к памяти всех параллельных задач. Если увеличение памяти исполнителя не является вариантом, вы можете уменьшить количество ядер на каждого исполнителя, чтобы каждая задача получала больше памяти для работы. Тест с 1 основным исполнителем, который имеет наибольшую возможную память, которую вы можете дать, а затем продолжать увеличивать ядра, пока не найдете лучший подсчет ядра.

Ответ 8

Вы сбросили свой главный журнал gc? Поэтому я столкнулся с подобной проблемой и обнаружил, что SPARK_DRIVER_MEMORY устанавливает только кучу Xmx. Первоначальный размер кучи остается 1 ГБ, а размер кучи никогда не увеличивается до кучи Xmx.

Передача "--conf" spark.driver.extraJavaOptions = -Xms20g "решает мою проблему.

PS Aux | grep java и вы увидите следующий журнал: =

24501 30,7 1,7 41782944 2318184 баллов /0 Sl+ 18:49 0:33/usr/java/последний /bin/java -cp/opt/spark/conf/: /opt/spark/jars/* -Xmx30g -Xms20g

Ответ 9

Местоположение для установки размера кучи памяти (по крайней мере, в искро-1.0.0) находится в conf/spark-env. Соответствующими переменными являются SPARK_EXECUTOR_MEMORY и SPARK_DRIVER_MEMORY. Дополнительные документы находятся в руководстве по развертыванию

Кроме того, не забудьте скопировать файл конфигурации во все подчиненные узлы.

Ответ 10

У меня есть несколько предложений для вышеупомянутой ошибки.

● Убедитесь, что память исполнителя, назначенная исполнителю, может иметь дело с разделами, требующими больше памяти, чем назначено.

● Попытайтесь выяснить, работает ли больше тасов, поскольку тасования являются дорогостоящими операциями, поскольку они включают дисковый ввод-вывод, сериализацию данных и сетевой ввод-вывод.

● использовать широковещательные соединения

● Избегайте использования groupByKeys и попробуйте заменить на ReduceByKey

● Избегайте использования огромных Java-объектов везде, где происходит перетасовка

Ответ 11

Исходя из моего понимания приведенного выше кода, он загружает файл, выполняет операцию отображения и сохраняет его обратно. Там нет операции, которая требует перемешивания. Кроме того, не существует операции, требующей передачи данных в драйвер, поэтому настройка всего, что связано с тасованием или приводом, может не повлиять. Драйвер действительно имеет проблемы, когда задач слишком много, но это было только до версии Spark 2.0.2. Там может быть две вещи, которые идут не так, как надо.

  • Есть только один или несколько исполнителей. Увеличить количество исполнителей, чтобы их можно было распределять по разным рабам. Если вы используете пряжу, необходимо изменить конфигурацию num-executors или если вы используете отдельную версию spark, то вам нужно настроить num ядер для каждого исполнителя и conf max max cores conf. В автономном num executors = максимум ядер/ядер на исполнителя.
  • Количество разделов очень мало или, может быть, только один. Таким образом, если этот уровень низкий, даже если у нас многоядерные многоэксплуатационные системы, это не сильно поможет, поскольку распараллеливание зависит от количества разделов. Так что увеличьте разделы, выполнив imageBundleRDD.repartition(11)