Trino (TSF) Installation and Configuration (Korean)
Trino 사용 이유를 명확하게 파악하기
Trino 는 사용하는 방법에 따라서 설치, 구성 방법이 다르기 때문에 사용하는 이유를 명확하게 파악하는 것을 먼저 수행되어야 합니다.
다양한 Data Source (MySQL, PostgreSQL, HDFS, Amazon S3, Cassandra, Kafka 등)로부터 데이터를 가져와 하나의 Query 로 통합하여 분석할 필요가 있는 지 파악
- Business Intelligence Platform 에서 Data Lake (HDFS) 와 Relatational Database (i.e. MySQL) 데이터를 통합하여 분석
여러 Cloud 환경 또는 On-Premise 와 Cloud 간의 데이터 통합 분석이 필요한지 파악
Impala 와 같이 Data Locality 가 중요한 Query 를 수행할 필요없는 지 파악 (for Trino)
Trino 는 In Memory 기반으로 작동하기 때문에, 일부 Query 는 Impala 보다 상대적으로 느릴 수 있습니다.
실시간 Dashboard 에서 초 단위로 데이터 분석 결과 제공이 필요한지 파악
Data Scientist 들이 빠른 데이터 탐색 및 Prototyping 을 수행할 필요가 있는 지 파악
복잡한 Batch 작업이 필요 없는 경우, 특히 ad-hoc 분석이나 데이터 검증이 필요한 지 파악
복잡한 Batch 작업은 Spark 가 더 유리합니다.
Data Pipeline 에서 간단한 데이터 처리 및 집계 작업이 필요한 지 파악
복잡한 Resource 관리 및 Query 우선 순위 설정이 필요한지 파악
Impala 도 어느정도 Resource 관리가 지원이 되지만, Trino 만큼 정교하게 관리하기에는 무리가 있습니다.
Trino 는 Resource Group 을 통해 Query 우선순위를 설정하고, 다양한 사용자 및 부서에 따라 Resource 를 배분할 수 있습니다.
Multi-Tenant 환경에서의 유연성이 필요한지 파악
다중 사용자가 혼재 하는 대기업에서 다양한 팀과 부서가 동시에 데이터 분석을 수행을 해야 하는 경우
Resource 제약이 있는 환경에서 여러 사용자의 요청을 동시에 처리
Impala 또는 Spark 와 Trino 선택 기준
Impala
대규모 Hive Table 이나 HDFS 기반 대용량 Data 를 대화형으로 빠르게 처리하는 데 적합.
Data Locality 를 활용하기 때문에 Computation 을 DataNode 로 이동하여 하는 것에 상당히 효율적임
- 특히 Hadoop 환경에 깊게 통합됨
Spark
대규모 Batch Data 처리, ETL 작업, 복잡한 데이터 변환에 적합
MLlib 같은 Library 를 사용한 Machine Learning workload 처리에 적합
Trino
다양한 Data Source 간의 통합 Query 가 필요할때 적합
Low Latency 대화형 분석, 가벼운 ad-hoc 쿼리에 적합
Resource 관리가 필요한 다중 사용자 환경에 적합
Trino Installation by Apache Ambari
Trino 를 설치하기로 마음을 정하셨다면, 아래와 같이 진행하는 것을 추천 드립니다.
Trino 는 여러가지 방법으로 설치가 가능하지만, Multi Tenant 환경에서 운영하려면, Ambari 를 사용하여 설치, Ranger 와 결합하여 사용할때, 빛을 발휘합니다.
기타 다른 설치 방법은 Trino Documentation 을 참고하시기 바랍니다.
Deploying Trino
Trino in a Docker container
Trino on Kubernetes with Helm
RPM package
Trino 설치는 Kerberized Hadoop (Secured Hadoop) 을 기준으로 설명합니다.
Trino Cluster 는 기본적으로 JVM 에서 실행됩니다.
- 적당한 JDK or JRE 가 설정되어야 합니다. Java 11 version 이상 추천
Trino Installation Step by Step
Ambari 에서 Trino Package 를 설치하여 Trino Cluster 를 구성합니다.
- Trino Cluster 는 Coordinator, Worker 로 구성되어 있습니다.
Trino 설치가 끝났다면, Ranger Trino Plugin 을 Trino 가 설치된 곳에 설치합니다.
Trino 보안을 위해서는 Trino Documentation 에서 제안하는 Security workflow 를 따르는 것을 추천합니다.
TLS/HTTPS 를 활성화 하기 위해서 인증서와 Load Balancer 를 구성합니다. (필수)
Shared Secret 을 설정합니다. (필수)
LDAP 과 같은 Authentication Provider 를 설정합니다. (필수)
- Kerberos 설정은 복잡하고 어렵기 때문에 왠만하면 사용하지 않도록 합니다.
필요하다면, URL 에 접근하는 사용자에 대해서 Authorization 을 구현해도 됩니다. (Optional)
Trino 를 위한 Kerberos Principal 을 생성하고, 생성한 keytab file 들을 Coordinator, Worker 에 배포합니다.
Trino 인증을 위해서 관련된 설정파일을 배포합니다.
Coordinator Server 에서
password-authenticator.properties
file 을 생성하고 설정합니다.password-authenticator.properties
file 의 내용은 아래와 같이 구성합니다. (LDAP 으로 인증을 하는 경우 입니다)# $TRINO_HOME/etc/password-authenticator.properties password-authenticator.name=ldap ldap.url=ldap://<ldap-host>:389 ldap.allow-insecure=true ldap.user-bind-pattern=uid=${USER},ou=users,dc=company,dc=com
Trino Connector 를 설정합니다. (Hive Connector 를 기준으로 설명합니다.)
$TRINO_HOME/etc/catalog/hive.properties
형식으로 file 을 생성하고 설정합니다.Trino Hive Connector 문서를 참고 합니다.
connector.name=hive hive.metastore.uri=thrift://<HMS-server>:9083 hive.config.resources=$HADOOP_HOME/conf/core-site.xml,$HADOOP_HOME/conf/hdfs-site.xml hive.metastore.authentication.type=KERBEROS hive.metastore.service.principal=hive/_HOST@<REALM> hive.metastore.client.principal=trino@<REALM> hive.metastore.client.keytab=<principal keytab path> hive.hdfs.authentication.type=KERBEROS hive.hdfs.impersonation.enabled=true hive.hdfs.trino.principal=trino@<REALM> hive.hdfs.trino.keytab=<principal keytab path>
Apache Ranger 와 잘 연동이 되어 작동하는 지 확인 합니다.
Ranger Trino Plugin 이 정상적으로 작동하는 지 확인
Ranger 에서 Policy 들을 생성하고 해당 Policy 별로 LDAP 으로 인증된 사용자들이 적합한 권한을 행사할 수 있는 지 확인
Trino 에서 Audit Log 가 잘 남는 지 확인
Trino Configuration
- Trino 설정에서 중요한 것들은 Resource, Coordinator, Worker 설정입니다.
Trino Resource Configuration
Trino 에서 Resource 를 관리하기 위해서는 Resource Group 이 있습니다.
Resource Group 을 적용하기 위해서는 Resource Group Manager 를 설정해야 합니다.
Resource Group Manager 는 file 기반 혹은 Database 를 사용할 수 있습니다.
File 기반으로 설정하려면,
$TRINO_HOME/etc/resource-groups.properties
파일을 생성, 설정합니다.여기서는 file 기반으로 설정하는 것을 예를 들어 설명 하겠습니다.
# resource-groups.properties resource-groups.configuration-manager=file resource-groups.config-file=$TRINO_HOME/etc/resource-groups.json
resource-groups.config-file 은 JSON 형식으로 작성하면 됩니다.
Resource Group config file 은
Resource group properties
라는 개념을 사용하여 설정하도록 합니다.자세한 설명은 Trino Documentation 을 참고하도록 합니다.
꼭 필요한 field 설명
name
- name of the group
maxQueued
maximum number of queued queries.
Once this limit is reached new queries are rejected.
hardConcurrencyLimit
- maximum number of running queries.
softMemoryLimit
maximum amount of distributed memory this group may use, before new queries become queued.
May be specified as an absolute value (i.e.
1GB
) or as a percentage (i.e.10%
) of the cluster’s memory.
Sample 설정 파일
{ "rootGroups": [ { "name" : "ADD_HOC", "maxQueued": 50, "hardConcurrencyLimit": 20, "softMemoryLimit": "15%" }, { "name" : "BI", "maxQueued": 80, "hardConcurrencyLimit": 40, "softMemoryLimit": "20%" } ] }
Resource group 에는 아래와 같은 특징이 있습니다.
Resource 사용량 제한과 Queue 정책에 대해서 강제할 수 있습니다.
사용량을 Sub-Group 으로 분리도 가능합니다.
Query 는 하나의 Resource Group 에 속하며, 해당 Group으로부터 Resource 를 소비합니다.
사용 가능한 Resource 가 부족하면 Queued 되어 대기중인 Query 들을 제외하고 실행중인 Query 의 실패를 유발하지는 않습니다.
- 대신에 새로운 Query 들이 전부 Queued 상태가 됩니다.
Sub-Group 을 갖거나, 혹은 Query 를 받거나 할 수 있는데 동시에 두개는 못합니다.
- Sub-Group 을 가지면서 Query 를 처리하는 방식은 불가능합니다.
Resource group name 에는 제약 사항이 있습니다.
Resource group 이 Tree 구조로 되어 있을 때, sub group 의 이름이 다른(sibling) sub group 의 이름과 중복되는 것은 허용되지 않습니다.
- i.e. a.b, a.b → 허용되지 않음
Tree 구조에서 각 Node 는 고유한 경로를 가져야 하며, 동일한 부모 아래에 있는 sub group 들은 서로 다른 이름을 가져야 합니다.
- i.e.a.b, a.c → 유효함
Resource group 의 sub group 이름이 서로 다른 부모 Node 아래에 동일 하더라도, 고유한 전체 경로로 식별 되므로 충돌이 발생하지 않습니다.
- i.e. a.b.d, a.c.d → 유효함
Resource group 을 설정했다면, selector 를 설정해야 합니다.
자세한 설명은 Trino Selector rules 문서 를 참고합니다.
Selector rule 은 Java Programming 언어의 Regular Expression 문법을 적용하여 사용합니다.
Selector rule 에서 필수는
group
입니다.group
: the group these queries will run in
기본적으로 모든 rule 들은 AND 로 합쳐 집니다.
clientTags 는 주로 JDBC 연결 설정에서 사용하여 rule 을 적용할 때 사용합니다.
clientTags 는 제약사항이 있습니다.
허용되지 않는 문자
- 공백 (Whitespace), 쉼표 (Comma, ,), 슬래시 (Slash, /), 콜론 (Colon, :)
Trino Impersonation Configuration (Optional)
Trino 에서 HDFS 접근시 Impersonation 을 적용하기 위하여 proxy user 설정이 필요합니다.
HDFS 에서 Impersonation 을 설정하는 것을 예를 들어 설명 합니다.
Ambari → HDFS → CONFIGS → ADVANCED → core-site.xml 설정
hadoop.proxyuser.trino.groups: *
hadoop.proxyuser.trino.hosts: *
core-site.xml 을 수정하였기 때문에 적용을 위해서는 NameNode 를 Restart 해야 합니다.
Trino Client Configuration
Resource Group 을 재대로 적용하기 위해서는 Client 쪽에서도 설정을 해야 합니다.
Client Connector 에서 clientTags 설정을 해주는 방법이 편한 방법 중에 하나 입니다.
Trino Connection for JDBC Driver
The Trino JDBC driver has the following requirements
Java version 8 or higher
All users that connect to Trino with the JDBC driver must be granted access to query tables in the system.jdbc schema.
위의 Trino JDBC 요구사항을 만족시키는 어떠한 JDBC Driver 도 사용가능 합니다.
Trino 에서 제공하는 trino-cli 를 사용
trino-cli executable jar 를 download 합니다.
아래와 같이 trino 서버에 접속이 가능 합니다.
접속하기 위해서 별도의 인증(i.e. Kerberos) 가 필요할 수 있습니다.
./trino --server http://trino.example.com:8080
Trino Python Client 를 사용
Client for Trino, a distributed SQL engine for interactive and batch big data processing.
Provides a low-level client and a DBAPI 2.0 implementation and a SQLAlchemy adapter. It supports Python>=3.8 and PyPy.
Trino.sqlalchemy is compatible with the latest 1.3.x, 1.4.x and 2.0.x SQLAlchemy versions at the time of release of a particular version of the client.
To connect to Trino using SQLAlchemy, use a connection string (URL) following this pattern
trino://<username>:<password>@<host>:<port>/<catalog>/<schema>
In order to pass additional connection attributes use connect_args method.
Attributes can also be passed in the connection string.
Python Client 를 사용하여 접속 하는 예제 코드
from sqlalchemy import create_engine from trino.sqlalchemy import URL engine = create_engine( URL( host="localhost", port=8080, catalog="system" ), connect_args={ "session_properties": {'query_max_run_time': '1d'}, "client_tags": ["tag1", "tag2"], "roles": {"catalog1": "role1"}, } ) # or in connection string engine = create_engine( 'trino://user@localhost:8080/system?' 'session_properties={"query_max_run_time": "1d"}' '&client_tags=["tag1", "tag2"]' '&roles={"catalog1": "role1"}' ) # or using the URL factory method engine = create_engine(URL( host="localhost", port=8080, client_tags=["tag1", "tag2"] ))
Trino Coordinator Configuration
Trino 의 Coordinator Server 는 Cluster 의 중추 역할을 하므로, 하드웨어 사양에 대해 신중하게 고려해야 합니다.
Trino Coordinator 는 Query Scheduling, Resource Management, 사용자 요청 처리 등 다양한 중요한 역할을 수행 하므로, 그에 맞는 적절한 Hardware 사양이 요구됩니다.
Trino Coordinator 로 사용할 Server 의 Hardware Spec 은 아래와 같은 것을 추천합니다.
CPU
CPU Cores: 최소 8~16 Core 이상을 권장합니다.
- Coordinator 는 Query Planning, 분석, Resource Scheduling 을 처리 하므로 Multi Core 환경에서 성능이 크게 향상됩니다.
CPU Clock Speed: High Clock 의 최신 Intel Xeon 또는 AMD EPYC 시리즈가 적합합니다.
Hyper Threading: Trino 는 Thread 를 많이 생성하는 경향이 있으므로, Hyper Threading 이 성능에 도움이 됩니다.
Memory
RAM Size: 최소 256 GB 이상이 권장됩니다.
- Coordinator 는 큰 Memory Pool 을 사용하여 Query Planning 과 실행을 관리 하므로, 대규모 Query 를 처리할 때 더 많은 메모리가 필요합니다.
Memory Speed: DDR4 2933 MHz 이상의 고속 Memory 를 사용하는 것이 유리합니다. 빠를 수록 좋습니다.
Swap 사용 금지
OS 에서 Swap Memory 를 사용하지 않도록 설정하는 것이 좋습니다.
Swap 이 발생하면 성능 저하가 심각할 수 있습니다.
DISK
DISK 종류: NVMe 또는 SSD(Solid State Drive)가 최선의 선택입니다.
- Coordinator 는 Log 기록과 Metadata 를 자주 Access 하기 때문에 DISK I/O 성능이 매우 중요합니다.
RAID 구성: RAID 1+0 구성을 권장합니다. 성능과 가용성을 모두 확보할 수 있습니다.
- RAID 1+0 구성으로 내구성과 읽기/쓰기 성능 모두에 최적화 되기 때문에 이것을 추천합니다.
DISK Size 는 최소 1 TB 이상을 권장합니다.
Disk Partition Configuration
OS 와 데이터가 충돌하지 않도록 별도의 partition 을 사용하는 것이 좋습니다.
root partition (for OS): 100 GB 이상으로 설정하여, OS 및 기타 서비스가 안정적으로 실행되도록 합니다.
/var/log partition: Trino 는 log 를 많이 남기므로,
/var/log
에 충분한 디스크 공간을 할당합니다. 200GB 이상을 권장합니다./data partition: Trino 의 Metadata 와 Cache data 를 저장할 수 있도록 별도의 partition 을 구성합니다.
Network
Coordinator 는 여러 Worker Node 와 Data 를 주고받기 때문에 Network 성능이 중요합니다.
10 GbE 네트워크 또는 그 이상의 대역폭을 갖춘 NIC(Network Interface Card)를 권장합니다.
일반적인 Trino Coordinator Server 의 Spec Example (이 글에서는 이정도 Server Spec 을 기준으로 설명합니다.)
CPU: Intel Xeon Gold 6248 2.5 GHz, 24 Core/48 Thread
Memory: 512 GB DDR4 3200 MHz
DISK: 2 TB NVMe SSD, RAID 1+0 구성
Network: 10 GbE Network Interface
OS: CenOS 7.9, Ubuntu 20.04 LTS, RedHat Enterprise Linux 9
OS 는 Linux 기반이 적절합니다.
CentOS 7, Ubuntu 18.04 이상 또는 RedHat Enterprise Linux (RHEL)를 사용하는 것이 일반적 입니다.
안정성과 성능 최적화 측면에서 Linux 기반 환경이 가장 적합합니다.
Kernel 설정
Network 성능을 최적화하기 위해 TCP Buffer Size 를 조절
I/O 성능을 위해서
vm.swappiness=0
와 같이 조정
JVM 설정
- Java 버전은 OpenJDK 11 또는 17 을 사용하는 것이 적합하며, JVM Option 을 최적화하여 Memory 관리와 GC (Garbage Collection) 를 효율적으로 설정해야 합니다.
Resource Isolation
Trino Coordinator 가 과도한 Resource 를 소비하지 않도록 CPU 와 Memory 를 제한하는 cgroup 을 활용할 수 있습니다.
cgroup 을 통해 Coordinator 와 기타 System Process 간의 Resource 충돌을 방지할 수 있습니다.
High Availability (HA) 를 구성
Trino Coordinator 는 SPOF (Single Point of Failure) 입니다. 그래서 장애 대응이 필요합니다.
HAProxy 같은 Load Balancer 를 사용하여 다중 Coordinator Server 를 설정
Trino Coordinator JVM Configuration in Detail (for Optimal Performance)
일반적으로 Coordinator 는 Worker 보다 Memory 사용량이 적습니다.
불필요하게 큰 Heap Size 는 GC Pause Time 을 증가시킬 수 있습니다.
-Xmx
Cluster 의 Worker 규모를 30대 정도로 가정하면, 60GB 정도를 Optimal 값으로 합니다.
Heap Memory Size 를 60GB 를 사용하기 때문에 G1 GC 가 적절합니다.
-Xmx60g
로 설정합니다.
-XX:InitiatingHeapOccupancyPercent
Default 값은 45% 이지만, 30% ~ 40% 으로 조정하여 Coordinator 의 역할에 맞게 최적화 합니다.
Heap 사용량이 낮은 경우 GC 를 일찍 시작하여 Memory Leak 을 감지하고 Memory 관리를 효율화 할 수 있습니다.
-XX:InitiatingHeapOccupancyPercent=35
으로 조정합니다.
-XX:MaxGCPauseMillis
Coordinator 의 응답성을 높이기 위해 목표 GC Pause Time 을 설정 합니다.
200ms 가 Default 값 이지만, 100ms ~ 200ms 으로 설정하여 조금더 빠른 응답 속도를 보이도록 조정 합니다.
Coordinator 는 Query Planning, Scheduling 등 Latency 에 민감한 작업을 수행하므로 짧은 Pause Time 이 바람직 합니다.
-XX:MaxGCPauseMillis=150
으로 현실적으로 조정 합니다.
-XX:G1HeapRegionSize
기본적으로 G1 GC는 Heap Size 에 따라 자동으로 Heap Region Size 를 결정 합니다.
Heap Size 의 1/6400 의 비율이 적절 (60 GB / 6400 = 9.6 MB) 하다고 판단합니다.
-XX:G1HeapRegionSize=10M
으로 조정합니다.
-XX:+AlwaysPreTouch
추가JVM 시작 시 Heap Memory 를 미리 할당하여 Runtime 성능을 향상 시킵니다.
-XX:+AlwaysPreTouch
을 활성화 합니다.
-XX:ParallelGCThreads
와-XX:ConcGCThreads
System 의 CPU Core 수에 맞게 GC Thread 수를 조정 합니다.
-XX:ParallelGCThreads=48
를 CPU Thread 수에 맞춥니다.-XX:ConcGCThreads=12
로 CPU Thread 의 ¼ 수준으로 맞춥니다.
-XX:+UseStringDeduplication
G1 GC에서 동일한 문자열의 중복을 제거하여 Memory 사용량을 줄입니다.
동일한 Query 가 비슷하게 입력으로 들어올 확률이 높기 때문입니다.
-XX:+UseStringDeduplication
을 활성화 합니다.
-Xlog
GC log 를 남겨서 GC 가 적절히 수행되고 있는 지 Monitoring 합니다.
-Xlog:gc*,safepoint:file=/var/log/trino/trino-gc.log:time,uptime,level,tags:filecount=10,filesize=10M
✅ Trino Coordinator 최종 JVM Option
-Xmx60G -XX:+UseG1GC -XX:+ExplicitGCInvokesConcurrent -XX:+HeapDumpOnOutOfMemoryError -XX:+ExitOnOutOfMemoryError -XX:ReservedCodeCacheSize=512M -Dpresto-temporarily-allow-java8=true -Djdk.attach.allowAttachSelf=true -XX:InitiatingHeapOccupancyPercent=35 -XX:MaxGCPauseMillis=150 -XX:G1HeapRegionSize=10M -XX:ParallelGCThreads=48 -XX:ConcGCThreads=12 -XX:+AlwaysPreTouch -XX:+UseStringDeduplication -Xlog:gc*,safepoint:file=/var/log/trino/trino-gc.log:time,uptime,level,tags:filecount=10,filesize=20M
Trino Worker Configuration
Trino Worker Server는 대용량 데이터를 처리하고 쿼리를 실행하는 핵심적인 역할을 담당합니다.
Worker Node 의 성능은 Traffic 양, Query 복잡성, 처리 Data 의 크기 등에 크게 영향을 받기 때문에 Hardware 사양을 신중하게 설정하는 것이 매우 중요합니다.
보통 Coordinator 와 비슷한 Spec 의 Server 를 사용하지만, Coordinator 보다 CPU Clock, Core 개수가 더 많고 Memory 도 더 클 수록 좋습니다.
Trino Worker 로 사용할 Server 의 Hardware Spec 은 아래와 같은 것을 추천합니다.
CPU
CPU Cores: 최소 16 Core 이상, 가능하다면 24~32 Core 를 권장합니다.
- Worker 는 병렬 처리가 매우 중요 하므로 Multi Core CPU 가 필수입니다.
CPU Clock Speed: 고성능 Query 를 위해서는 High Clock 의 최신 CPU가 유리합니다.
- Intel Xeon Scalable 시리즈 또는 AMD EPYC 프로세서가 적합합니다.
Hyper Threading: Worker 는 Thread 를 많이 사용하기 때문에 Hyper Threading 이 성능 향상에 도움이 됩니다.
Memory
RAM 용량: Worker Node 는 Data 처리를 위한 Memory Pool 을 주로 사용 하므로, 최소 256GB 이상의 RAM 이 필요합니다. 대규모 Data 처리 작업의 경우 512GB 이상의 메모리가 필요할 수 있습니다.
메모리 속도: DDR4 2933 MHz 이상의 Memory Speed 가 권장됩니다. Worker Node 의 Memory 대역폭은 Query 성능에 직접적인 영향을 미칩니다.
DISK
DISK 종류: NVMe SSD 또는 고성능 SATA SSD가 적합합니다.
- Worker 는 DISK I/O에 큰 의존성을 가지므로, 빠른 Data Access 와 처리 성능을 위해 고속 SSD 를 사용하는 것이 좋습니다.
RAID 구성: RAID 1+0 을 권장합니다.
DISK Size: 각 Worker Node 는 최소 1TB 이상의 Disk 용량이 필요합니다. 특히 대규모 Data Set 을 처리할 때 충분한 여유 공간이 필요합니다.
DISK partition
Worker Node 의 DISK 는 I/O 성능을 최적화하기 위해 분리된 partition 을 사용하는 것이 좋습니다.
root partition (for OS): OS 와 기타 기본 서비스가 안정적으로 실행될 수 있도록 100GB 이상의 공간을 할당합니다.
/data partition: Worker 가 처리할 데이터와 중간 결과를 저장할 충분한 DISK 공간을 할당합니다.
/var/log partition: log file 이 많이 쌓일 수 있으므로, 100 ~ 200GB 의 공간을 별도로 할당하는 것이 좋습니다.
Network
Worker Node 는 Network Traffic 을 많이 주고 받으므로 최소 10GbE Network 또는 그 이상을 권장합니다.
Low Latency: Network Latency 를 최소화하기 위해 빠른 Switching 환경을 갖춘 Low Latency Network 설정이 필요합니다.
일반적인 Trino Worker Server 의 사양 예시 (이 글에서는 이 정도의 Spec 을 갖춘 Worker Server 를 기준으로 설명합니다.)
CPU: Intel Xeon Gold 6248R 2.4GHz, 24 Core/48 Thread
Memory: 512GB DDR4 3200MHz
DISK: 2TB NVMe SSD, RAID 1+0 구성
Network: 10GbE Network Interface
OS: CenOS 7.9, Ubuntu 20.04 LTS, RedHat Enterprise Linux 9
OS, JVM, Resource Isolation 는 Coordinator 와 동일한 수준으로 설정하면 좋습니다.
Storage & Caching
Local Disk Storage: Worker 는 Local DISK 에서 임시 Data 를 처리 하므로, 빠른 I/O 성능이 중요 합니다.
특히, SSD 나 NVMe DISK 에서 중간 데이터 저장 및 처리 성능이 크게 향상됩니다.
Distributed Storage Integration: HDFS, S3 와 같은 Distributed File System 을 사용할 경우, Local Cache DISK 를 적절히 활용하여 성능을 향상시킬 수 있습니다.
Trino Worker JVM Configuration in Detail (for Optimal Performance, G1 GC Version)
Trino Worker 는 대용량 데이터를 처리하며, Memory 사용 패턴이 급격하게 변할 수 있습니다.
Trino 는 일반적으로 대규모 Query 를 처리 하므로, 전체적인 처리량이 중요 합니다.
그러나 Worker Node 의 응답성이 지나치게 느려지면 Cluster 전체의 성능에 영향을 줄 수 있습니다.
Worker 도 Coordinator 와 동일하게 G1 GC 를 사용할 수 있지만, ZGC 를 사용하여 성능을 더 끌어 올릴 수 있습니다.
-Xmx
물리 메모리 용량의 약 70~80%를 사용하고, 나머지 메모리는 운영체제와 다른 프로세스에 할당되도록 남겨두는 것이 안정적 입니다.
Worker Memory 의 최대 가용량 = 512GB × 0.8 = 409.6GB
-Xmx410g
으로 설정합니다.
-XX:MaxGCPauseMillis
최대 GC 중단 시간을 설정하여 Application 의 응답성을 향상 시킵니다.
대용량 Heap 에서는 200ms 이하의 Pause Time 을 유지하기 어렵습니다.
현실적인 목표인 500ms 로 Pause Time 을 설정하여 G1 GC 가 응답성과 처리량 사이의 균형을 추구 하도록 합니다.
-XX:MaxGCPauseMillis=500
으로 설정합니다.
-XX:InitiatingHeapOccupancyPercent
Concurrent GC 가 시작되는 Heap 사용률을 조정하여 GC 빈도를 최적화 합니다.
대용량 Heap (410 GB) 에서 Heap 사용량이 급격히 증가할 수 있으므로, GC 사이클을 일찍 시작하여 메모리 부족 상황을 예방 합니다.
Heap 사용량이 30% 정도인 약 123GB 에 도달하면 GC 를 시작하여 Memory 관리의 안정성을 높입니다.
-XX:InitiatingHeapOccupancyPercent=30
-XX:G1HeapRegionSize
대용량 Heap 에서는 최대 크기인 32MB 로 설정될 수 있는데, 이를 16 MB 로 명시적으로 줄여 더 많은 Region 으로 나누어 세밀한 GC 를 수행하도록 설정합니다.
-XX:G1HeapRegionSize=16M
-XX:ParallelGCThreads
와-XX:ConcGCThreads
GC 작업에 적절한 Thread 수를 할당하여 GC 효율을 높입니다.
-XX:ParallelGCThreads
: 전체 CPU 코어 수와 동일하게 설정 합니다. (48)-XX:ConcGCThreads
: ParallelGCThreads의 1/4 로 설정합니다.-XX:ParallelGCThreads=48
으로 설정-XX:ConcGCThreads=12
으로 설정
-XX:+AlwaysPreTouch
JVM 시작 시 Heap Memory 를 미리 할당하여 Page Fault 로 인한 지연을 방지합니다.
큰 Heap Memory 를 사용하는 경우 JVM 시작 시간을 늘리지만 Runtime 성능에 이점이 있을 수 있습니다.
✅ Trino Worker 최종 JVM Option (G1 GC Version)
-Xmx410G -XX:+UseG1GC -XX:+ExplicitGCInvokesConcurrent -XX:+HeapDumpOnOutOfMemoryError -XX:+ExitOnOutOfMemoryError -XX:ReservedCodeCacheSize=512M -Dpresto-temporarily-allow-java8=true -Djdk.attach.allowAttachSelf=true -XX:InitiatingHeapOccupancyPercent=30 -XX:MaxGCPauseMillis=500 -XX:G1HeapRegionSize=16M -XX:ParallelGCThreads=48 -XX:ConcGCThreads=12 -Xlog:gc*,safepoint:file=/var/log/trino/trino-gc.log:time,uptime,level,tags:filecount=10,filesize=20M
Trino Worker JVM Configuration in Detail (for Optimal Performance, ZGC Version)
Java 11 이상 필요: ZGC 는 JDK 11 부터 도입 되었으며, JDK 17 LTS Version 에서 더욱 안정화되고 개선되었습니다. 그래서 OpenJDK 17 을 사용하는 것을 권장합니다.
Trino 356 Version 이상은 JDK 11 및 JDK 17 을 지원합니다.
ZGC 는 Heap Memory 크기에 관계없이 매우 낮은 GC Pause Time (일반적으로 1~2ms 이하) 를 유지하도록 설계되어 있습니다.
Heap Memory 가 수백 GB 인 경우에도 일관된 성능을 제공합니다.
이는 ZGC 가 대부분의 GC 작업을 Application Thread 와 병행하여 수행하기 때문입니다.
기존에 설정 했던 G1 GC Option 중에서 필요 없는 Option 들을 제거 합니다.
-XX:+UseG1GC -XX:MaxGCPauseMillis=500 -XX:G1HeapRegionSize=16M -XX:InitiatingHeapOccupancyPercent=30 -XX:ParallelGCThreads=48 -XX:ConcGCThreads=12
Java 8 관련 Option 을 제거합니다.
-Dpresto-temporarily-allow-java8=true
기타 불필요한 Option 을 제거 합니다.
# ZGC에서는 기본적으로 Full GC를 피하기 때문에 필요성이 낮습니다. -XX:+ExplicitGCInvokesConcurrent
ZGC 를 위한 기존의 (G1 GC) JVM Option 을 변경 합니다.
-XX:+UseZGC
- ZGC를 활성화합니다. JDK 17 이상에서는
-XX:+UnlockExperimentalVMOptions
옵션이 필요하지 않습니다.
- ZGC를 활성화합니다. JDK 17 이상에서는
-Xms
and-Xmx
ZGC 에서는 Heap 의 최소값과 최대값을 동일하게 설정하여 Memory 재 할당으로 인한 Overhead 를 방지합니다.
-Xms410g
로 최소 Heap 설정-Xmx410g
로 최대 Heap 설정
GC log
-Xlog:gc*,safepoint:file=/var/log/trino/trino-gc.log:time,uptime,level,tags:filecount=10,filesize=20M
-XX:+UseLargePages
- 큰 Page Memory 를 사용하여 TLB(Translation Lookaside Buffer) Miss rate 를 줄이고 Memory Access 성능을 향상시킵니다.
-XX:+AlwaysPreTouch
- JVM 이 Heap Memory 를 초기화 할 때 미리 모든 Page 를 Touch 하여 Page Fault 를 방지합니다.
-XX:+ParallelRefProcEnabled
- Reference 처리의 병렬화를 활성화하여 GC 성능을 향상 시킵니다.
✅ Trino Worker 최종 JVM Option (ZGC Version)
-Xms410G -Xmx410G -XX:+UseZGC -XX:+HeapDumpOnOutOfMemoryError -XX:+ExitOnOutOfMemoryError -XX:ReservedCodeCacheSize=512M -Djdk.attach.allowAttachSelf=true -XX:+UseLargePages -XX:+AlwaysPreTouch -XX:+ParallelRefProcEnabled -Xlog:gc*,safepoint:file=/var/log/trino/trino-gc.log:time,uptime,level,tags:filecount=10,filesize=20M
✅ OS Level 에서 최적화
Linux Kernel Parameter 를 수정할 수 있는 권한이 있어야 합니다.
Transparent Huge Pages(THP) 비활성화
THP 가 성능에 부정적 영향을 줄 수 있으므로 비활성화 하는 것이 좋습니다.
echo never > /sys/kernel/mm/transparent_hugepage/enabled
booting 시 자동 적용을 위해
/etc/rc.local
또는 시스템 설정 파일에 해당 명령을 추가합니다.
Huge Pages 활성화
Huge Page 를 사용하면 TLB (Translation Lookaside Buffer) Miss Rate 이 감소하여 Memory Access 성능이 향상됩니다.
설정 방법
Heap Memory Size (410GB) 를 고려하여 필요한 Page 수를 계산합니다.
예를 들어서, 2MB 의 Default Huge Page Size 를 사용하는 경우에는 아래와 같이 설정합니다.
필요한 페이지 수 = (410GB * 1024MB/GB) / 2MB = 209,920
/etc/sysctl.conf
파일에 다음을 추가합니다.vm.nr_hugepages=209920
설정 적용을 위해 다음 명령어를 실행합니다.
sudo sysctl -p
JVM Option 을 추가 하여야 합니다.
-XX:+UseLargePages -XX:LargePageSizeInBytes=2m
시스템에서 1GB Huge Pages 를 지원하는 경우에는 아래와 같은 Option 도 추가합니다.
-XX:LargePageSizeInBytes=1g
이 경우
vm.nr_hugepages
값도 다시 계산해야 합니다.
Swap Memory 비활성화를 진행 합니다.
Swap 사용은 GC 성능에 부정적인 영향을 미칩니다.
/etc/sysctl.conf
파일에 아래와 같은 내용을 추가 합니다.vm.swappiness=0
설정 적용을 위해 아래의 명령어를 실행합니다.
sudo sysctl -p
ulimit 설정 조정
File descriptor 및 process Limit 을 늘려야 할 수 있습니다.
Memory Mapping 및 File 사용 증가
- ZGC 는 Memory 관리와 GC 를 위해 내부적으로 Memory-mapped Files 을 더 많이 사용합니다. 이는 Process 가 열 수 있는 File descriptor 수를 늘리게 됩니다.
Trino Worker 는 데이터 처리 시 많은 수의 파일과 Network Socket 을 동시에 열 수 있습니다. 이는 데이터 소스 접근, 결과 저장, Worker 간 통신 등에 필요합니다.
프로세스 및 스레드 수 제한 (
ulimit -u
) 증가 필요Thread 수 증가: ZGC 는 병행 및 병렬 GC 를 위해 더 많은 GC Thread 를 생성합니다. 또한, 대용량 Heap 을 관리하기 위해 추가적인 작업 Thread 가 필요할 수 있습니다.
Trino 의 Multi-Threading: Trino 는 Query 실행 시 많은 작업을 병렬로 처리하며, 각 작업은 별도의 Thread 를 사용합니다.
ulimit -n 65536 ulimit -u 4096
Memory Lock
memlock 설정
Huge Page 사용 시 Memory 잠금 제한을 늘려야 합니다. (필수)
ZGC 에서 Huge Pages 를 사용할 경우, Process 가 잠글 수 있는 Memory 양을 늘려야 합니다. 기본 설정으로는 충분한 Memory 를 잠글 수 없어서 Huge Pages 를 활용하지 못할 수 있습니다.
memlock
값을unlimited
로 설정하여 Process 가 필요한 만큼 Memory 를 잠글 수 있도록 합니다./etc/security/limits.conf
파일에 다음을 추가합니다.soft memlock unlimited hard memlock unlimited
NUMA 설정
NUMA binding
Multi Socket Server 의 경우 NUMA Node 에 process 를 binding 하여 Memory Access Latency 를 최소화할 수 있습니다.
이를 통해 Memory 가 모든 NUMA Node 에 균등하게 분산됩니다.
Trino 실행 시, 아래와 같은 numactl 을 활용하여 설정합니다.
numactl --interleave=all <trino command>
ZGC 를 사용할 때 잠재적인 문제
File descriptor 및 Thread 부족 현상
Error 발생 가능성: File descriptor 나 Thread 수 제한이 낮으면 다음과 같은 에러가 발생할 수 있습니다.
"Too many open files"
"Unable to create new native thread"
성능 저하 및 시스템 불안정: 자원 제한으로 인해 Trino Worker Node 가 정상적으로 작동하지 못하고 성능 저하나 예기치 않은 종료가 발생할 수 있습니다.
ZGC 를 사용할 때는 대용량 Heap Memory 와 병렬 GC 작업으로 인해 운영체제의 자원 제한에 도달할 수 있습니다. 이를 방지하고 Trino Worker Node 의 성능과 안정성을 확보하기 위해
ulimit
설정을 늘려주는 것이 필요합니다.ulimit
값을 너무 높게 설정하면 시스템 자원이 고갈될 수 있으므로, 서버의 전체 자원(CPU, Memory, File descriptor 수 등)을 고려하여 적절한 값을 설정해야 합니다.일부 환경에서는 보안이나 안정성 이유로
ulimit
값을 높이는 것이 제한될 수 있으므로, 시스템 관리자나 보안 팀과 협의하여 설정 변경을 진행해야 합니다.
참고 문서
Subscribe to my newsletter
Read articles from Gyuhang Shim directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Gyuhang Shim
Gyuhang Shim
Gyuhang Shim Passionate about building robust data platforms, I specialize in large-scale data processing technologies such as Hadoop, Spark, Trino, and Kafka. With a deep interest in the JVM ecosystem, I also have a strong affinity for programming in Scala and Rust. Constantly exploring the intersections of high-performance computing and big data, I aim to innovate and push the boundaries of what's possible in the data engineering world.