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

지구정복

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

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

[Trino] Query exceeded per-node memory limit of 1GB | Trino Memory, CPU 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-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.

 

 

 

CPU관련


* 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.

 

 

* task.concurrency
Type: integer
Restrictions: Must be a power of two
Default value: min(max(number of physical CPUs of the node, 2), 32)

Default local concurrency for parallel operators, such as joins and aggregations. 

This value should be adjusted up or down based on the query concurrency and worker resource utilization. 

Lower values are better for clusters that run many queries concurrently, because the cluster is already utilized by all the running queries, so adding more concurrency results in slow downs due to context switching and other overhead. 

Higher values are better for clusters that only run one or a few queries at a time. 

This can also be specified on a per-query basis using the task_concurrency session property.

 

 

* task.max-worker-threads
Type: integer
Default value: (Node CPUs * 2)

Sets the number of threads used by workers to process splits. 

Increasing this number can improve throughput, if worker CPU utilization is low and all the threads are in use, but it causes increased heap space usage. 

Setting the value too high may cause a drop in performance due to a context switching. 

The number of active threads is available via the RunningSplits property of the trino.execution.executor:name=TaskExecutor.RunningSplits JMX object.

 

 

* exchange.client-threads
Type: integer
Minimum value: 1
Default value: 25

Number of threads used by exchange clients to fetch data from other Trino nodes. 

A higher value can improve performance for large clusters or clusters with very high concurrency, but excessively high values may cause a drop in performance due to context switches and additional memory usage.

 

 

 

 

 

 

 

 

일단 메모리만 고려한다.

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

 

 

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

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