Correggere un errore Apache Hive di memoria insufficiente in Azure HDInsight

Informazioni su come risolvere un errore Apache Hive di memoria insufficiente durante l'elaborazione di tabelle di grandi dimensioni configurando le impostazioni di memoria Hive.

Eseguire una query Apache Hive su tabelle di grandi dimensioni

Un cliente ha eseguito una query Hive:

SELECT
    COUNT (T1.COLUMN1) as DisplayColumn1,
    …
    …
    ….
FROM
    TABLE1 T1,
    TABLE2 T2,
    TABLE3 T3,
    TABLE5 T4,
    TABLE6 T5,
    TABLE7 T6
where (T1.KEY1 = T2.KEY1….
    …
    …

Dettagli della query:

  • T1 è un alias di una tabella di grandi dimensioni, TABLE1, che include molti tipi di colonna STRING.
  • Altre tabelle non sono di grandi dimensioni, ma hanno molte colonne.
  • Tutte le tabelle sono unite tra loro, in alcuni casi con più colonne in TABLE1 e altre.

La query Hive ha richiesto 26 minuti in un nodo del cluster HDInsight A3 24. Il cliente ha notato i messaggi di avviso seguenti:

    Warning: Map Join MAPJOIN[428][bigTable=?] in task 'Stage-21:MAPRED' is a cross product
    Warning: Shuffle Join JOIN[8][tables = [t1933775, t1932766]] in Stage 'Stage-4:MAPRED' is a cross product

Tramite il motore di esecuzione di Apache Tez. La stessa query ha richiesto 15 minuti e quindi ha generato l'errore seguente:

    Status: Failed
    Vertex failed, vertexName=Map 5, vertexId=vertex_1443634917922_0008_1_05, diagnostics=[Task failed, taskId=task_1443634917922_0008_1_05_000006, diagnostics=[TaskAttempt 0 failed, info=[Error: Failure while running task:java.lang.RuntimeException: java.lang.OutOfMemoryError: Java heap space
        at
    org.apache.hadoop.hive.ql.exec.tez.TezProcessor.initializeAndRunProcessor(TezProcessor.java:172)
        at org.apache.hadoop.hive.ql.exec.tez.TezProcessor.run(TezProcessor.java:138)
        at
    org.apache.tez.runtime.LogicalIOProcessorRuntimeTask.run(LogicalIOProcessorRuntimeTask.java:324)
        at
    org.apache.tez.runtime.task.TezTaskRunner$TaskRunnerCallable$1.run(TezTaskRunner.java:176)
        at
    org.apache.tez.runtime.task.TezTaskRunner$TaskRunnerCallable$1.run(TezTaskRunner.java:168)
        at java.security.AccessController.doPrivileged(Native Method)
        at javax.security.auth.Subject.doAs(Subject.java:415)
        at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1628)
        at
    org.apache.tez.runtime.task.TezTaskRunner$TaskRunnerCallable.call(TezTaskRunner.java:168)
        at
    org.apache.tez.runtime.task.TezTaskRunner$TaskRunnerCallable.call(TezTaskRunner.java:163)
        at java.util.concurrent.FutureTask.run(FutureTask.java:262)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:745)
    Caused by: java.lang.OutOfMemoryError: Java heap space

L'errore persiste quando si usa una macchina virtuale più grande (ad esempio, D12).

Debug dell'errore di memoria insufficiente

Il supporto Microsoft insieme al team di progettazione ha rilevato che uno dei problemi che provocava l'errore di memoria insufficiente era un problema noto descritto in Apache JIRA:

"Quando hive.auto.convert.join.noconditionaltask = true controlliamo noconditionaltask.size e se la somma delle dimensioni delle tabelle nel join della mappa è minore di noconditionaltask.size il piano genera un join mappa, il problema è che il calcolo non tiene conto del sovraccarico introdotto da un'implementazione HashTable diversa come risultato se la somma delle dimensioni di input è inferiore alla dimensione noconditionaltask di una piccola query di margine raggiungerà OOM".

hive.auto.convert.join.noconditionaltask nel file hive-site.xml file è stato impostato su true:

<property>
    <name>hive.auto.convert.join.noconditionaltask</name>
    <value>true</value>
    <description>
            Whether Hive enables the optimization about converting common join into mapjoin based on the input file size.
            If this parameter is on, and the sum of size for n-1 of the tables/partitions for a n-way join is smaller than the
            specified size, the join is directly converted to a mapjoin (there is no conditional task).
    </description>
</property>

È probabile che il mapping join sia la causa dell'errore di memoria insufficiente dello spazio heap Java. Come illustrato nel post di blog sulle impostazioni della memoria Yarn di Hadoop in HDInsight, quando si usa il motore di esecuzione Tez lo spazio dell'heap effettivamente usato appartiene al contenitore Tez. Vedere l'immagine seguente che descrive la memoria del contenitore Tez.

Tez container memory diagram: Hive out of memory error.

Come suggerisce il post di blog, le due impostazioni di memoria seguenti definiscono la memoria del contenitore per l'heap: hive.tez.container.size e hive.tez.java.opts. Dalla nostra esperienza, l'eccezione di memoria insufficiente non significa che le dimensioni del contenitore sono troppo piccole. Ossia, ad essere ridotte solo le dimensioni dell'heap di Java (hive.tez.java.opts). Pertanto ogni volta che viene visualizzato un errore di memoria insufficiente, è possibile provare ad aumentare hive.tez.java.opts. Se necessario, può essere necessario aumentare hive.tez.container.size. L'impostazione java.opts deve essere circa l'80% di container.size.

Nota

L'impostazione hive.tez.java.opts deve sempre essere inferiore a hive.tez.container.size.

Poiché un computer D12 ha 28 GB di memoria, si è deciso di usare una dimensione del contenitore di 10 GB (10240 MB) e assegnare l'80% a java.opts:

SET hive.tez.container.size=10240
SET hive.tez.java.opts=-Xmx8192m

Con le nuove impostazioni, la query è stata eseguita in meno di dieci minuti.

Passaggi successivi

Un errore di memoria insufficiente non indica necessariamente che le dimensioni del contenitore sono troppo piccole. Al contrario, è necessario configurare le impostazioni della memoria in modo che le dimensioni dell'heap aumentino e raggiungano almeno l'80% delle dimensioni della memoria del contenitore. Per l'ottimizzazione delle query Hive, vedere Ottimizzare le query Apache Hive per Apache Hadoop in HDInsight.