Конфигуриране на Spark на YARN

Хабр, здравей! Вчера на среща, посветена на Apache Spark, от момчетата от Rambler&Co, имаше доста въпроси от участниците, свързани с конфигурирането на този инструмент. Решихме да тръгнем по неговите стъпки и да споделим нашия опит. Темата не е лесна - затова ви каним да споделите опита си в коментарите, може би и ние разбираме и използваме нещо погрешно.

Малко въведение в това как използваме Spark. Имаме тримесечна програма „Специалист по големи данни“, а през целия втори модул нашите участници работят по този инструмент. Съответно, нашата задача като организатори е да подготвим клъстера за използване в рамките на такъв случай.

Особеността на нашата употреба е, че броят на хората, работещи едновременно върху Spark, може да бъде равен на цялата група. Например на семинар, когато всички опитват нещо едновременно и повтарят след нашия учител. И това не е много - понякога до 40 души. Вероятно няма много компании в света, които се сблъскват с такъв случай на употреба.

След това ще ви кажа как и защо избрахме определени конфигурационни параметри.

Да започнем от самото начало. Spark има 3 опции за работа в клъстер: самостоятелен, с помощта на Mesos и с помощта на YARN. Решихме да изберем третия вариант, защото ни се струваше логичен. Вече имаме hadoop клъстер. Нашите участници вече са добре запознати с неговата архитектура. Да използваме ПРЕЖДА.

spark.master=yarn

Още по-интересно. Всяка от тези 3 опции за разполагане има 2 опции за разполагане: клиент и клъстер. Базиран документация и различни връзки в интернет, можем да заключим, че клиентът е подходящ за интерактивна работа - например чрез jupyter notebook, а клъстерът е по-подходящ за производствени решения. В нашия случай се интересувахме от интерактивна работа, следователно:

spark.deploy-mode=client

Като цяло оттук нататък Spark ще работи по някакъв начин върху YARN, но това не ни беше достатъчно. Тъй като имаме програма за големи данни, понякога участниците не разполагаха с достатъчно от полученото в рамките на равномерно нарязване на ресурси. И тогава открихме интересно нещо - динамично разпределение на ресурсите. Накратко, смисълът е следният: ако имате трудна задача и клъстерът е свободен (например сутрин), тогава използването на тази опция Spark може да ви даде допълнителни ресурси. Там необходимостта се изчислява по хитра формула. Няма да навлизаме в подробности - работи добре.

spark.dynamicAllocation.enabled=true

Зададохме този параметър и при стартиране Spark се срина и не стартира. Точно така, защото трябваше да го прочета документация по-внимателно. Там пише, че за да е наред всичко трябва да активирате и допълнителен параметър.

spark.shuffle.service.enabled=true

Защо е необходимо? Когато работата ни вече не изисква толкова много ресурси, Spark трябва да ги върне в общия пул. Най-отнемащият време етап в почти всяка задача на MapReduce е етапът на разбъркване. Този параметър ви позволява да запазите данните, които се генерират на този етап, и съответно да освободите изпълнителите. А изпълнителят е процесът, който изчислява всичко върху работника. Има определен брой процесорни ядра и определено количество памет.

Този параметър е добавен. Всичко изглеждаше работещо. Стана забележимо, че на участниците всъщност бяха дадени повече ресурси, когато имаха нужда от тях. Но възникна друг проблем - в един момент други участници се събудиха и също искаха да използват Spark, но там всичко беше заето и те бяха недоволни. Те могат да бъдат разбрани. Започнахме да разглеждаме документацията. Оказа се, че има редица други параметри, чрез които може да се повлияе на процеса. Например, ако изпълнителят е в режим на готовност, след колко време могат да се вземат ресурси от него?

spark.dynamicAllocation.executorIdleTimeout=120s

В нашия случай, ако вашите изпълнители не правят нищо в продължение на две минути, моля, върнете ги в общия пул. Но този параметър не винаги е бил достатъчен. Ясно беше, че човекът не е правил нищо от дълго време и ресурси не се освобождават. Оказа се, че има и специален параметър - след колко време да се избират изпълнители, които съдържат кеширани данни. По подразбиране този параметър беше безкрайност! Коригирахме го.

spark.dynamicAllocation.cachedExecutorIdleTimeout=600s

Тоест, ако вашите изпълнители не правят нищо 5 минути, дайте ги в общия пул. В този режим скоростта на освобождаване и издаване на ресурси за голям брой потребители стана прилична. Количеството недоволство намаля. Но решихме да отидем по-далеч и да ограничим максималния брой изпълнители на приложение - по същество на участник в програмата.

