web-dev-qa-db-fra.com

Pourquoi Spark échoue-t-il avec Java.lang.OutOfMemoryError: limite de temps système GC dépassée?

J'essaie d'implémenter un travail Hadoop Map/Reduce qui fonctionnait bien auparavant dans Spark. La définition de l'application Spark est la suivante:

val data = spark.textFile(file, 2).cache()
val result = data
  .map(//some pre-processing)
  .map(docWeightPar => (docWeightPar(0),docWeightPar(1))))
  .flatMap(line => MyFunctions.combine(line))
  .reduceByKey( _ + _)

MyFunctions.combine est

def combine(tuples: Array[(String, String)]): IndexedSeq[(String,Double)] =
  for (i <- 0 to tuples.length - 2;
       j <- 1 to tuples.length - 1
  ) yield (toKey(tuples(i)._1,tuples(j)._1),tuples(i)._2.toDouble * tuples(j)._2.toDouble)

La fonction combine génère de nombreuses clés de carte si la liste utilisée pour la saisie est volumineuse et que les exceptions sont levées.

Dans le paramètre Réduction de la carte Hadoop, je n'avais aucun problème, car c’est le point où la fonction combine est le point où Hadoop a écrit les paires de cartes sur le disque. Spark semble garder tout en mémoire jusqu'à ce qu'il explose avec un Java.lang.OutOfMemoryError: GC overhead limit exceeded.

Je fais probablement quelque chose de vraiment faux, mais je ne peux pas trouver d'indication sur la façon de s'en sortir, j'aimerais savoir comment je peux éviter cela. Depuis que je suis un noob total à Scala et Spark je ne suis pas sûr si le problème vient de l'un ou de l'autre, ou des deux. J'essaie actuellement pour exécuter ce programme dans mon propre ordinateur portable, et cela fonctionne pour les entrées où la longueur du tableau tuples n'est pas très longue. Merci d'avance.

44
Augusto

L'ajustement de la mémoire est probablement une bonne solution, comme cela a déjà été suggéré, car il s'agit d'une opération coûteuse et évolutive. Mais peut-être que quelques changements de code aideront.

Vous pouvez adopter une approche différente dans votre fonction de combinaison qui évite les instructions if en utilisant la fonction combinations. Je voudrais également convertir le deuxième élément des n-uplets en doubles avant l'opération de combinaison:

tuples.

    // Convert to doubles only once
    map{ x=>
        (x._1, x._2.toDouble)
    }.

    // Take all pairwise combinations. Though this function
    // will not give self-pairs, which it looks like you might need
    combinations(2).

    // Your operation
    map{ x=>
        (toKey(x{0}._1, x{1}._1), x{0}._2*x{1}._2)
    }

Cela donnera un itérateur, que vous pouvez utiliser en aval ou, si vous voulez, convertir en liste (ou quelque chose de ce genre) avec toList.

12
ohruunuruus

Ajoutez l'argument JVM suivant lorsque vous lancez spark-Shell ou spark-submit:

-Dspark.executor.memory=6g

Vous pouvez également envisager de définir explicitement le nombre de travailleurs lorsque vous créez une instance de SparkContext:

Cluster distribué

Définissez les noms d'esclaves dans le conf/slaves:

val sc = new SparkContext("master", "MyApp")
15
javadba

Dans la documentation ( http://spark.Apache.org/docs/latest/running-on-yarn.html ), vous pouvez lire comment configurer les exécuteurs et la limite de mémoire. Par exemple:

--master yarn-cluster --num-executors 10 --executor-cores 3 --executor-memory 4g --driver-memory 5g  --conf spark.yarn.executor.memoryOverhead=409

MemoryOverhead devrait représenter 10% de la mémoire de l'exécuteur.

Edit: Fixed 4096 to 409 (le commentaire ci-dessous fait référence à cela)

11
Carlos AG

J'ai eu le même problème pendant la longue période de régression. J'ai mis en cache le train et l'ensemble de test. Cela a résolu mon problème.

train_df, test_df = df3.randomSplit([0.8, 0.2], seed=142)
pipeline_model = pipeline_object.fit(train_df)

pipeline_model line donnait Java.lang.OutOfMemoryError: GC overhead limit exceeded Mais quand j'ai utilisé

train_df, test_df = df3.randomSplit([0.8, 0.2], seed=142)
train_df.cache()
test_df.cache()
pipeline_model = pipeline_object.fit(train_df)

Ça a marché.

2
Erkan Şirin

Cette erreur de récupération de place de la machine virtuelle Java s'est produite de manière reproductible dans mon cas lorsque j'ai augmenté le spark.memory.fraction aux valeurs supérieures à 0.6. Il est donc préférable de laisser la valeur à sa valeur par défaut pour éviter les erreurs de récupération de place JVM. Ceci est également recommandé par https://forums.databricks.com/questions/2202/javalangoutofmemoryerror-gc-overhead-limit-exceede.html .

Pour plus d'informations one pourquoi 0.6 est la meilleure valeur pour spark.memory.fraction voir https://issues.Apache.org/jira/browse/SPARK-15796 .

1
asmaier