Як налаштувати номер виконавця іскри, ядра та пам’ять виконавця?


84

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

Відповіді:


206

Наступна відповідь охоплює 3 основні аспекти, згадані в назві - кількість виконавців, пам’ять виконавця та кількість ядер. Можуть бути й інші параметри, такі як пам'ять драйвера та інші, на які я не звертався на момент відповіді, але хотів би додати найближчим часом.

Випадок 1 Апаратне забезпечення - 6 вузлів, а кожен вузол - 16 ядер, 64 ГБ оперативної пам'яті

Кожен виконавець є екземпляром JVM. Отже, ми можемо мати декілька виконавців в одному Вузлі

Перше 1 ядро ​​та 1 ГБ потрібні для ОС та демонів Hadoop, тому доступні 15 ядер, 63 ГБ оперативної пам'яті для кожного вузла

Почніть з того, як вибрати кількість ядер :

Number of cores = Concurrent tasks as executor can run 

So we might think, more concurrent tasks for each executor will give better performance. But research shows that
any application with more than 5 concurrent tasks, would lead to bad show. So stick this to 5.

This number came from the ability of executor and not from how many cores a system has. So the number 5 stays same
even if you have double(32) cores in the CPU.

Кількість виконавців:

Coming back to next step, with 5 as cores per executor, and 15 as total available cores in one Node(CPU) - we come to 
3 executors per node.

So with 6 nodes, and 3 executors per node - we get 18 executors. Out of 18 we need 1 executor (java process) for AM in YARN we get 17 executors

This 17 is the number we give to spark using --num-executors while running from spark-submit shell command

Пам'ять для кожного виконавця:

From above step, we have 3 executors  per node. And available RAM is 63 GB

So memory for each executor is 63/3 = 21GB. 

However small overhead memory is also needed to determine the full memory request to YARN for each executor.
Formula for that over head is max(384, .07 * spark.executor.memory)

Calculating that overhead - .07 * 21 (Here 21 is calculated as above 63/3)
                            = 1.47

Since 1.47 GB > 384 MB, the over head is 1.47.
Take the above from each 21 above => 21 - 1.47 ~ 19 GB

So executor memory - 19 GB

Остаточні цифри - виконавці - 17, ядра 5, пам’ять виконавця - 19 Гб


Випадок 2 Апаратне забезпечення: Той самий 6 вузол, 32 ядра, 64 ГБ

5 однаково для хорошої паралельності

Кількість виконавців для кожного вузла = 32/5 ~ 6

Отже, загальна кількість виконавців = 6 * 6 Вузлів = 36. Тоді остаточне число - 36 - 1 для AM = 35

Пам'ять виконавця - це 6 виконавців для кожного вузла. 63/6 ~ 10. Над головою - 0,07 * 10 = 700 МБ. Отже, округлюючи до 1 Гб, як над головою, отримуємо 10-1 = 9 Гб

Остаточні цифри - виконавці - 35, ядра 5, пам’ять виконавця - 9 Гб


Випадок 3

Вищевказані сценарії починаються з прийняття кількості ядер як фіксованої та переміщення до # виконавців та пам'яті.

Тепер для першого випадку, якщо ми вважаємо, що нам не потрібно 19 ГБ, а достатньо лише 10 ГБ, то наступні цифри:

ядер 5 # виконавців для кожного вузла = 3

На цьому етапі це призведе до 21, а потім 19 згідно з нашим першим розрахунком. Але оскільки ми вважали, що 10 - це нормально (припустимо, мало накладних витрат), то ми не можемо переключити кількість виконавців на вузол на 6 (наприклад, 63/10). Окрім 6-ти виконавців на вузол і 5 ядер, воно зменшується до 30 ядер на вузол, коли у нас лише 16 ядер. Тож нам також потрібно змінити кількість ядер для кожного виконавця.

Отже, обчислюючи ще раз,

Чарівне число 5 приходить до 3 (будь-яке число менше або дорівнює 5). Отже, з 3 ядрами та 15 доступними ядрами - ми отримуємо 5 виконавців на вузол. Отже (5 * 6 -1) = 29 виконавців

Отже, пам’ять становить 63/5 ~ 12. Над головою - 12 * .07 = .84 Отже, пам’ять виконавця - 12 - 1 ГБ = 11 ГБ

Кінцеві номери - це 29 виконавців, 3 ядра, пам’ять виконавця - 11 Гб


Динамічний розподіл:

Примітка: Верхня межа кількості виконавців, якщо ввімкнено динамічне розподіл. Отже, це говорить про те, що програма іскр може з’їсти всі ресурси, якщо це потрібно. Тож у кластері, де у вас запущені інші програми, і їм також потрібні ядра для запуску завдань, будь ласка, переконайтесь, що ви робите це на рівні кластера. Я маю на увазі, що ви можете виділити певну кількість ядер для YARN на основі доступу користувачів. Таким чином, ви можете створити spark_user може бути, а потім дати ядра (мін / макс) для цього користувача. Ці обмеження призначені для спільного використання між іскрою та іншими програмами, які працюють на YARN.

