Comment résoudre les exceptions de mémoire insuffisante d'espace de tas Java se produisant sur Amazon EMR lorsque Hive génère les résultats de la requête ?

Date de la dernière mise à jour : 18/05/2020

J'exécute une requête Apache Hive sur Amazon EMR. Hive lève une exception en raison d'une mémoire insuffisante lors de la sortie des résultats de la requête. Comment puis-je résoudre ce problème ?

Brève description

L'exception OutOfMemoryError se produit généralement en cas d'utilisation des commandes INSERT OVERWRITE lorsque l'espace du tas est insuffisant sur hive-server2, le metastore Hive ou le côté client. Pour résoudre ce problème, augmentez l'allocation de mémoire maximale pour la machine virtuelle Java ou augmentez HADOOP_HEAPSIZE.

Solution

Utilisez une ou plusieurs des solutions suivantes pour résoudre les exceptions OutOfMemoryError.

Remarque : cette solution ne couvre pas les exceptions OutOfMemoryError qui se produisent pendant le réglage de la mémoire du conteneur Apache Tez.

Augmenter l'allocation de mémoire maximale pour la machine virtuelle Java

Lorsque vous lancez un shell Hive, 1 Go de mémoire est alloué par défaut. L'allocation de mémoire maximale est définie par le paramètre -Xmx. Lorsque votre processus tente d'outrepasser cette limite, Hive l'arrête et lève l'exception de mémoire insuffisante OutOfMemoryError. Pour résoudre ce problème, augmentez la valeur -Xmx du script de shell Hive (en Mo), puis exécutez à nouveau votre requête Hive.

Augmenter la valeur de HADOOP_HEAPSIZE

Recherchez l'erreur suivante dans /mnt/var/log/hive/user/hadoop/hive.log :

# java.lang.OutOfMemoryError: Java heap space
# -XX:OnOutOfMemoryError="kill -9 %p"
#   Executing /bin/sh -c "kill -9 12345"...
Killed

Si ce message est présent, cela signifie que l'espace de tas de la machine virtuelle Java manque de mémoire. Augmentez la valeur de HADOOP_HEAPSIZE pour le service d'interface de ligne de commande Hive dans /etc/hive/conf/hive-env.sh, comme illustré dans l'exemple suivant. La valeur par défaut est 1000. Augmentez-la en fonction de votre cas d'utilisation. Ensuite, exécutez à nouveau la requête Hive.

export HADOOP_HEAPSIZE=2000

Important : ce paramètre s'applique à hive-server2, au metastore Hive, ainsi qu'à l'interface de ligne de commande Hive après le redémarrage de ces services. Le cas échéant, vous pouvez définir des valeurs distinctes pour chacun de ces services.

Beeline ou SQL Workbench/J

1.    Si vous exécutez la même requête à partir de Beeline ou de SQL Workbench/J, vérifiez /mnt/var/log/hive/hive-server2.log et hive-server2.out pour détecter les erreurs de nettoyage de la mémoire de l'espace de tas. Voici un exemple :

Transaction isolation: TRANSACTION_REPEATABLE_READ
0: jdbc:hive2://emr-analytics_master.abc.aws.> select id, name, x.* from mydb.location a, curated_admin.nxpepnd1_tpn_prvdr_pra_fclt b, curated_admin.test_table c where a.test = b._id and a._id = b._id and b._prod_id = c.prod_f_id;
#
# java.lang.OutOfMemoryError: Java heap space
# -XX:OnOutOfMemoryError="kill -9 %p"
#   Executing /bin/sh -c "kill -9 27745"...
Killed

2.    Si vous trouvez des erreurs de ce type, augmentez la valeur de HADOOP_HEAPSIZE pour hive-server2 dans /etc/hive/conf/hive-env.sh. Ce paramètre s'applique également au metastore Hive et au client Hive.

export HADOOP_HEAPSIZE=2048

Le cas échéant, utilisez des instructions conditionnelles pour spécifier différentes tailles de tas pour hive-server2, le metastore et le client. Voici un exemple :

export HIVE_CLIENT_HEAPSIZE=1024
export HIVE_METASTORE_HEAPSIZE=2048
export HIVE_SERVER2_HEAPSIZE=3072 
if [ "$SERVICE" = "metastore" ]
then
export HADOOP_HEAPSIZE=$HIVE_METASTORE_HEAPSIZE
elif [ "$SERVICE" = "hiveserver2" ]
then
export HADOOP_HEAPSIZE=$HIVE_SERVER2_HEAPSIZE
export HADOOP_OPTS="$HADOOP_OPTS -server -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/hive"
else
export HADOOP_HEAPSIZE=$HIVE_CLIENT_HEAPSIZE
fi

3.    Exécutez à nouveau la requête Hive après avoir mis à jour ces paramètres. Si vous obtenez toujours l'exception OutOfMemoryError et que vous exécutez plusieurs clients en même temps, passez à l'étape 4. Si l'erreur persiste, mais que vous n'exécutez pas plusieurs clients en même temps, passez à l'étape 8.

4.    Augmentez les paramètres -Xmx pour chaque client, en fonction de votre cas d'utilisation.

5.    Choisissez le nettoyage de mémoire adapté à votre cas d'utilisation en ajoutant -XX:+UseParNewGC (nouveau nettoyage de mémoire parallèle) ou -XX:+UseConcMarkSweepGC (nettoyage de mémoire de balayage des marques simultanées) dans les lignes HADOOP_OPTS, comme illustré dans l'exemple ci-dessous. Pour plus d'informations sur les différentes options de nettoyage de la mémoire, consultez les sections Garbage Collection et Java HotSpot VM Options dans la documentation Java.

