반응형
Notice
Recent Posts
Recent Comments
Link
관리 메뉴

지구정복

[Trino] Query exceeded per-node memory limit of 1GB | Trino Memory Tunning 본문

데이터 엔지니어링 정복/Trino

[Trino] Query exceeded per-node memory limit of 1GB | Trino Memory Tunning

noohhee 2025. 2. 18. 14:42
728x90
반응형

 

 

Hue에서 트리노 사용중 아래 에러가 발생.

 

{'message': 'Query exceeded per-node memory limit of 1GB [Allocated: 1015.31MB, Delta: 11.74MB, Top Consumers: {TableScanOperator=588.89MB, OrderByOperator=379.89MB, LazyOutputBuffer=46.53MB}]', 'errorCode': 131079, 'errorName': 'EXCEEDED_LOCAL_MEMORY_LIMIT', 'errorType': 'INSUFFICIENT_RESOURCES', 'failureInfo': {'type': 'io.trino.ExceededMemoryLimitException', 'message': 'Query exceeded per-node memory limit of 1GB [Allocated: 1015.31MB, Delta: 11.74MB, Top Consumers: {TableScanOperator=588.89MB, OrderByOperator=379.89MB, LazyOutputBuffer=46.53MB}]', 'suppressed': [], 'stack': 

io.trino.ExceededMemoryLimitException.exceededLocalUserMemoryLimit(ExceededMemoryLimitException.java:40)
io.trino.memory.QueryContext.enforceUserMemoryLimit(QueryContext.java:320)
io.trino.memory.QueryContext.updateUserMemory(QueryContext.java:161)
io.trino.memory.QueryContext.lambda$addTaskContext$0(QueryContext.java:241)
io.trino.memory.QueryContext$QueryMemoryReservationHandler.reserveMemory(QueryContext.java:301)
io.trino.memory.context.RootAggregatedMemoryContext.updateBytes(RootAggregatedMemoryContext.java:37)
io.trino.memory.context.ChildAggregatedMemoryContext.updateBytes(ChildAggregatedMemoryContext.java:38)
io.trino.memory.context.SimpleLocalMemoryContext.setBytes(SimpleLocalMemoryContext.java:66)
io.trino.operator.DirectExchangeClient.updateRetainedMemory(DirectExchangeClient.java:328)
io.trino.operator.DirectExchangeClient.addPages(DirectExchangeClient.java:307)
io.trino.operator.DirectExchangeClient$ExchangeClientCallback.addPages(DirectExchangeClient.java:387)
io.trino.operator.HttpPageBufferClient$1.onSuccess(HttpPageBufferClient.java:416)
io.trino.operator.HttpPageBufferClient$1.onSuccess(HttpPageBufferClient.java:347)
cohttp://m.google.common.util.concurrent.Futures$CallbackListener.run(Futures.java:1138)
java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
java.base/java.lang.Thread.run(Thread.java:833)

 

 

trino-config-properties에서 아래 설정값들을 조정해줘야 한다.

 

설정값 설명은 다음과 같다.

(참고 https://trino.io/docs/current/admin/properties-resource-management.html)

 

* query.max-cpu-time
Default value: 1_000_000_000d

This is the max amount of CPU time that a query can use across the entire cluster. Queries that exceed this limit are killed.

 

 

* query.max-memory-per-node

Default value: (JVM max memory * 0.3)

 

This is the max amount of user memory a query can use on a worker. 
User memory is allocated during execution for things that are directly attributable to, or controllable by, a user query. 
For example, memory used by the hash tables built during execution, memory used during sorting, etc. 
When the user memory allocation of a query on any worker hits this limit, it is killed.

Warning
The sum of query.max-memory-per-node and memory.heap-headroom-per-node must be less than the maximum heap size in the JVM on the node. 
See JVM config.

 

 

* query.max-memory
Default value: 20GB

This is the max amount of user memory a query can use across the entire cluster.
When the user memory allocation of a query across all workers hits this limit it is killed.

Warning 
query.max-total-memory must be greater than query.max-memory.



* query.max-total-memory
Default value: (query.max-memory * 2)

This is the max amount of memory a query can use across the entire cluster, including revocable memory. 
When the memory allocated by a query across all workers hits this limit it is killed. 
The value of query.max-total-memory must be greater than query.max-memory.


* memory.heap-headroom-per-node
Default value: (JVM max memory * 0.3)

This is the amount of memory set aside as headroom/buffer in the JVM heap for allocations that are not tracked by Trino.

Warning
The sum of query.max-memory-per-node and memory.heap-headroom-per-node must be less than the maximum heap size in the JVM on the node. 
See JVM config.

 

 

 

 

 

위 설정값들의 최적값은 어떻게 될까?

 

 

아래 잘 정리된 글을 보고 먼저 트리노 메모리 구조 이해가 필요하다.

https://cloudsqale.com/2019/11/28/presto-troubleshooting-query-exceeded-per-node-total-memory-limit-resource_overcommit-query-max-total-memory-per-node-reserved-pool-disk-spill/

https://it-sunny-333.tistory.com/102

 

[Presto] Memory Pool / Memory configuration (config.properties)

Presto Memory 각 Memory Pool 에서 메모리를 할당한다. 무조건 General Pool에서 먼저 할당한다. 메모리의 종류는 2가지이다. user 메모리 group by, join 등 쿼리에 따른 메모리이다. system 메모리 input/output buffer

it-sunny-333.tistory.com

 

 

트리노 각 노드 메모리( JVM Memory ) = General Memory Pool + Reserved Memory Pool + Headroom Memory

 

General Memory는 일반적인 쿼리를 실행하는 메모리 pool이라 이해하면 된다.

Reserved Memory는 General Pool 할당 메모리를 초과하는 무거운 쿼리를 실행 할 때, 해당 쿼리를 Reserved Pool로 보내져 실행된다.
단 1개의 쿼리만 보낼 수 있고, 메모리 사용량이 제일 많은 쿼리부터 실행한다.

 

 

 

만약 JVM xmx값이 150GB이고, default값으로 확인해보면 다음과 같다.

 

JVM Memory(150GB)

= General Memory Pool + Reserved Memory Pool(JVM Max Memory * 0.3) + Headroom Memory (JVM Max Memory * 0.3)

= General + Reserved(query.max-total-memory-per-node) + Headroom(memory.heap-headroom-per-node)

 

= General Memory Pool + 45GB + 45GB

( General Memory Pool는 60GB로 유추가능 )

 

 

만약 Reserved Pool을 사용하고 싶지 않다면, (General Pool 만 사용함) 아래 설정을 해준다.
experimental.reserved-pool-enabled = false

General Pool 만 사용하면 쿼리 동시성은 더 높아진다. Reserved Pool 에서는 1개의 쿼리만 실행 가능하므로. 

 

 

따라서 일단은 기본값으로 셋팅해보고 사용해본다.

 

JVM -Xmx 150G인 경우 

query.max-memory = (150 - headroom memory) / 2 = 105 / 2 = 50

 

query.max-total-memory(default) = query.max-memory * 2 = 100

 

query.max-memory-per-node(default) = 설정값에서 제거하여 default값 사용하게 하든지 명시적으로 default값 사용하기

= 150 * 0.3 = 45

 

memory.heap-headroom-per-node(default) = 150 * 0.3 = 45

 

그럼 정리하면 다음과 같다.

 

JVM Xmx Memory(150GB) = General(60) + Reserved(45) + Headroom(45)

 

 

추가적으로 Trino WEB UI에서 쿼리에 대한 메모리 분석을 할 수 있다.

 

 

 

만약 이렇게 설정했는데도 문제가 생기면 headrooom을 줄이고 Reserved(query.max-memory-per-node) 를 늘려준다.

 

 

그럼에도 문제가 되면 experimental.reserved-pool-enabled=false 를 설정하여 reserved memory를 없애고, general memory만 사용하게 한다.

(이러면 동시성 작업의 효율은 증가하지만 큰 쿼리가 있을 경우 다른 쿼리들이 계속 대기할 가능성 있음)

 

그럼에도 문제가 생기면 아래 설정값을 설정하여 메모리 찼을 때 디스크도 사용하게 한다.

  experimental.spill-enabled=true
  experimental.max-spill-per-node=80GB
  experimental.query-max-spill-per-node=80GB

728x90
반응형
Comments