Configurer Spark sur YARN

Habr, bonjour ! Hier, le meetup dédié à Apache Spark, de la part des gars de Rambler&Co, les participants ont posé beaucoup de questions concernant la configuration de cet outil. Nous avons décidé de suivre ses traces et de partager notre expérience. Le sujet n'est pas facile - nous vous invitons donc à partager votre expérience dans les commentaires, peut-être que nous comprenons et utilisons également quelque chose de mal.

Une petite introduction à la façon dont nous utilisons Spark. Nous avons un programme de trois mois « Spécialiste du Big Data », et tout au long du deuxième module, nos participants travaillent sur cet instrument. En conséquence, notre tâche, en tant qu'organisateurs, est de préparer le cluster à être utilisé dans un tel cas.

La particularité de notre utilisation est que le nombre de personnes travaillant simultanément sur Spark peut être égal à celui de l'ensemble du groupe. Par exemple, lors d'un séminaire, lorsque tout le monde essaie quelque chose en même temps et répète après notre professeur. Et ce n'est pas beaucoup - parfois jusqu'à 40 personnes. Il n’existe probablement pas beaucoup d’entreprises dans le monde confrontées à un tel cas d’utilisation.

Ensuite, je vais vous expliquer comment et pourquoi nous avons sélectionné certains paramètres de configuration.

Commençons par le tout début. Spark propose 3 options pour s'exécuter sur un cluster : autonome, en utilisant Mesos et en utilisant YARN. Nous avons décidé de choisir la troisième option car elle nous paraissait logique. Nous avons déjà un cluster hadoop. Nos participants connaissent déjà bien son architecture. Utilisons YARN.

spark.master=yarn

Encore plus intéressant. Chacune de ces 3 options de déploiement dispose de 2 options de déploiement : client et cluster. Basé documentation et divers liens sur Internet, nous pouvons conclure que le client est adapté au travail interactif - par exemple, via Jupyter Notebook, et que le cluster est plus adapté aux solutions de production. Dans notre cas, nous nous sommes intéressés au travail interactif, donc :

spark.deploy-mode=client

En général, Spark fonctionnera désormais d'une manière ou d'une autre sur YARN, mais cela ne nous suffisait pas. Puisque nous avons un programme sur le big data, parfois les participants n'avaient pas assez de ce qui avait été obtenu dans le cadre d'une répartition égale des ressources. Et puis nous avons découvert une chose intéressante : l’allocation dynamique des ressources. En bref, le point est le suivant : si vous avez une tâche difficile et que le cluster est libre (par exemple le matin), alors utiliser cette option Spark peut vous donner des ressources supplémentaires. La nécessité y est calculée selon une formule astucieuse. Nous n’entrerons pas dans les détails, cela fonctionne bien.

spark.dynamicAllocation.enabled=true

Nous avons défini ce paramètre et au démarrage, Spark s'est écrasé et n'a pas démarré. C'est vrai, parce que je devais le lire documentation plus attentivement. Il indique que pour que tout se passe bien, vous devez également activer un paramètre supplémentaire.

spark.shuffle.service.enabled=true

Pourquoi est-ce nécessaire ? Lorsque notre travail ne nécessite plus autant de ressources, Spark doit les remettre dans le pool commun. L'étape la plus longue de presque toutes les tâches MapReduce est l'étape Shuffle. Ce paramètre vous permet de sauvegarder les données générées à ce stade et de libérer les exécuteurs en conséquence. Et l'exécuteur testamentaire est le processus qui calcule tout sur le travailleur. Il possède un certain nombre de cœurs de processeur et une certaine quantité de mémoire.

Ce paramètre a été ajouté. Tout semblait fonctionner. Il est devenu évident que les participants recevaient davantage de ressources lorsqu’ils en avaient besoin. Mais un autre problème est survenu : à un moment donné, d'autres participants se sont réveillés et ont également voulu utiliser Spark, mais tout y était occupé et ils n'étaient pas satisfaits. Ils peuvent être compris. Nous avons commencé à regarder la documentation. Il s'est avéré qu'il existe encore un certain nombre de paramètres avec lesquels vous pouvez influencer le processus. Par exemple, si l'exécuteur est en mode veille, au bout de quel délai des ressources peuvent-elles lui être retirées ?

spark.dynamicAllocation.executorIdleTimeout=120s

Dans notre cas, si vos exécuteurs testamentaires ne font rien pendant deux minutes, veuillez les remettre dans la piscine commune. Mais ce paramètre n’était pas toujours suffisant. Il était clair que la personne ne faisait rien depuis longtemps et que les ressources n'étaient pas libérées. Il s'est avéré qu'il existe également un paramètre spécial - après combien de temps sélectionner les exécuteurs contenant des données mises en cache. Par défaut, ce paramètre était l'infini ! Nous l'avons corrigé.

spark.dynamicAllocation.cachedExecutorIdleTimeout=600s

