web-dev-qa-db-fra.com

Ressources Spark non entièrement allouées sur Amazon EMR

J'essaie de maximiser l'utilisation du cluster pour une tâche simple.

Le cluster est 1 + 2 x m3.xlarge, en cours d'exécution Spark 1.3.1, Hadoop 2.4, Amazon AMI 3.7.

La tâche lit toutes les lignes d'un fichier texte et les analyse en tant que csv.

Lorsque je déclenche une tâche en tant que mode grappe de fils, j'obtiens l'un des résultats suivants:

  • 0 exécuteur: le travail attend indéfiniment jusqu'à ce que je le tue manuellement
  • 1 exécuteur: emploi sous ressources avec 1 seule machine en fonctionnement
  • MOO lorsque je n'affecte pas assez de mémoire sur le pilote

Ce à quoi je m'attendais:

  • Le pilote Spark s'exécute sur le maître de cluster avec toute la mémoire disponible, ainsi que 2 exécuteurs exécutant 9404 Mo chacun (définis par le script install-spark).

Parfois, lorsque j’obtiens une exécution "réussie" avec 1 exécuteur, le clonage et le redémarrage de l’étape aboutissent à 0 exécuteur.

J'ai créé mon cluster en utilisant cette commande:

aws emr --region us-east-1 create-cluster --name "Spark Test"
--ec2-attributes KeyName=mykey 
--AMI-version 3.7.0 
--use-default-roles 
--instance-type m3.xlarge 
--instance-count 3 
--log-uri s3://mybucket/logs/ 
--bootstrap-actions Path=s3://support.elasticmapreduce/spark/install-spark,Args=["-x"] 
--steps Name=Sample,Jar=s3://elasticmapreduce/libs/script-runner/script-runner.jar,Args=[/home/hadoop/spark/bin/spark-submit,--master,yarn,--deploy-mode,cluster,--class,my.sample.spark.Sample,s3://mybucket/test/sample_2.10-1.0.0-SNAPSHOT-shaded.jar,s3://mybucket/data/],ActionOnFailure=CONTINUE

Avec quelques variations de pas incluant:

--driver-memory 8G --driver-cores 4 --num-executors 2


le script install-spark avec -x génère le fichier spark-defaults.conf suivant:

$ cat spark-defaults.conf
spark.eventLog.enabled  false
spark.executor.extraJavaOptions         -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70 -XX:MaxHeapFreeRatio=70
spark.driver.extraJavaOptions         -Dspark.driver.log.level=INFO
spark.executor.instances        2
spark.executor.cores    4
spark.executor.memory   9404M
spark.default.parallelism       8

Mise à jour 1

J'obtiens le même comportement avec un exemple générique JavaWordCount:

/home/hadoop/spark/bin/spark-submit --verbose --master yarn --deploy-mode cluster --driver-memory 8G --class org.Apache.spark.examples.JavaWordCount /home/hadoop/spark/lib/spark-examples-1.3.1-hadoop2.4.0.jar s3://mybucket/data/

Cependant, si je supprime le '--driver-memory 8G', la tâche se voit attribuer 2 exécuteurs et se termine correctement. 

Alors, quel est le problème avec la mémoire de pilote empêchant ma tâche d'obtenir des exécuteurs?

Le pilote doit-il être exécuté sur le noeud principal du cluster avec le conteneur principal de fil, comme expliqué ici ?

Comment donner plus de mémoire à mon pilote de job spark? (Où collectes et quelques autres opérations utiles surviennent)

19
Michel Lemay

La solution pour optimiser l'utilisation du cluster consiste à oublier le paramètre '-x' lors de l'installation de spark sur EMR et à ajuster manuellement la mémoire et les cœurs des exécutants.

This post donne une assez bonne explication de la façon dont l’allocation de ressources est effectuée lors de l’exécution de Spark on YARN.