spark.dynamicAllocation.enabled - Коли для цього встановлено значення true - нам не потрібно згадувати виконавців. Причина нижче:

Число статичних параметрів, яке ми надаємо при подачі іскри, стосується всієї тривалості роботи. Однак, якщо динамічне розподіл потрапляє в картину, існують різні етапи, подібні

З чого почати:

Початкова кількість виконавців ( spark.dynamicAllocation.initialExecutors ) для початку з

Скільки :

Потім на основі завантаження (очікуваних завдань), скільки запитувати. Зрештою це були б цифри, які ми даємо при іскровому поданні статичним способом. Отож, як тільки встановлені початкові номери виконавців, ми переходимо до мінімальних ( spark.dynamicAllocation.minExecutors ) та максимальних ( spark.dynamicAllocation.maxExecutors ) чисел.

Коли запитувати чи давати:

Коли ми запитуємо нових виконавців ( spark.dynamicAllocation.schedulerBacklogTimeout ) - Протягом такої тривалості було виконано завдання. так просимо. кількість виконавців, запитуваних у кожному турі, збільшується в геометричній прогресії порівняно з попереднім туром. Наприклад, програма додасть 1 виконавця в першому раунді, а потім 2, 4, 8 тощо, у наступних раундах. У певний момент вищезгаданий макс з’являється у картині

коли ми віддаємо виконавця ( spark.dynamicAllocation.executorIdleTimeout ) -

Будь ласка, виправте мене, якщо я щось пропустив. Вищезазначене я розумію на основі блогу, про який я поділився, та деяких Інтернет-ресурсів. Дякую.

Список літератури:


2
Я десь читав, що в автономному режимі лише один виконавець на вузол, будь-яка ідея щодо цього? Я не бачу цього у вашій відповіді.
— jangorecki

2
В автономному кластері за замовчуванням ми отримуємо одного виконавця на кожного працівника. Нам потрібно грати з spark.executor.cores, і працівник має достатньо ядер, щоб отримати більше одного виконавця.
— Рамзі,

Я виявив, що мій працівник використовує всі 32 ядра без налаштування spark.executor.cores, тому він може використовувати всі доступні за замовчуванням.
— jangorecki

Так, за замовчуванням ядра нескінченні, як то кажуть. Отже, іскра може використовувати всі доступні ядра, якщо ви не вказали.
— Рамзі,

2
@Ramzy Я думаю, що слід зазначити, що навіть при динамічному розподілі ви все одно повинні вказати spark.executor.cores, щоб визначити розмір кожного виконавця, який збирається виділити Spark. В іншому випадку, коли Spark збирається виділити нового виконавця у вашу програму, він виділить цілий вузол (якщо він доступний), навіть якщо все, що вам потрібно, це лише ще п'ять ядер.
— Dan Markhasin

6

Крім того, важливим параметром конфігурації є:

spark.memory.fraction(Частка (простір купи - 300 МБ), що використовується для виконання та зберігання) з http://spark.apache.org/docs/latest/configuration.html#memory-management .

Якщо ви не використовуєте кеш / зберігати, встановіть його на 0,1, щоб у вас була вся пам’ять для вашої програми.

Якщо ви використовуєте кеш / персист, ви можете перевірити пам'ять, зайняту:

sc.getExecutorMemoryStatus.map(a => (a._2._1 - a._2._2)/(1024.0*1024*1024)).sum

Чи читаєте ви дані з HDFS або з HTTP?

Знову ж таки, налаштування залежить від вашого варіанту використання.


Чи знаєте ви, як би виглядала команда map під час використання pyspark? Я використовую sc._jsc.sc (). GetExecutorMemoryStatus (), щоб отримати статус виконавця, але нічого не можу зробити з тим, що повертає ...
— Томас

1
Вибачте @Thomas Decaux , але ви мали на увазі налаштування spark.memory.storageFraction=0.1? Оскільки AFAIK spark.memory.fractionвирішує обсяг пам'яті, який використовується як Sparkдля виконання, так і для зберігання (про це ви вже згадали), і лише spark.memory.storageFractionпам'ять (доступна для зберігання + виконання) не захищена від вилучення кешу . Будь ласка, перегляньте це посилання
— y2k-shubham

@Thomas Якщо в моїй заявці я маю лише persist (StorageLevel.DISK_ONLY), ніж цей параметр також застосовується, так? Він впливає лише на частку пам'яті, але не впливає на розливання диска?
— jk1
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.