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 ?

Dernière mise à jour : 23-05-2022

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.

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.

Identifier OutOfMemoryError dans les journaux

Vérifiez l'erreur suivante dans l'emplacement de votre journal (par exemple : /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 vous trouvez ce message d'erreur, cela signifie que l'espace de tas JVM manque de mémoire. Augmentez HADOOP_HEAPSIZE pour le service de l'interface de ligne de commande Hive dans /etc/hive/conf/hive-env.sh, comme illustré dans l'exemple suivant. Vous pouvez également augmenter le HADOOP_HEAPSIZE à l'aide de l'API de reconfiguration Amazon EMR pour la classification hive-env. 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=2048

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. Vous pouvez également, si vous le souhaitez, définir des valeurs distinctes pour chaque service.

Mise à jour de l'allocation mémoire lors de la création d’un cluster

Amazon EMR fournit l'opération de configuration API pour mettre à jour la configuration par défaut lorsque vous mettez à jour le cluster à l'aide de l'objet de configuration. Mettez à jour la valeur HADOOP_HEAPSIZE en fonction de votre cas d'utilisation :

{
  "Classification": "hive-env",
  "Properties": {},
  "Configurations": [
    {
      "Classification": "export",
      "Properties": {
        "HADOOP_HEAPSIZE": "2048"
      },
      "Configurations": []
    }
  ]
}

Mise à jour de l'allocation mémoire sur un cluster actif

Vous pouvez augmenter la valeur de HADOOP_HEAPSIZE sur un cluster en cours d'exécution en vous connectant au mode maître à l'aide de SSH ou à l’aide de l'API de reconfiguration Amazon EMR. L'API de reconfiguration Amazon EMR est disponible uniquement pour Amazon EMR versions 5.21 et ultérieures. Si les mises à jour de la mémoire sont effectuées par SSH sur le cluster, vous devez redémarrer les services Hive pour que les modifications prennent effet.

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. Par 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 rencontrez ce type d'erreurs, augmentez 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. Par 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. Par 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 émet toujours l'exception OutOfMemoryError, procédez comme suit pour le client.

Beeline :

Par défaut, Beeline tente de mettre en mémoire tampon l'ensemble de la relation de sortie avant de l'imprimer sur stdout. Ce comportement peut provoquer une exception OutOfMemoryError lorsque la relation de sortie est de taille importante. Pour résoudre l'exception OutOfMemoryError dans Beeline, lancez Beeline en utilisant la commande suivante, puis exécutez de nouveau la requête Hive :

beeline --incremental=true

SQL Workbench/J :

Dans Java Runtime Environment (JRE) 32 bits, l'application peut utiliser jusqu'à 1 Go de mémoire par défaut. 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. Le redémarrage de hive-server 2 affecte les requêtes en cours d'exécution sur le cluster. Il est recommandé de redémarrer les processus lorsqu'aucune requête n'est en cours d'exécution ou pendant une fenêtre de maintenance planifiée.

Les commandes que vous utilisez pour redémarrer les processus hive varient en fonction de la version d'Amazon EMR. Pour plus d'informations, consultez la documentation relative au Comment redémarrage un service dans Amazon EMR ?.

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

1.    Connectez-vous au nœud principal à l'aide de SSH.

2.    Redémarrez le metastore :

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

3.    Redémarrez hive-server2 :

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

Pour Amazon EMR versions 4.7.0 à 5.29 :

1.    Connectez-vous au nœud principal à l'aide de 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 à l'aide de 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