Trino 개념 — 클러스터·카탈로그·스키마와 분산 실행 모델
Trino 개념 — 클러스터·카탈로그·스키마와 분산 실행 모델
Trino를 잘 쓰려면 문서 곳곳에 등장하는 용어부터 확실히 알아야 해요. 사용자 입장에서도 stages와 splits 같은 개념을 이해하면 쿼리를 더 효율적으로 짤 수 있고, 관리자나 기여자라면 stages가 tasks로, tasks가 drivers로 어떻게 분해되는지 알아야 진짜 Trino를 이해했다고 할 수 있어요. 이 글에서는 핵심 개념을 일반적인 것에서 구체적인 순서로 정리해 드릴게요.
본문
아키텍처: 코디네이터와 워커
Trino는 여러 서버에서 데이터를 병렬로 처리하는 분산 쿼리 엔진이에요. Trino 서버는 두 종류로 나뉘어요 — **코디네이터(coordinator)**와 **워커(worker)**예요.
- 클러스터(Cluster): 하나의 코디네이터와 0개 이상의 워커로 구성돼요. 사용자는 SQL 툴로 코디네이터에 접속하죠. 코디네이터가 워커와 협력하고, 둘 다 데이터소스에 접근해요. 이 접근 설정이 카탈로그랍니다. 각 쿼리 처리는 상태를 유지하는 작업으로, 코디네이터가 총괄하고 클러스터 전체 워커에 병렬로 분산돼요.
- 노드(Node): 클러스터에 속한 Trino 서버 하나를 가리켜요. 기술적으로는 Trino 프로그램을 실행하는 Java 프로세스를 뜻하지만, 보통 한 컴퓨터에 Trino 프로세스 하나만 돌리도록 권장해서 노드 = 컴퓨터로 쓰이기도 해요.
- 코디네이터(Coordinator): 문장(statement)을 파싱하고 쿼리를 계획하며 워커 노드를 관리하는 서버예요. Trino 설치의 "두뇌"이며, 클라이언트가 실행을 위해 접속하는 노드죠. 코디네이터는 각 워커의 활동을 추적하고 쿼리 실행을 조율해요. 쿼리를 일련의 stages로 구성한 논리 모델로 만들고, 이를 Trino 워커 클러스터 위에서 도는 연결된 tasks로 변환해요. REST API로 워커·클라이언트와 통신해요.
- 워커(Worker): 작업(task)을 실행하고 데이터를 처리하는 서버예요. 커넥터에서 데이터를 가져오고 워커끼리 중간 데이터를 교환해요. 최종 결과를 모아 클라이언트에 돌려주는 건 코디네이터의 몫이에요. 워커 프로세스는 시작할 때 코디네이터의 디스커버리(discovery) 서버에 자신을 알려서 실행 대상이 되죠.
플러그인과 데이터소스
Trino는 플러그인 아키텍처로 확장돼요. 다양한 데이터소스와 시스템을 통합하기 위한 수단이죠. 데이터소스에는 데이터레이크·레이크하우스, 수많은 관계형 DBMS, 키-값 저장소 등이 포함돼요. 데이터소스에 접근하려면 해당 커넥터로 카탈로그를 설정하면 돼요.
커넥터(Connector)
커넥터는 Trino를 데이터소스에 적응시키는 어댑터예요. Hadoop/Hive나 Apache Iceberg 데이터레이크, PostgreSQL 같은 관계형 DB에 연결하죠. 데이터베이스의 "드라이버"와 같은 역할로 생각하면 쉬워요. Trino의 SPI(서비스 제공자 인터페이스) 구현체라서 표준 API로 리소스와 상호작용해요. Trino에는 Delta Lake, Hive, Hudi, Iceberg, MySQL, PostgreSQL, Oracle, SQL Server, Cassandra, ClickHouse, OpenSearch, Pinot, Prometheus, SingleStore, Snowflake, JMX, System, TPC-H 등 수많은 내장 커넥터가 있어요.
모든 카탈로그는 특정 커넥터를 사용해요. 카탈로그 설정 파일을 열어 보면 connector.name 프로퍼티가 커넥터를 식별하는 값으로 반드시 들어 있어요. 예를 들어 설정 파일에 보통 이렇게 적혀 있어요.
connector.name=postgresql
connection-url=jdbc:postgresql://example.net:5432/database
connection-user=root
connection-password=secret
카탈로그(Catalog)
카탈로그는 특정 데이터소스에 접근하기 위한 설정 속성의 모음이에요. 필요한 커넥터와 자격 증명, URL 같은 세부 정보를 담아요. Trino 설정 디렉터리의 프로퍼티 파일로 정의되며, 파일 이름이 곧 카탈로그 이름이 돼요. 예를 들어 etc/example.properties 파일은 example이라는 카탈로그를 만들어요.
카탈로그는 여러 개를 동시에 설정할 수 있어요. 예를 들어 두 개의 데이터레이크가 있다면 둘 다 Hive 커넥터를 쓰는 카탈로그 두 개를 한 클러스터에 두고, 심지어 같은 SQL 쿼리 안에서 두 클러스터 데이터를 조회할 수도 있어요. 한 데이터레이크를 Hive 커넥터로, 다른 레이크하우스를 Iceberg 커넥터로 각기 다른 카탈로그로 묶거나, 서로 다른 PostgreSQL 데이터베이스에 접근하는 카탈로그를 여러 개 두는 것도 자유로워요.
카탈로그는 하나 이상의 스키마를 담고, 스키마는 테이블·뷰·머티어리얼라이즈드 뷰 같은 객체를 담아요. Trino에서 객체를 지칭할 때 정규화된 이름(full name)은 항상 카탈로그로 시작해요. 예를 들어 example.test_data.test라는 정규화된 테이블 이름은 example 카탈로그의 test_data 스키마에 있는 test 테이블을 뜻해요.
스키마(Schema)와 테이블(Table)
스키마는 테이블을 정리하는 방법이에요. 카탈로그와 스키마가 함께 질의 가능한 테이블·객체 집합을 정의하죠. Hive나 MySQL 같은 관계형 DB에 접근할 때 스키마는 대상 데이터베이스의 같은 개념으로 매핑돼요. 테이블은 타입을 가진 이름 있는 컬럼들로 구성된 순서 없는 행의 집합이에요. 소스 데이터에서 Trino 타입으로의 매핑은 커넥터가 정의해요.
쿼리 실행 모델 — 분산 실행
Trino는 SQL 문장을 실행해 쿼리로 만들고, 이를 코디네이터와 워커로 이루어진 분산 클러스터에서 실행해요.
- 문장(Statement): ANSI 호환 SQL 문장의 텍스트 표현이에요. 절(clause)·식(expression)·술어(predicate)로 구성돼요.
- 쿼리(Query): Trino가 문장을 파싱하면 쿼리로 변환하고 **분산 쿼리 계획(distributed query plan)**을 만들어요. 이 계획은 워커에서 실행되는 일련의 상호 연결된 stages로 실현돼요. 즉 문장은 "넘겨준 SQL 텍스트", 쿼리는 "그 문장을 실행하기 위해 만들어진 구성과 컴포넌트"예요.
- 스테이지(Stage): 쿼리 실행을 계층 구조로 쪼갠 조각이에요. 예컨대 Hive에 저장된 10억 행을 집계하려면, 여러 하위 stage의 출력을 집계하는 root stage를 두고 각 stage가 분산 쿼리 계획의 다른 부분을 담당해요. stage 계층은 트리(tree) 모양이에요. 중요한 건 stage 자체는 워커에서 실행되지 않는다는 점이에요.
- 태스크(Task): stage는 워커 네트워크 위에 분산된 일련의 tasks로 구현돼요. 분산 쿼리 계획이 stages로 분해되고, stages는 tasks로 변환되며, tasks는 splits를 처리하죠. task는 입출력을 갖고, stage가 여러 tasks로 병렬 실행되듯 task도 여러 drivers로 병렬 실행돼요.
- 스플릿(Split): 더 큰 데이터셋의 일부분이에요. 계획의 최하위 stage는 커넥터에서 splits를 통해 데이터를 가져오고, 상위 stage는 다른 stage에서 데이터를 받아요. 쿼리를 스케줄링할 때 코디네이터는 커넥터에게 테이블에 사용 가능한 splits 목록을 묻고, 어느 머신이 어느 task를, 어느 split을 처리 중인지 추적해요.
- 드라이버(Driver): task는 하나 이상의 병렬 드라이버를 포함해요. 드라이버는 데이터에 작용해 operator들을 조합해 출력을 만들고, task가 이를 모아 다른 stage의 task로 전달해요. operator 인스턴스들의 시퀀스로, Trino 아키텍처에서 가장 낮은 수준의 병렬성이에요. 입력 하나, 출력 하나를 가져요.
- 오퍼레이터(Operator): 데이터를 소비·변환·생성해요. 테이블 스캔 연산자는 커넥터에서 데이터를 가져와 다른 연산자가 소비할 수 있게 만들고, 필터 연산자는 입력에 술어를 적용해 부분집합을 만들어 내죠.
- 익스체인지(Exchange): 쿼리의 서로 다른 stage 간에 Trino 노드 사이에서 데이터를 전송해요. task는 출력 버퍼로 데이터를 만들고, 익스체인지 클라이언트로 다른 task의 데이터를 소비해요.
이렇게 Trino의 실행 모델은 문장 → 쿼리 → 스테이지 → 태스크 → 드라이버 → 오퍼레이터로 내려가며 분산 병렬 처리돼요. 이 사다리를 기억하면 EXPLAIN 결과도, 웹 UI의 쿼리 화면도 훨씬 쉽게 읽을 수 있어요.