Autrement dit, si vos exécuteurs testamentaires ne font rien pendant 5 minutes, donnez-les au pool commun. Dans ce mode, la vitesse de libération et d'émission des ressources pour un grand nombre d'utilisateurs est devenue décente. Le mécontentement a diminué. Mais nous avons décidé d'aller plus loin et de limiter le nombre maximum d'exécuteurs testamentaires par candidature, essentiellement par participant au programme.

spark.dynamicAllocation.maxExecutors=19

Maintenant, bien sûr, il y a des mécontents de l'autre côté - "le cluster est inactif et je n'ai que 19 exécuteurs testamentaires", mais que pouvez-vous faire ? Nous avons besoin d'une sorte d'équilibre correct. On ne peut pas rendre tout le monde heureux.

Et encore une petite histoire liée aux spécificités de notre cas. D'une manière ou d'une autre, plusieurs personnes étaient en retard pour un cours pratique et, pour une raison quelconque, Spark n'a pas commencé pour eux. Nous avons examiné la quantité de ressources gratuites - elle semble être là. Spark devrait démarrer. Heureusement, à ce moment-là, la documentation avait déjà été ajoutée quelque part au sous-cortex, et nous nous sommes souvenus qu'au lancement, Spark cherchait un port sur lequel démarrer. Si le premier port de la plage est occupé, il passe au suivant dans l'ordre. Si c'est gratuit, ça capture. Et il existe un paramètre qui indique le nombre maximum de tentatives pour cela. La valeur par défaut est 16. Le nombre est inférieur au nombre de personnes de notre groupe en classe. En conséquence, après 16 tentatives, Spark a abandonné et a déclaré que je ne pouvais pas démarrer. Nous avons corrigé ce paramètre.

spark.port.maxRetries=50

Je vais ensuite vous parler de quelques paramètres qui ne sont pas très liés aux spécificités de notre cas.

Pour démarrer Spark plus rapidement, il est recommandé d'archiver le dossier jars situé dans le répertoire personnel SPARK_HOME et de le placer sur HDFS. Il ne perdra alors pas de temps à charger ces jarniks par les ouvriers.

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

Il est également recommandé d'utiliser kryo comme sérialiseur pour un fonctionnement plus rapide. Il est plus optimisé que celui par défaut.

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

Et il existe également un problème de longue date avec Spark : il plante souvent de la mémoire. Cela se produit souvent au moment où les ouvriers ont tout calculé et envoient le résultat au conducteur. Nous avons augmenté ce paramètre pour nous-mêmes. Par défaut, c'est 1 Go, nous en avons fait 3.

spark.driver.maxResultSize=3072

Et enfin, en dessert. Comment mettre à jour Spark vers la version 2.1 sur la distribution HortonWorks - HDP 2.5.3.0. Cette version de HDP contient une version 2.0 préinstallée, mais nous avons décidé une fois par nous-mêmes que Spark se développe assez activement, et chaque nouvelle version corrige quelques bugs et fournit des fonctionnalités supplémentaires, y compris pour l'API python, nous avons donc décidé ce qui doit être fait est une mise à jour.

J'ai téléchargé la version sur le site officiel de Hadoop 2.7. Décompressez-le et placez-le dans le dossier HDP. Nous avons installé les liens symboliques selon les besoins. Nous le lançons - il ne démarre pas. Écrit une erreur très peu claire.

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

Après avoir cherché sur Google, nous avons découvert que Spark avait décidé de ne pas attendre la naissance de Hadoop et d'utiliser la nouvelle version de Jersey. Ils discutent eux-mêmes de ce sujet dans JIRA. La solution était de télécharger maillot version 1.17.1. Placez-le dans le dossier jars de SPARK_HOME, compressez-le à nouveau et téléchargez-le sur HDFS.

Nous avons contourné cette erreur, mais une nouvelle erreur, plutôt simplifiée, est apparue.

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

En même temps, nous essayons d'exécuter la version 2.0 - tout va bien. Essayez de deviner ce qui se passe. Nous avons examiné les journaux de cette application et avons vu quelque chose comme ceci :

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

En général, pour une raison quelconque, hdp.version n'a pas été résolu. Après avoir cherché sur Google, nous avons trouvé une solution. Vous devez accéder aux paramètres YARN dans Ambari et y ajouter un paramètre au site de fil personnalisé :

hdp.version=2.5.3.0-37

Cette magie a aidé et Spark a décollé. Nous avons testé plusieurs de nos ordinateurs portables Jupyter. Tout fonctionne. Nous sommes prêts pour le premier cours Spark de samedi (demain) !

UPD. Pendant le cours, un autre problème est apparu. À un moment donné, YARN a cessé de fournir des conteneurs pour Spark. Dans YARN il a fallu corriger le paramètre, qui par défaut était 0.2 :

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

Autrement dit, seulement 20 % des ressources ont participé à la répartition des ressources. Après avoir modifié les paramètres, nous avons rechargé YARN. Le problème a été résolu et le reste des participants ont également pu exécuter le contexte Spark.

Source: habr.com

Ajouter un commentaire