spark.dynamicAllocation.maxExecutors=19

Сега, разбира се, има недоволни хора от другата страна - „клъстерът не работи, а аз имам само 19 изпълнители“, но какво да правите, имаме нужда от някакъв правилен баланс. Не можете да направите всички щастливи.

И още една малка история, свързана със спецификата на нашия случай. По някакъв начин няколко души закъсняха за практически урок и по някаква причина Spark не започна за тях. Разгледахме количеството безплатни ресурси - изглежда, че е там. Spark трябва да започне. За щастие по това време документацията вече беше добавена някъде в подкорката и си спомнихме, че при стартиране Spark търси порт, от който да започне. Ако първият порт в диапазона е зает, той преминава към следващия по ред. Ако е свободен, той улавя. И има параметър, който показва максималния брой опити за това. По подразбиране е 16. Броят е по-малък от броя на хората в нашата група в клас. Съответно след 16 опита Spark се отказа и каза, че не мога да започна. Коригирахме тази настройка.

spark.port.maxRetries=50

След това ще ви разкажа за някои настройки, които не са много свързани със спецификата на нашия случай.

За да стартирате Spark по-бързо, се препоръчва да архивирате папката jars, намираща се в домашната директория SPARK_HOME, и да я поставите на HDFS. Тогава той няма да губи време да зарежда тези ярници от работници.

spark.yarn.archive=hdfs:///tmp/spark-archive.zip

Също така се препоръчва използването на kryo като сериализатор за по-бърза работа. Той е по-оптимизиран от стандартния.

spark.serializer=org.apache.spark.serializer.KryoSerializer

И също така има дългогодишен проблем със Spark, че често се срива от паметта. Често това се случва в момента, когато работниците са изчислили всичко и изпращат резултата на шофьора. Ние направихме този параметър по-голям за себе си. По подразбиране е 1 GB, ние го направихме 3.

spark.driver.maxResultSize=3072

И накрая, като десерт. Как да актуализирате Spark до версия 2.1 на HortonWorks дистрибуция - HDP 2.5.3.0. Тази версия на HDP съдържа предварително инсталирана версия 2.0, но веднъж решихме за себе си, че Spark се развива доста активно и всяка нова версия поправя някои грешки плюс предоставя допълнителни функции, включително за API на python, така че решихме какво трябва да да се направи е актуализация.

Изтеглих версията от официалния уебсайт за Hadoop 2.7. Разархивирайте го и го сложете в папката HDP. Инсталирахме символните връзки според нуждите. Стартираме го - не стартира. Пише много неясна грешка.

java.lang.NoClassDefFoundError: com/sun/jersey/api/client/config/ClientConfig

След като потърсихме в Google, разбрахме, че Spark е решил да не чака да се роди Hadoop и е решил да използва новата версия на трико. Самите те спорят помежду си по тази тема в JIRA. Решението беше да изтеглите фланелка версия 1.17.1. Поставете това в папката jars в SPARK_HOME, компресирайте го отново и го качете в HDFS.

Заобиколихме тази грешка, но се появи нова и доста рационализирана.

org.apache.spark.SparkException: Yarn application has already ended! It might have been killed or unable to launch application master

В същото време се опитваме да стартираме версия 2.0 - всичко е наред. Опитайте се да познаете какво се случва. Разгледахме регистрационните файлове на това приложение и видяхме нещо подобно:

/usr/hdp/${hdp.version}/hadoop/lib/hadoop-lzo-0.6.0.${hdp.version}.jar

Като цяло по някаква причина hdp.version не се разреши. След гугъл намерихме решение. Трябва да отидете в настройките на YARN в Ambari и да добавите параметър там към персонализиран сайт за прежди:

hdp.version=2.5.3.0-37

Тази магия помогна и Спарк излетя. Тествахме няколко от нашите лаптопи jupyter. Всичко работи. Готови сме за първия урок по Spark в събота (утре)!

DUP. По време на урока изникна още един проблем. В един момент YARN спря да предоставя контейнери за Spark. В YARN беше необходимо да се коригира параметърът, който по подразбиране беше 0.2:

yarn.scheduler.capacity.maximum-am-resource-percent=0.8

Тоест само 20% от ресурсите са участвали в разпределението на ресурсите. След като променихме параметрите, презаредихме YARN. Проблемът беше разрешен и останалите участници също успяха да изпълнят контекста на spark.

Източник: www.habr.com

Добавяне на нов коментар