Іскровий 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. Чи є в іскри будь-яке налаштування jvm для її завдань? Цікаво, чи spark.executor.memory має таке саме значення, як mapred.child.java.opts у hadoop. У моїй програмі spark.executor.memory вже встановлено на 4g набагато більше, ніж Xmx400m в hadoop. Дякую ~
hequn8128

Чи є трьома кроками, про які ти згадуєш, єдині, які ти робиш? Який розмір даних генерується (data._1, desPoints) - це повинно вписатись у пам'ять esp, якщо ці дані перенесуть на інший етап
Арнон Ротем-Гал-Оз

1
Яка конфігурація пам'яті для драйвера? Перевірте, який сервер вийшов з помилки пам'яті. Це водій чи хтось із виконавців.
RanP

Дивіться тут усі властивості конфігурацій: 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 часто змушує OOMs відходити. ОНОВЛЕННЯ: З іскри 1.6, мабуть, нам більше не потрібно буде грати з цими значеннями, іскра визначатиме їх автоматично.
  • Подібно до вище, але перемішуйте фракцію пам'яті . Якщо для вашої роботи не потрібна велика пам'ять перетасування, то встановіть її на нижчу величину (це може призвести до того, що ваші перетасовки перекинуться на диск, що може мати катастрофічний вплив на швидкість). Іноді, коли це операція перетасування, яка є OOMing, вам потрібно зробити навпаки, тобто встановити її на щось велике, наприклад, 0,8, або переконайтесь, що ви дозволяєте перетасувати переміщення на диск (це за замовчуванням з 1.0.0).
  • Слідкуйте за витоком пам’яті , вони часто спричинені випадковим закриттям об’єктів, які вам не потрібні у ваших лямбдах. Спосіб діагностування полягає в пошуку "завдання, серіалізованого як XXX байт" у журналах, якщо XXX більше кількох k або більше, ніж MB, можливо, випаде пам'ять. Дивіться https://stackoverflow.com/a/25270600/1586965
  • Пов'язане з вищезгаданим; використовуйте змінні трансляції, якщо вам дійсно потрібні великі об'єкти.
  • Якщо кешування великих РДУ і може принести в жертву яке - той час доступу вважають serialising ДРР http://spark.apache.org/docs/latest/tuning.html#serialized-rdd-storage . Або навіть кешувати їх на диску (що іноді не так вже й погано, якщо використовуються SSD).
  • ( Розширено ) Пов’язане з вищезгаданим, уникайте Stringта сильно вкладених структур (як-от Mapі вкладені класи справ). Якщо можливо, спробуйте використовувати тільки примітивні типи та індексуйте всі непримітивні, особливо якщо ви очікуєте багато дублікатів. Вибирайте WrappedArrayвкладені структури, коли це можливо. Або навіть розгорніть власну серіалізацію - ВИ будете мати найбільшу інформацію щодо того, як ефективно створити резервні дані в байти, ВИКОРИСТУЙТЕСЯ !
  • ( трохи хакі ) Знову під час кешування подумайте про використання Datasetкешу вашої структури, оскільки це використовуватиме більш ефективну серіалізацію. Це слід розцінювати як хак в порівнянні з попереднім пунктом кулі. Внесення доменних знань у альго / серіалізацію може мінімізувати обсяг пам’яті / кеш-пам’яті на 100x або 1000x, тоді як все Dataset, що ймовірно, дає 2x - 5x в пам'яті та 10-кратне стиснення (паркет) на диску.

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

EDIT: (Тож я можу легше перейти в Google). Наступне також свідчить про цю проблему:

java.lang.OutOfMemoryError : GC overhead limit exceeded

Дякуємо за ваші пропозиції ~ Якщо я встановив spark.executor.memory = 6 г, у искра возникнет проблема: "перевірте свій інтерфейс кластера, щоб переконатися, що працівники зареєстровані та мають достатню кількість пам'яті". Встановлення spark.storage.memoryFraction до 0,1 також не може вирішити проблему. Можливо, проблема полягає в моєму коді. Дякую!
hequn8128

2
@samthebest Це фантастична відповідь. Я дуже вдячний за допомогою реєстрації для пошуку витоків пам'яті.
Майлз Бейкер

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

2
Привіт @ user449355, будь ласка, можете задати нове запитання? Побоюючись розпочати довгу тему для коментарів :) Якщо у вас виникли проблеми, ймовірно, є інші люди, і питання полегшить пошук для всіх.
samthebest

1
До вашого першого моменту, @samthebest, ви не повинні використовувати ВСЮ пам'ять, spark.executor.memoryтому що вам напевно потрібен об'єм пам'яті для накладних витрат. Якщо ви використаєте все це, це сповільнить вашу програму. Винятком з цього може бути Unix, і в цьому випадку у вас є місце для заміни.
Хань

58

Для того, щоб додати випадок використання до цього , що часто не обговорюється, я буду представляти рішення при подачі Sparkзаявки через spark-submitв локальному режимі.

Згідно gitbook Mastering Apache Спарк по Яцек Ласковского :

Ви можете запустити Spark в локальному режимі. У цьому нерозподіленому режимі розгортання одного JVM Spark породжує всі компоненти виконання - драйвер, виконавець, бекенд і master - у тому ж 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 може мати справу з набором даних, значно більшим, ніж наявна оперативна пам'ять?
fuyi

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 допомогла
kennyut

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

1
НАЙКРАЩИЙ ВІДПОВІДЬ! Моя проблема полягала в тому, що Spark не був встановлений на майстерному вузлі, я просто використав PySpark для підключення до HDFS і отримав ту ж помилку. За допомогою configвирішеної проблеми.
Mikhail_Sam

