Подтвердить что ты не робот

Apache Spark Эффекты памяти драйвера, памяти исполнителя, накладных расходов на память драйверов и памяти служебных модулей на успех выполнения заданий

Я делаю некоторую настройку памяти на моей работе Spark в YARN, и я замечаю, что разные настройки будут давать разные результаты и влиять на результат запуска Spark. Однако я смущен и не понимаю полностью, почему это происходит, и было бы признательно, если бы кто-то мог дать мне некоторые рекомендации и объяснения.

Я предоставлю некоторую справочную информацию и отправлю свои вопросы и расскажу о случаях, которые я испытал после них ниже.

Настройки моей среды были следующими:

  • Память 20G, 20 VCores за node (всего 3 узла)
  • Hadoop 2.6.0
  • Spark 1.4.0

Мой код рекурсивно фильтрует RDD, чтобы уменьшить его (удаление примеров как часть алгоритма), затем mapToPair и собирать для сбора результатов и сохранения их в списке.

Вопросы

  • Почему возникает другая ошибка, и задание работает дольше (для второго случая) между первым и вторым случаями, когда только увеличивается память исполнителей? Связаны ли эти две ошибки?

  • И третий, и четвертый случай преуспевает, и я понимаю, что это потому, что я даю больше памяти, которая решает проблемы с памятью. Однако в третьем случае

spark.driver.memory + spark.yarn.driver.memoryOverhead = память что YARN создаст JVM

= 11g + (driverMemory * 0,07, минимум 384 м) = 11 г + 1,154 г = 12,154 г

Итак, из формулы я вижу, что моя работа требует MEMORY_TOTAL около 12.154g для успешного запуска, что объясняет, почему мне нужно больше 10 г для настройки памяти драйвера.

Но для четвертого случая

spark.driver.memory + spark.yarn.driver.memoryOverhead = память что YARN создаст JVM

= 2 + (driverMemory * 0,07, с минимумом 384 м) = 2 г + 0,524 г = 2,524 г

Похоже, что просто увеличивая накладные расходы на память на небольшое количество 1024 (1 г), это приводит к успешному запуску задания с памятью водителя всего 2 г, а MEMORY_TOTAL - всего лишь 2,524 г! В то время как без конфигурации служебных данных память драйвера меньше 11 г, но это не имеет смысла из формулы, поэтому я запутался.

Почему увеличение накладных расходов памяти (как для драйвера, так и для исполнителя) позволяет моей работе успешно завершить работу с более низким значением MEMORY_TOTAL (12.154g против 2.524g)? Есть ли здесь какие-то другие внутренние вещи, которые мне не хватает?

Первый случай

/bin/spark-submit --class <class name> --master yarn-cluster --driver-memory 7g --executor-memory 1g --num-executors 3 --executor-cores 1 --jars <jar file>

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

DriverMemory-7g_ExecutorMemory-1g

Второй случай

/bin/spark-submit --class <class name> --master yarn-cluster --driver-memory 7g --executor-memory 3g --num-executors 3 --executor-cores 1 --jars <jar file>

Если я запускаю программу с той же памятью драйвера, но с более высокой памятью исполнителей, задание выполняется дольше (примерно на 3-4 минуты), чем в первом случае, а затем оно будет сталкиваться с другой ошибкой ранее, которая представляет собой запрос/использование контейнера из-за этого больше памяти, чем разрешено, и убивается. Хотя я нахожу это странным, поскольку память исполнителей увеличивается, и эта ошибка возникает вместо ошибки в первом случае.

DriverMemory-7g_ExecutorMemory-3g

Третий случай

/bin/spark-submit --class <class name> --master yarn-cluster --driver-memory 11g --executor-memory 1g --num-executors 3 --executor-cores 1 --jars <jar file>

Любая настройка с памятью драйвера более 10 г приведет к успешному выполнению задания.

Четвертый случай

/bin/spark-submit --class <class name> --master yarn-cluster --driver-memory 2g --executor-memory 1g --conf spark.yarn.executor.memoryOverhead=1024 --conf spark.yarn.driver.memoryOverhead=1024 --num-executors 3 --executor-cores 1 --jars <jar file>

Задание будет успешно выполняться с этим параметром (память драйвера 2g и память исполнителей 1g, но увеличение служебных данных памяти драйвера (1g) и служебных данных памяти для исполнителей (1g).

Любая помощь будет оценена и действительно поможет в моем понимании Spark. Спасибо заранее.

4b9b3361

Ответ 1

Во всех ваших случаях используйте

--executor-cores 1

Лучше всего идти выше 1. И не ходите выше 5. Из нашего опыта и от рекомендаций разработчиков Spark.

например. http://blog.cloudera.com/blog/2015/03/how-to-tune-your-apache-spark-jobs-part-2/ :

A rough guess is that at most five tasks per executor 
can achieve full write throughput, so it’s good to keep 
the number of cores per executor below that number

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

Начните с -executor-core 2, double -executor-memory (потому что -executor-core сообщает также, сколько задач будет выполняться одним исполнителем) и посмотрите, что он делает для вас. Ваша среда компактна с точки зрения доступной памяти, поэтому переход на 3 или 4 даст вам еще больше возможностей использования памяти.

Мы используем Spark 1.5 и перестали использовать -executor-core 1 еще некоторое время назад, так как это давало проблемы с GC; он также выглядит как ошибка Spark, потому что просто предоставление большего объема памяти не помогло, а просто переключилось на большее количество задач на контейнер. Я думаю, что задачи одного и того же исполнителя могут пик потребления памяти в разное время, поэтому вы не тратите впустую/не должны перепроизводить память, чтобы заставить ее работать.

Другим преимуществом является то, что общие переменные Spark (аккумуляторы и широковещательные переменные) будут иметь только одну копию для каждого исполнителя, а не одну задачу, поэтому переход на несколько задач для каждого исполнителя - прямая память. Даже если вы явно не используете общие переменные Spark, Spark, скорее всего, создает их внутри себя. Например, если вы присоединитесь к двум таблицам через Spark SQL, Spark CBO может решить трансляцию меньшей таблицы (или меньшего фреймворка) для ускорения соединения.

http://spark.apache.org/docs/latest/programming-guide.html#shared-variables