export HADOOP_HEAPSIZE=2048
if [ "$SERVICE" = "cli" ]; then
if [ -z "$DEBUG" ]; then
export HADOOP_OPTS="$HADOOP_OPTS -XX:NewRatio=12 -Xmx12288m -Xms10m -XX:MaxHeapFreeRatio=40 -XX:MinHeapFreeRatio=15 -XX:+useParNewGC -XX:-useGCOverheadLimit"
else
export HADOOP_OPTS="$HADOOP_OPTS -XX:NewRatio=12 -Xmx12288m -Xms10m -XX:MaxHeapFreeRatio=40 -XX:MinHeapFreeRatio=15 -XX:-useGCOverheadLimit"
fi
fi

6.    Hive lève l'exception OutOfMemoryError lorsque le nettoyage de la mémoire n'aboutit pas dans le laps de temps spécifié. Pour supprimer la limite de temps, supprimez l'option -XX:-UseGCOverheadLimit ou remplacez-la par -XX:+UseGCOverheadLimit. Le cas échéant, modifiez la valeur de -XX:-UseGCOverheadLimit en spécifiant un nouveau délai de nettoyage de la mémoire. Pour plus d'informations, consultez la section The Parallel Collector dans la documentation Java.

7.    Exécutez à nouveau la requête Hive. Si Hive génère une erreur d'espace de tas sur le terminal pendant l'exécution (et s'il n'y a pas d'erreurs dans hive.log ou hive-server2.log), cela signifie probablement que votre client Hive manque de mémoire. Voici un exemple :

Transaction isolation: TRANSACTION_REPEATABLE_READ
0: jdbc:hive2://emr-analytics_master.abc.aws.> select id, name, x.* from mydb.location a, curated_admin.nxpepnd1_tpn_prvdr_pra_fclt b, curated_admin.test_table c where a.test = b._id and a._id = b._id and b._prod_id = c.prod_f_id;
#
# java.lang.OutOfMemoryError: Java heap space
# -XX:OnOutOfMemoryError="kill -9 %p"
#   Executing /bin/sh -c "kill -9 27745"...
Killed

8.    Pour y remédier, augmentez la mémoire du client, puis exécutez à nouveau la requête.

9.    Si Hive renvoie toujours l'exception « OutOfMemoryError », effectuez les opérations suivantes pour votre client.

Beeline :

Par défaut, Beeline tâche de mettre en tampon la totalité de la relation de sortie avant de l'imprimer sur stdout. Ce comportement peut entraîner une exception « OutOfMemoryError » lorsque la relation de sortie est volumineuse. Pour résoudre cette exception de mémoire insuffisante, lancez Beeline à l'aide de la commande suivante, puis exécutez à nouveau la requête Hive :

beeline --incremental=true

SQL Workbench/J :

Par défaut, l'application peut utiliser jusqu'à 1 Go de mémoire dans un environnement d'exécution Java (JRE) 32 bits, et jusqu'à 65 % de la mémoire physique disponible sous Java 64 bits. Pour vérifier la quantité de mémoire disponible pour l'application, choisissez Aide, puis À propos.

  • Sous macOS : vous pouvez augmenter le cas échéant la valeur -Xmx1024m dans le fichier Info.plist. Celui-ci se trouve généralement dans le répertoire /Applications/SQLWorkbenchJ2.app/Contents. Par exemple, pour doubler la quantité de mémoire disponible pour l'application, remplacez la valeur -Xmx1024m par -Xmx2048m. Exécutez ensuite à nouveau la requête.
  • Sous Windows : créez un fichier INI, puis ajoutez-y le paramètre vm.heapsize.preferred afin d'augmenter la quantité de mémoire disponible pour l'application.

Si vous utilisez des scripts shell ou de commandes par lots, vous pouvez augmenter la mémoire disponible lorsque vous installez SQL Workbench/J. L'exemple ci-dessous permet de créer 3 Go de mémoire disponible au cours de l'installation :

java -Xmx3g -jar sqlworkbench.jar

Remarque : si l'exception OutOfMemoryError se produit côté client plutôt que sur hive-server2 ou sur l'interface de ligne de commande Hive, enregistrez la sortie dans Amazon Simple Storage Service (Amazon S3) ou HDFS. N'utilisez pas Beeline ou SQL Workbench/J pour afficher les résultats de la requête.

Redémarrage de Hive

Si vous modifiez les propriétés Hive dans hive-site.xml ou hive-env.sh, vous devrez peut-être redémarrer Hive avant que les paramètres mis à jour prennent effet.

Pour les versions 4.7.0 et ultérieures d'Amazon EMR :

1.    Connectez-vous au nœud principal en utilisant SSH.

2.    Redémarrez le metastore :

sudo stop hive-hcatalog-server
sudo start hive-hcatalog-server
sudo status hive-hcatalog-server

Remarque : ne redémarrez pas le metastore à l'aide de la commande sudo restart hive-hcatalog-server.

3.    Redémarrez hive-server2 :

sudo stop hive-server2
sudo start hive-server2
sudo status hive-server2

Pour les versions 4.0.0 à 4.6 d'Amazon EMR :

1.    Connectez-vous au nœud principal en utilisant SSH.

2.    Redémarrez le metastore :

sudo stop hive-metastore
sudo start hive-metastore
sudo status hive-metastore

3.    Redémarrez hive-server2 :

sudo stop hive-server2
sudo start hive-server2
sudo status hive-server2