Я тільки що додав конфігурації за допомогою команди-команда подання, щоб виправити проблему розміру купи. Дякую.
Прітам Садхухан

16

Ви повинні збільшити пам'ять драйвера. Я думаю, що у вашій папці $ SPARK_HOME / conf слід знайти файл spark-defaults.conf, відредагувати та встановити spark.driver.memory 4000mзалежно від пам'яті вашого майстра. Це те, що вирішило проблему для мене, і все працює безперебійно


Скільки відсотків пам’яті буде виділено самостійно
Яшувант Камбала

14

Погляньте на сценарії запуску, розміщений розмір купи 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"

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


Дякую ~ я ​​спробую пізніше. З іскрового інтерфейсу видно, що пам’ять кожного виконавця становить 4096. Отже, налаштування увімкнено, правда?
hequn8128

Бачив свою відповідь, коли я стикаюся з подібним питанням ( stackoverflow.com/questions/34762432/… ). Переглядаючи надане вами посилання, схоже, що налаштування Xms / Xmx більше не існує, можете сказати чому?
Seffy

На start up scriptsжаль, зміст сценарію, на який посилається, змінився, на жаль, змінився. Немає таких варіантів станом на 2019-12-19
Девід Грумес

7

Я дуже страждав від цього питання, ми використовуємо динамічне розподілення ресурсів, і я думав, що він використовуватиме мої кластерні ресурси, щоб найкраще підходити до програми.

Але правда полягає в тому, що динамічний розподіл ресурсів не встановлює пам'ять драйвера, і він зберігає його за замовчуванням, яке становить 1 г.

Я вирішив це, встановивши spark.driver.memory на число, яке відповідає пам’яті мого драйвера (для 32 ГБ оперативної пам'яті я встановив його на 18 ГБ)

ви можете встановити його за допомогою команди подання іскри наступним чином:

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

Дуже важлива примітка, ця властивість не буде врахована, якщо встановити її з коду, відповідно до іскрової документації:

Властивості іскри в основному можна розділити на два види: один пов'язаний з розгортанням, як-от "spark.driver.memory", "spark.executor.in вещества", цей тип властивостей може не впливати при програмному налаштуванні через SparkConf під час виконання програми, або поведінка залежить від обраного вами диспетчера кластерів та режиму розгортання, тому було б запропоновано встановити через конфігураційний файл або параметри командного рядка для подачі іскри; інший стосується, головним чином, управління іскровим режимом виконання, наприклад, "spark.task.maxFailures", такі властивості можна встановити будь-яким способом.


2
Вам слід скористатися --conf spark.driver.memory = 18g
merenptah

5

Загалом, іскрову пам'ять виконавця JVM можна розділити на дві частини. Іскра і пам'ять користувача. Це контролюється властивістю spark.memory.fraction- значення становить від 0 до 1. Під час роботи з зображеннями або обробці оперативної пам'яті в іскрових програмах слід врахувати зменшення значення spark.memory.fraction. Це зробить більше пам’яті доступним для роботи вашої програми. Іскра може розпливатися, тому вона все ще працюватиме з меншою часткою пам'яті.

Друга частина проблеми - це розподіл роботи. Якщо можливо, розділіть ваші дані на менші шматки. Менше даних, можливо, потребує менше пам'яті. Але якщо це неможливо, ви приносите жертву для обчислення пам'яті. Зазвичай одним виконавцем буде працювати декілька ядер. Загальної пам’яті виконавців повинно бути достатньо, щоб обробляти вимоги пам’яті всіх паралельних завдань. Якщо збільшення пам’яті виконавця не є можливим, ви можете зменшити ядра на одного виконавця, щоб кожна задача отримувала більше пам’яті для роботи. Тестуйте з 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 Sl + 18:49 0:33 / usr / java / останній / bin / java -cp / opt / spark / conf /: / opt / spark / jar / * -Xmx30g -Xms20g


3

Місце для встановлення розміру маси пам’яті (принаймні в іскрі-1.0.0) знаходиться в conf / spark-env. Відповідними змінними є SPARK_EXECUTOR_MEMORY& SPARK_DRIVER_MEMORY. Більше документів міститься в посібнику з розгортання

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


4
Звідки ви знаєте, яку налаштувати між SPARK_EXECUTOR_MEMORY& SPARK_DRIVER_MEMORY?
Ханле

13
тобто яка помилка скаже вам збільшити SPARK_EXECUTOR_MEMORY, а яка помилка підкаже вам збільшити SPARK_DRIVER_MEMORY?
Хань

2

У мене є кілька пропозицій щодо вищезгаданої помилки.

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

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

● Використовуйте мовлення приєднання

● Уникайте використання groupByKeys і намагайтеся замінити на ReduceByKey

● Уникайте використання величезних об'єктів Java, де б не відбулося переміщення


Вибачте, що викрали чужий запит, але як використовувати ReduByKey над groupBy?
Соміл Асея

1

З мого розуміння наведеного вище коду, він завантажує файл і виконує операцію з картою та зберігає її назад. Немає жодної операції, яка потребує переміщення. Крім того, не існує жодної операції, яка вимагає доведення даних до водія, отже, налаштування нічого, пов'язаного з переміщенням або драйвером, може не впливати. У драйвера є проблеми, коли завдань занадто багато, але це було лише до іскри версії 2.0.2. Можуть бути дві речі, які йдуть не так.

  • Є лише один або кілька виконавців. Збільшити кількість виконавців, щоб їх можна було розподілити на різних рабів. Якщо ви використовуєте пряжу, вам потрібно змінити конфігурацію 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.