Tech

Apache Hive 쿼리 오류 해결 방안

samine 2022. 6. 27. 14:06

대부분의 Hive 쿼리는 초기에는 잘 실행되다가 누적 데이터가 증가하면서 여러가지 오류가 발생을 합니다.

아래 오류 외에도 많겠지만, 업무를 진행하며 가장 많이 맞닥뜨리는 오류 4가지를 추렸습니다.

 

  • java.lang.OutOfMemoryError: Java heap space 오류
  • MapJoinMemoryExhaustionError 오류
  • AllocatorOutOfMemoryException: entire cache is fragmented and locked or, an internal issue
  • 리소스 할당을 못받고 대기하는 경우

 

 

그럼, 각 오류별 해결 방법에 대해서 알아보겠습니다.

 

1.  java.lang.OutOfMemoryError: Java heap space 오류

ERROR : Vertex failed, vertexName=Map 1, vertexId=vertex_1654346369288_0835_1_02, diagnostics=[Task failed, taskId=task_1654346369288_0835_1_02_000009, diagnostics=[TaskAttempt 0 failed, info=[Error: Error while running task ( failure ) : java.lang.OutOfMemoryError: Java heap space
	at java.nio.HeapByteBuffer.<init>(HeapByteBuffer.java:57)
	at java.nio.ByteBuffer.allocate(ByteBuffer.java:335)
	at org.apache.tez.runtime.library.common.sort.impl.PipelinedSorter.allocateSpace(PipelinedSorter.java:250)
	at org.apache.tez.runtime.library.common.sort.impl.PipelinedSorter$SortSpan.end(PipelinedSorter.java:1054)
	at org.apache.tez.runtime.library.common.sort.impl.PipelinedSorter$SortSpan.next(PipelinedSorter.java:1009)
	at org.apache.tez.runtime.library.common.sort.impl.PipelinedSorter.sort(PipelinedSorter.java:318)
	at org.apache.tez.runtime.library.common.sort.impl.PipelinedSorter.collect(PipelinedSorter.java:423)
	at org.apache.tez.runtime.library.common.sort.impl.PipelinedSorter.write(PipelinedSorter.java:379)
	at org.apache.tez.runtime.library.output.OrderedPartitionedKVOutput$1.write(OrderedPartitionedKVOutput.java:167)
	at org.apache.hadoop.hive.ql.exec.tez.TezProcessor$TezKVOutputCollector.collect(TezProcessor.java:338)
	at org.apache.hadoop.hive.ql.exec.vector.reducesink.VectorReduceSinkCommonOperator.doCollect(VectorReduceSinkCommonOperator.java:384)
...	
    at org.apache.hadoop.hive.ql.exec.vector.VectorMapOperator.process(VectorMapOperator.java:845)
	at org.apache.hadoop.hive.ql.exec.tez.MapRecordSource.processRow(MapRecordSource.java:92)
	at org.apache.hadoop.hive.ql.exec.tez.MapRecordSource.pushRecord(MapRecordSource.java:76)
	at org.apache.hadoop.hive.ql.exec.tez.MapRecordProcessor.run(MapRecordProcessor.java:419)
	at org.apache.hadoop.hive.ql.exec.tez.TezProcessor.initializeAndRunProcessor(TezProcessor.java:267)
	at org.apache.hadoop.hive.ql.exec.tez.TezProcessor.run(TezProcessor.java:250)
, errorMessage=Cannot recover from this error:java.lang.OutOfMemoryError: Java heap space
	at java.nio.HeapByteBuffer.<init>(HeapByteBuffer.java:57)
	at java.nio.ByteBuffer.allocate(ByteBuffer.java:335)
 
 ...

오류를 해결하기 위해서는 컨테이너 메모리 사이즈를 늘리거나 매퍼당 최대 처리 사이즈를 설정하는 방법이 있습니다.

 

Tez 메모리 설정

그림 참고 (https://wikidocs.net/23573)

 

1 )  컨테이너 메모리 사이즈 설정

  • java.opts 는 설정한 컨테이너 메모리의 80%로 설정합니다.
-- TEZ AM 메모리 설정 
set tez.am.resource.memory.mb=2048;
-- java.opts 값은 설정한 컨테이너 메모리의 80%로 설정 
set tez.am.java.opts=-Xmx1600m;

-- TEZ 컨테이너 메모리 설정 
set hive.tez.container.size=2048;
-- java.opts 값은 설정한 컨테이너 메모리의 80%로 설정 
set hive.tez.java.opts=-Xmx1600m;

 

2) 매퍼당 최대 처리 사이즈 설정

  • Tez 컨테이너 메모리가 설정과 상관없이 매퍼 입력 사이즈를 초과해서 발생하는 경우 아래와 같이 해당 옵션값을 설정합니다.
  • 일부 Tez 작업에서 MR 설정을 같이 입력해야 매퍼 개수가 늘어나는 경우가 있습니다. 데이터 사이즈에 따라 매퍼 개수가 늘어 나지 않으면 MR엔진, TEZ엔진 설정을 같이 합니다.
-- MR 엔진의 매퍼당 최대 처리 사이즈 
set mapreduce.input.fileinputformat.split.maxsize=25600000;
set mapreduce.input.fileinputformat.split.minsize=12800000;

-- TEZ 엔진의 매퍼당 최대 처리 사이즈
set tez.grouping.max-size=25600000;
set tez.grouping.min-size=12800000;

 

결론적으로 저희는 쿼리가 실행되면서 매퍼 입력 사이즈를 초과해서 발생하였고

2번째 해결 방법인 "2) 매퍼당 최대 처리 사이즈 설정"으로 OutOfMemoryError 오류를 해결했습니다.

 

 

 

 

2. MapJoinMemoryExhaustionError 오류

  • Hive에서 테이블간의 조인을 처리하는 방법은 셔플조인, 맵조인, 정렬-병합-버켓조인 3가지가 있습니다. 
    • 셔플조인 : 셔플 조인은 셔플(Shuffle) 단계에서 조인을 처리합니다.
    • 맵조인 : 맵 조인은 두 개의 테이블을 조인할 때 하나의 테이블이 메모리에 로드 되어 처리합니다.
    • 정렬-병합-바켓조인(SMB 조인) : 조인 테이블이 버켓팅 되어 있을 때 사용합니다. 
  • 그 중에서 맵조인 관련 아래와 같이 오류가 발생을 합니다.
Caused by: org.apache.hadoop.hive.ql.exec.mapjoin.MapJoinMemoryExhaustionError: Hash table loading exceeded memory limits for input: Reducer 3 numEntries: 2300000 estimatedMemoryUsage: 7155532792 effectiveThreshold: 7099279140 memoryMonitorInfo: { isLlap: true executorsPerNode: 23 maxExecutorsOverSubscribeMemory: 7 memoryOverSubscriptionFactor: 0.30000001192092896 memoryCheckInterval: 100000 noConditionalTaskSize: 1145044992 adjustedNoConditionalTaskSize: 3549639570 hashTableInflationFactor: 2.0 threshold: 7099279140 }
at org.apache.hadoop.hive.ql.exec.vector.mapjoin.fast.VectorMapJoinFastHashTableLoader.load(VectorMapJoinFastHashTableLoader.java:140)
at org.apache.hadoop.hive.ql.exec.MapJoinOperator.loadHashTableInternal(MapJoinOperator.java:344)
at org.apache.hadoop.hive.ql.exec.MapJoinOperator.loadHashTable(MapJoinOperator.java:413)
at org.apache.hadoop.hive.ql.exec.MapJoinOperator.lambda$initializeOp$0(MapJoinOperator.java:215)
at org.apache.hadoop.hive.ql.exec.tez.LlapObjectCache.retrieve(LlapObjectCache.java:120)
at org.apache.hadoop.hive.ql.exec.tez.LlapObjectCache$1.call(LlapObjectCache.java:147)
... 4 more

 

오류를 해결하기 위해서 테이블이 메모리에 올라 갈 수 있는 사이즈를 설정 

-- 맵조인은 hive.auto.convert.join=true 일때 적용됩니다.
set hive.auto.convert.join=true;
-- 맵조인 적용을 위한 설정. 기본 10MB로 설정 
set hive.auto.convert.join.noconditionaltask.size=10000000;

또는 아래와 같이 맵조인을 사용안함으로 설정하여 해결 할 수 있습니다.

-- 맵조인 사용안함
set hive.auto.convert.join=false;

 

 

 

3.AllocatorOutOfMemoryException: entire cache is fragmented and locked or, an internal issue

해당 오류는 LLAP 캐쉬 할당 관련해서 발생하는 오류로 Ambari UI 에서 Hive 설정을 통해서 해결합니다.

 

1) Ambari UI 에 로그인 합니다.

 

 

2) Hive > CONFIGS > ADVANCED 항목으로 이동합니다.

 

 