Une chose importante à retenir est que tous les exécutants doivent avoir les mêmes ressources allouées! En ce moment même, Spark ne prend pas en charge les exécuteurs hétérogènes. (Certains travaux sont en cours pour supporter les GPU mais c'est un autre sujet)

Donc, afin d’obtenir le maximum de mémoire allouée au pilote tout en maximisant celle des exécuteurs, je dois fractionner mes nœuds comme suit (this slideshare donne de bonnes captures d’écran à la page 25):

  • Nœud 0 - Maître (gestionnaire de ressources de fil)
  • Noeud 1 - NodeManager (conteneur (pilote) + conteneur (exécuteur))
  • Noeud 2 - NodeManager (Conteneur (Executor) + Conteneur (Executor))

REMARQUE: Une autre option consisterait à spark-submit avec --master yarn --deploy-mode client à partir du nœud maître 0. Existe-t-il un exemple de compteur qui est une mauvaise idée?

Dans mon exemple, je peux avoir au plus 3 exécuteurs de 2 vcores de 4736 Mo chacun + un pilote avec les mêmes spécifications.

La mémoire 4736 est dérivée de la valeur de yarn.nodemanager.resource.memory-mb définie dans /home/hadoop/conf/yarn-site.xml. Sur un m3.xlarge, il est défini sur 11520 mb (voir ici pour toutes les valeurs associées à chaque type d'instance)

Ensuite, nous obtenons:

(11520 - 1024)/2 (exécuteurs par nœud) = 5248 => 5120 (arrondi à l'incrément de 256 mb, comme défini dans yarn.scheduler.minimum-allocation-mb)

7% * 5120 = 367 arrondi à 384 (surcharge de mémoire) deviendra 10% dans l'étincelle 1.4

5120 - 384 = 4736

Autres liens intéressants:

20
Michel Lemay

Le problème concerne les attentes concernant le fonctionnement de Spark sur YARN. Lorsque Spark est exécuté avec un mode de déploiement cluster ou maître défini sur yarn-cluster, le pilote est exécuté not sur le nœud maître mais dans le conteneur Maître de l'application sur l'un des nœuds esclaves. Pour plus de détails, voir https://spark.Apache.org/docs/latest/running-on-yarn.html

Je suppose que ce qui se passe, c’est que le cluster ne peut pas répondre aux besoins en mémoire du pilote (rappelez-vous que la mémoire réellement demandée au cluster correspond à ce que vous demandez, plus une surcharge), et donc attendre indéfiniment pour allouer le maître d’application où le pilote sera exécuté exécuteurs.

Pour donner au pilote la quantité de mémoire demandée, vous devez utiliser des esclaves supplémentaires afin de fournir des ressources à la fois pour le pilote basé sur le cluster et les exécuteurs. Avec les frais généraux sur le pilote, je suppose que vous devrez peut-être utiliser un type d'instance avec plus de mémoire. Lorsque vous demandez 8G pour le pilote, consultez le journal du gestionnaire de ressources et vérifiez le montant réel demandé.

Pour exécuter le pilote sur le nœud maître, le mode de déploiement doit être client. Cela peut toujours être fait avec les étapes EMR si vous utilisez une étape pour appeler un script afin de localiser les fichiers JAR du pilote sur le nœud maître. L'étape suivante peut ensuite appeler le jeu d'envoi et d'envoi spark pour le client en mode de déploiement et référencer le fichier JAR sur le fichier maître local. système.

2
ChristopherB

Le post de Michel Lemay est une bonne lecture de fond et il donne une réponse pour 1 configuration de cluster particulière. J'ai intégré cette logique dans une feuille de calcul qui présentera les meilleures options pour n'importe quel cluster. Pour l'utiliser, indiquez le nombre de nœuds du cluster, le nombre de cœurs/nœuds virtuels et la quantité de mémoire/nœud pouvant être allouée. Ceci fait, la feuille vous donnera des options pour les commandes de lancement qui utiliseront pleinement votre cluster pour les modes client et cluster pour 1, 2, 4 et 8 exécuteurs par nœud. J'ai mis en surbrillance la ligne correspondant à 2 exécuteurs par nœud, ce qui a toujours été la meilleure option dans mes tests. N'hésitez pas à copier cette feuille ou à ajouter des onglets pour différents types de cluster à votre guise.

https://docs.google.com/spreadsheets/d/1VH7Qly308hoRPu5VoLIg0ceolrzen-nBktRFkXHRrY4/edit?usp=sharing

1
David

Voici comment je contourne le problème:

En définissant spark.executor.memory + driver-memory sous le total d'un nœud MASTER donné, YARN peut alors placer le maître et l'exécuteur sur un nœud donné. plus important que j'ai les processeurs en cours d'exécution. Voici un exemple (sur r3.8xlarge):

aws emr add-steps --cluster-id j-1234 --steps Type=Spark,Name=foob3,Args=[--conf,spark.memory.fraction=0.95,--conf,spark.memory.storageFraction=0.1,--conf,spark.yarn.executor.memoryOverhead=8000,--conf,spark.executor.memory=200g,--conf,spark.executor.cores=32,--conf,spark.executor.instances=4,--conf,spark.dynamicAllocation.enabled=false,--class,myclass.Foo,--deploy-mode,cluster,--master,yarn,--driver-memory,10g,s3://myjar-1.0-SNAPSHOT.jar],ActionOnFailure=CONTINUE
1
Jeremy