Apache Spark: количество ядер по сравнению с количеством исполнителей

Я пытаюсь понять взаимосвязь количества ядер и числа исполнителей при запуске задания Spark в YARN.

Условия тестирования следующие:

  • Количество узлов данных: 3
  • Данные node спецификация машины:
    • CPU: Core i7-4790 (# из ядер: 4, # из потоков: 8)
    • Оперативная память: 32 ГБ (8 ГБ x 4)
    • HDD: 8TB (2TB x 4)
  • Сеть: 1Gb

  • Исправленная версия: 1.0.0

  • Версия Hadoop: 2.4.0 (Hortonworks HDP 2.1)

  • Исходный поток задач: sc.textFile → filter → map → filter → mapToPair → reduceByKey → map → saveAsTextFile

  • Входные данные

    • Тип: текстовый файл
    • Размер: 165 ГБ
    • Количество строк: 454 568 833
  • Выход

    • Количество строк после второго фильтра: 310,640,717
    • Количество строк файла результата: 99,848,268
    • Размер файла результата: 41 ГБ

Работа выполнялась со следующими конфигурациями:

  • --master yarn-client --executor-memory 19G --executor-cores 7 --num-executors 3 (исполнители на данные node, используйте столько же, сколько ядра)

  • --master yarn-client --executor-memory 19G --executor-cores 4 --num-executors 3 (сокращено количество ядер)

  • --master yarn-client --executor-memory 4G --executor-cores 2 --num-executors 12 (меньше ядра, больше исполнителей)

Истекшее время:

  • 50 мин. 15 сек.

  • 55 мин 48 сек

  • 31 мин 23 сек

К моему удивлению, (3) было намного быстрее.
Я думал, что (1) будет быстрее, так как при перетасовке будет меньше взаимодействия между исполнителями.
Хотя количество ядер из (1) меньше (3), # ядро ​​не является ключевым фактором, поскольку 2) хорошо выполнялось.

(Последовательность была добавлена ​​после ответа pwilmot.)

Для получения информации снимок экрана монитора производительности выглядит следующим образом:

  • Данные Ganglia node резюме для (1) - задание начато в 04:37.

Ganglia data node summary for (1)

  • Данные Ganglia node резюме для (3) - работа началась в 19:47. Пожалуйста, проигнорируйте график до этого времени.

Ganglia data node summary for (3)

Граф грубо делит на 2 секции:

  • Сначала: от начала до reduceByKey: интенсивность процессора, отсутствие активности в сети.
  • Во-вторых: после reduceByKey: CPU опускается, сетевой ввод-вывод завершен.

Как показывает график, (1) может использовать как можно больше мощности ЦП. Таким образом, это может быть не проблема количества потоков.

Как объяснить этот результат?

Ответ 1

Чтобы надеяться сделать все это немного более конкретным, это проработанный пример настройки приложения Spark, чтобы использовать столько кластера, сколько Возможно: представьте кластер с шестью узлами, работающими с NodeManagers, каждый оснащенный 16 ядрами и 64 ГБ памяти. Возможности NodeManager, yarn.nodemanager.resource.memory-mb и yarn.nodemanager.resource.cpu-vcores, вероятно, должно быть установлено значение 63 * 1024 = 64512 (мегабайт) и 15 соответственно. Мы избегаем выделения 100% ресурсов для контейнеров YARN, потому что node нуждается в некоторых ресурсы для запуска демонов ОС и Hadoop. В этом случае мы оставляем гигабайт и ядро ​​для этих системных процессов. Менеджер Cloudera помогает путем учета этих параметров и настройки этих свойств YARN автоматически.

Вероятным первым импульсом будет использование - num-executors 6 --executor-core 15 --executor-memory 63G. Однако это неправильный подход, потому что:

63 ГБ + накладные расходы на память оператора не будут вместимы в емкость 63 ГБ диспетчеров узлов. Мастер приложения займет основное место на одном узлов, что означает, что не будет места для 15-лучевого исполнителя на этом node. 15 ядер на одного исполнителя могут привести к плохому вводу/выводу HDFS пропускная способность.

Лучшим вариантом будет использование - num-executors 17 --executor-core 5 --executor-memory 19G. Почему?

Эта конфигурация приводит к выполнению трех исполнителей на всех узлах, кроме одного с AM, который будет иметь двух исполнителей. --executor-memory была получена как (63/3 исполнителей за node) = 21. 21 * 0.07 = 1.47. 21 - 1,47 ~ 19.

Объяснение было дано в статье в блоге cloudera http://blog.cloudera.com/blog/2015/03/how-to-tune-your-apache-spark-jobs-part-2/

Ответ 2

Когда вы запускаете свое искровое приложение поверх HDFS, в соответствии с Sandy Ryza

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

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

Ответ 3

Я не играл с этими настройками самостоятельно, так что это всего лишь предположение, но если мы подумаем об этой проблеме как о нормальных ядрах и потоках в распределенной системе, то в вашем кластере вы можете использовать до 12 ядер (4 * 3 машины) и 24 потока (8 * 3 машины). В ваших первых двух примерах вы даете своей работе достаточное количество ядер (потенциальное пространство вычислений), но количество потоков (заданий) для запуска на этих ядрах настолько ограничено, что вы не можете использовать большую часть выделенной мощности обработки и, следовательно, работа выполняется медленнее, хотя выделено больше ресурсов для вычислений.

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

Ответ 4

Краткий ответ: я думаю, что tgbaggio прав. Вы достигли ограничений по пропускной способности HDFS для своих исполнителей.

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

Ключ для меня в графе кластерной сети. Для прогона 1 загрузка устойчива на уровне ~ 50 Мбайт/с. Для прогона 3 устойчивое использование удваивается, около 100 Мбайт/с.

Из поста блога cloudera, опубликованного DzOrd, вы можете увидеть эту важную цитату:

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

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


Запуск 1:19 ГБ, 7 ядер, 3 исполнителя

  • 3 исполнителя x 7 потоков = 21 потоков
  • с 7 ядрами на исполнителя мы ожидаем ограниченный ввод-вывод для HDFS (максимально до ~ 5 ядер)
  • эффективная пропускная способность ~ = 3 исполнителя x 5 потоков = 15 потоков

Запуск 3: 4 ГБ, 2 ядра, 12 исполнителей

  • 2 исполнителя x 12 потоков = 24 потока
  • 2 ядра на исполнителя, так что пропускная способность hdfs в порядке
  • эффективная пропускная способность ~ = 12 исполнителей x 2 потока = 24 потока

Если задание на 100% ограничено параллелизмом (количеством потоков). Мы ожидаем, что время выполнения будет полностью обратно коррелировано с количеством потоков.

ratio_num_threads = nthread_job1 / nthread_job3 = 15/24 = 0.625
inv_ratio_runtime = 1/(duration_job1 / duration_job3) = 1/(50/31) = 31/50 = 0.62

Итак, ratio_num_threads ~= inv_ratio_runtime, и похоже, что мы ограничены в сети.

Этот же эффект объясняет разницу между прогоном 1 и прогоном 2.


Запуск 2: 19 ГБ, 4 ядра, 3 исполнителя

  • 3 исполнителя x 4 темы = 12 темы
  • с 4 ядрами на исполнителя, хорошо, IO для HDFS
  • эффективная пропускная способность ~ = 3 исполнителя x 4 потока = 12 потоков

Сравнение количества эффективных потоков и времени выполнения:

ratio_num_threads = nthread_job2 / nthread_job1 = 12/15 = 0.8
inv_ratio_runtime = 1/(duration_job2 / duration_job1) = 1/(55/50) = 50/55 = 0.91

Это не так идеально, как в предыдущем сравнении, но мы все еще видим аналогичное падение производительности, когда теряем потоки.

Теперь напоследок: почему мы получаем лучшую производительность с большим количеством потоков, особенно? больше потоков, чем количество процессоров?

Хорошее объяснение разницы между параллелизмом (то, что мы получаем, разделяя данные на несколько процессоров) и параллелизмом (что мы получаем, когда мы используем несколько потоков для работы на одном процессоре), представлено в этом замечательном посте Роба Пайка: Параллельность это не параллелизм.

Краткое объяснение состоит в том, что если задание Spark взаимодействует с файловой системой или сетью, центральный процессор тратит много времени на ожидание связи с этими интерфейсами и не тратит много времени на "выполнение работы". Предоставляя этим процессорам более одной задачи за раз, они тратят меньше времени на ожидание и больше времени на работу, и вы видите лучшую производительность.

Ответ 5

Из превосходных ресурсов, доступных на странице пакета RStudio Sparklyr:

СПАРК ОПРЕДЕЛЕНИЯ:

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

Узел: сервер

Рабочий узел: сервер, который является частью кластера и доступен для запуска заданий Spark.

Главный узел: сервер, который координирует рабочие узлы.

Исполнитель: своего рода виртуальная машина внутри узла. Один узел может иметь несколько исполнителей.

Узел водителя: узел, который инициирует сеанс Spark. Как правило, это будет сервер, на котором расположен sparklyr.

Драйвер (Исполнитель): Узел драйвера также появится в списке Исполнитель.

Ответ 6

Я думаю, что одной из основных причин является местность. Размер вашего входного файла - 165G, блоки, связанные с файлами, которые, конечно, распределены по нескольким DataNodes, больше исполнителей могут избежать сетевой копии.

Попробуйте установить счетчик числа равных блоков, думаю, может быть быстрее.

Ответ 7

Динамическое распределение Spark обеспечивает гибкость и динамически распределяет ресурсы. В этом количестве min и max могут быть заданы исполнители. Также можно указать количество исполнителей, которые должны быть запущены при запуске приложения.

Прочтите ниже то же самое:

http://spark.apache.org/docs/latest/configuration.html#dynamic-allocation

Ответ 8

В первых двух конфигурациях, о которых я думаю, есть небольшая проблема. Понятия потоков и ядер как следует. Концепция потоковой передачи - это если ядра идеальны, тогда используйте это ядро ​​для обработки данных. Таким образом, память не полностью используется в первых двух случаях. Если вы хотите отметить этот пример, выберите машины, на которых есть более 10 ядер. Затем выполните оценку.

Но не давайте более 5 ядер на каждого исполнителя, и на производительность i/o будет бутылочка.

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

Данные node спецификация машины: Процессор: Core i7-4790 (# из ядер: 10, количество потоков: 20) ОЗУ: 32 ГБ (8 ГБ x 4) HDD: 8TB (2TB x 4)

Ответ 9

Есть способ получить оптимальную конфигурацию (без особых требований к памяти). Я написал сообщение об этом по адресу https://matteoguzzo.com/blog/spark-configurator/ и создал веб-приложение, которое выполняет вычисления для вас, по адресу http://sparkconf.mgbox.me/. В посте подробно объясняется логика расчетов, а также ссылки на предыдущие посты по данной теме, включая документацию Cloudera.