3) 스크롤을 내려서 Custom hive-interactive-site 를  확장하고 "hive.llap.io.allocator.alloc.min=256Kb" 를 입력합니다.

 

 

4) 저장 후 Hive 서비스를 재시작합니다.

 

설정한 hive.llap.io.allocator.alloc.min 옵션에 대한 참고 사이트입니다.

https://cwiki.apache.org/confluence/display/hive/configuration+properties

 

 

 

4. 특정Job 또는 쿼리 실행 시 다른 Job 이 리소스 할당을 못받고 대기하는 경우

일반적으로 Hive 쿼리가 실행 되면 리소스 매니저에서 자원을 적절하게 분배를 합니다.

그러나 특정 쿼리가 실행 될때  컨테이너 메모리를 설정(set tez.am.resource.memory.mb) 한다고 해도 계속해서 가상 메모리를 사용을 할 경우 리소스 매니저는 자원을 분배하지 못하고 다른 Job 또는 쿼리들은 계속해서 대기를 하게 됩니다. 

 

이런 현상을 해결 하기 위해서는 아래와 같이 설정을 합니다.

-- 컨테이너 메모리 설정
set tez.am.resource.memory.mb=2048;
set hive.tez.container.size=2048;

-- 가상 메모리 사용 안함
set yarn.nodemanager.vmem-check-enabled=false;
  • 가상 메모리 사용 옵션 (yarn.nodemanager.vmem-check-enabled) 을 false 로 설정 하고 컨테이너 메모리 설정을 조정합니다.

 


저희 TG360 에서 Hive ETL 과정에서 발생하는 대부분의 오류가 메모리 관련 오류였습니다.

처음에는 구글 검색에서 나오는 여러 해결 방안을 검토 적용하면서 시행 착오도 많았고 시간도 많이 소비하였습니다. 

 

Hive 쿼리에서 메모리 관련 오류 발생은 위의 4가지 범주에서 크게 벗어나지 않을꺼라 생각하며, 

Hive 관련 오류 때문에 고생하시는 분들께 많은 도움이 되었으면 합니다.