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


228

Мой кластер: 1 ведущий, 11 ведомых, каждый узел имеет 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 МБ.

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


как запустить искру? это из консоли? или какие сценарии развертывания вы используете?
Томбарт

Я использую sbt для компиляции и запуска моего приложения. пакет sbt затем запускается sbt. Я реализовал ту же программу в hadoop месяц назад и столкнулся с той же проблемой OutOfMemoryError, но в hadoop ее легко решить, увеличив значение mapred.child.java.opts с Xmx200m до Xmx400m. Есть ли в spark какие-либо настройки jvm для своих задач? Интересно, имеет ли spark.executor.memory такое же значение, как mapred.child.java.opts в hadoop. В моей программе spark.executor.memory уже было установлено значение 4g намного больше, чем Xmx400m в hadoop. Спасибо ~
hequn8128

Три шага, которые вы упоминаете, единственные, которые вы делаете? Каков размер данных, сгенерированных (data._1, desPoints) - это должно уместиться в памяти esp, если эти данные затем перетасовываются на другой этап
Арнон Ротем-Гал-Оз

1
Какая конфигурация памяти для драйвера? Проверьте, на каком сервере произошла ошибка нехватки памяти. Это водитель или один из исполнителей.
Ран

Смотрите здесь все свойства конфигурации: spark.apache.org/docs/2.1.0/configuration.html
Naramsim

Ответы:


364

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

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

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

РЕДАКТИРОВАТЬ: (Так что я могу гуглить себя проще) Следующее также указывает на эту проблему:

java.lang.OutOfMemoryError : GC overhead limit exceeded

Спасибо за ваши предложения ~ Если я установлю spark.executor.memory = 6g, у spark возникнет проблема: «проверьте пользовательский интерфейс кластера, чтобы убедиться, что рабочие зарегистрированы и имеют достаточно памяти». Установка spark.storage.memoryFraction в 0.1 также не может решить проблему. Может быть, проблема заключается в моем коде. Спасибо!
hequn8128

2
@samthebest Это фантастический ответ. Я действительно ценю помощь регистрации для обнаружения утечек памяти.
Майлз Бейкер

1
Привет @ samthebest, как вы указали 8000 разделов? Так как я использую Spark SQL, я могу указать раздел только с помощью spark.sql.shuffle.partitions, значение по умолчанию равно 200, если я установлю его больше, я попытался установить его на 1000, но не помогая получить OOM, вы знаете, что должно быть оптимальным значение раздела У меня есть 1 ТБ искаженных данных для обработки, и это включает групповые запросы улья. Пожалуйста, руководство.
Umesh K

2
Привет @ user449355, пожалуйста, не могли бы вы задать новый вопрос? Из-за боязни начать длинную ветку комментариев :) Если у вас есть проблемы, скорее всего, есть другие люди, и вопрос поможет найти его для всех.
Самбест

1
К вашему первому замечанию, @samthebest, вам не следует использовать ВСЕ память, spark.executor.memoryпотому что вам определенно необходим некоторый объем памяти для накладных расходов ввода-вывода. Если вы используете все это, это замедлит вашу программу. Исключением из этого может быть Unix, в этом случае у вас есть пространство подкачки.
Hunle

58

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

Согласно справочнику « Освоение 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 

Какой процент мы должны учитывать для памяти драйвера в автономном режиме.
Яшвант Камбала

@Brian, в локальном режиме память драйвера должна быть больше размера входных данных? Можно ли указать количество разделов для входного набора данных, чтобы задание Spark могло работать с набором данных, значительно превышающим доступную оперативную память?
Фуи

19

Вы должны настроить параметры памяти 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 .


Добавлена ​​настройка offHeap помогла
кеннют

2
установка памяти драйвера в вашем коде не будет работать, для этого прочитайте документацию по spark: свойства Spark в основном можно разделить на два вида: один относится к развертыванию, например «spark.driver.memory», «spark.executor.instances», На этот тип свойств может не повлиять программная настройка через SparkConf во время выполнения, или же поведение зависит от того, какой менеджер кластера и режим развертывания вы выберете, поэтому будет предложено установить его с помощью файла конфигурации или параметров командной строки spark-submit.
Абдулхафет Сартави

1
ЛУЧШИЙ ОТВЕТ! Моя проблема заключалась в том, что Spark не был установлен на главном узле, я просто использовал PySpark для подключения к HDFS и получил ту же ошибку. Использование configрешило проблему.
Mikhail_Sam

Я просто добавил конфигурации, используя команду spark-submit, чтобы исправить проблему с размером кучи. Спасибо.
Притам Садхухан

16

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


Сколько процентов памяти будет выделено в одиночестве
Яшвант Камбала

14

Взгляните на сценарии запуска, в которых установлен размер кучи Java, похоже, что вы не устанавливаете это до запуска Spark worker.

# 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"

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


Спасибо ~ Я постараюсь позже. От spark ui он показывает, что память каждого исполнителя составляет 4096. Значит, настройка включена, верно?
hequn8128

Видел твой ответ, когда я сталкиваюсь с подобной проблемой ( stackoverflow.com/questions/34762432/… ). Если вы посмотрите на предоставленную вами ссылку, похоже, что настройки Xms / Xmx там больше нет, можете сказать почему?
Сеффи

Содержание скрипта, на которое ссылается автор start up scripts, изменилось, к сожалению. По состоянию на 2019-12-19 гг. Таких вариантов не было
Дэвид Грумс

7

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

Но правда в том, что динамическое распределение ресурсов не устанавливает память драйвера и сохраняет ее по умолчанию, равную 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», этот тип свойств может быть установлен любым способом.


2
Вы должны использовать --conf spark.driver.memory =
18g

5

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

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


5

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

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

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

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


3

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

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


4
Как вы знаете, какой из них настроить между SPARK_EXECUTOR_MEMORY& SPARK_DRIVER_MEMORY?
Hunle

13
т.е. какая ошибка скажет вам увеличить SPARK_EXECUTOR_MEMORY, а какая ошибка скажет вам увеличить SPARK_DRIVER_MEMORY?
Hunle

2

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

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

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

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

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

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


Извините, что перехватил чужой запрос, но как использовать lowerByKey вместо groupBy?
Сомил Асея

1

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

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

0

Установка этих точных конфигураций помогла решить проблему.

spark-submit --conf spark.yarn.maxAppAttempts=2 --executor-memory 10g --num-executors 50 --driver-memory 12g
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.