Trino 아키텍처와 에러 파악하기

대용량 데이터 처리에 쓰일 수 있는 분산 SQL 엔진 중 대표적인 Trino에 대해서 알아봅니다.
Trino는 Facebook에서 개발된 Presto SQL에서 파생된 프로젝트입니다. 대규모 데이터셋에 대한 분산 SQL 쿼리를 제공하는 아키텍처이며 코디네이터-워크 노드로 구성되어 있습니다.

아키텍처

Trino 아키텍처는 크게 두 핵심 요소가 있습니다.

  • 코디네이터
  • 워커 노드

코디네이터(Coordinator)

쿼리 수신, 계획 수립, 작업 분배 및 전체적인 쿼리 진행을 관리하는 중심 역할을 합니다.

1. 쿼리 파싱 및 분석

  • 사용자가 실행한 SQL 쿼리를 수신한 후, 이를 파싱 하여 구문을 분석합니다.
  • 쿼리 문법과 구조를 분석하여 쿼리 실행이 가능한지 확인하고, 최적화된 실행 계획을 수립합니다.

2. 실행 계획(Execution Plan) 수립

  • 쿼리의 논리적 실행 계획을 수립하고, 이를 기반으로 실제 실행 계획을 생성합니다. 이 과정에서는 쿼리의 효율을 최대화하기 위해 다양한 최적화 작업이 수행됩니다.
  • 예를 들어, 데이터 소스에 접근하는 방식이나, 조인 순서 등을 최적화하여 쿼리 성능을 높입니다.

3. 작업(Task) 분배

  • 쿼리를 여러 개의 태스크로 분할하고, 이를 각 워크 노드에 할당합니다. Trino의 워크 노드는 할당된 작업을 병렬로 처리할 수 있으므로, 코디네이터는 이를 최적화된 방식으로 나누어 워크 노드의 부하를 분산시킵니다.
  • 코디네이터는 각 워크 노드가 담당할 데이터를 지정하고, 워크 노드 간 데이터 이동이 필요한 경우도 효율적으로 관리합니다.

4. 워크 노드 모니터링 및 에러 관리

  • 각 워크 노드의 작업 상태를 모니터링하여 쿼리가 원활하게 진행되고 있는지 확인합니다.
  • 특정 워크 노드에 문제가 발생하거나 작업에 실패한 경우, 코디네이터는 이를 감지하고 필요한 경우 작업을 재시도하거나 에러를 처리합니다.
  • 코디네이터는 기본적인 내결함성(fault tolerance) 기능도 일부 제공하지만 설계상 특정 워커 노드에 자동으로 작업을 다른 노드에 완전히 리다이렉트 하는 기능이 제한적이기 때문에 해당 쿼리는 전체적으로 실패할 수 있습니다. 특히 join연산이나 대규모 데이터 처리 중 장애가 발생했을 때 다른 노드로 자동 재할당되지 않는 경우가 많다고 합니다.

5. 결과 수집 및 반환

  • 모든 워크 노드의 작업이 완료되면 결과를 수집하여 사용자가 요청한 형식으로 최종 결과를 반환합니다.
  • 코디네이터는 필요한 경우 중간 결과를 집계하여 최종 결과를 계산하고 사용자에게 전달합니다.

Trino 코디네이터는 클러스터에서 발생하는 모든 쿼리의 시작과 끝을 책임지기 때문에 Trino의 성능과 안정성에 매우 중요한 역할을 합니다. 코디네이터의 성능과 안정성을 확보하기 위해 충분한 리소스와 모니터링이 필요하며, 대규모 클러스터의 경우 코디네이터의 성능이 전체 쿼리 처리 속도에 직접적인 영향을 미칠 수 있습니다.

워커 노드(Worker Nodes)

코디네이터로부터 할당된 작업을 수행하며 실제 데이터를 처리하고 쿼리 결과를 계산합니다.

아키텍처 흐름도

코디네이터와 워크 노드는 긴밀히 협력하여 쿼리를 처리합니다. 코디네이터가 쿼리 실행을 총괄하는 중앙 관리 역할을 맡는 반면, 워크 노드는 실제로 데이터를 읽고, 처리하고, 연산을 수행하는 역할을 합니다. 각 워크 노드는 코디네이터로부터 독립적으로 작업을 수행하므로, 클러스터의 워크 노드 수를 늘리면 Trino는 대규모 데이터를 더 빠르게 처리할 수 있게 됩니다.


Trino QueryError: NO_NODES_AVAILABLE, message="No worker nodes avaliable"

트리노 구조에 대해서 이해한다면 Trino QueryError 발생 시 다양한 원인에 대해서 어느 지점을 더 봐야 하는지, 어떤 관계이길래 영향을 받는 건지 알 수 있습니다. 메시지대로 코디네이터가 쿼리를 처리할 수 있는 워커 노드를 찾지 못했음을 의미합니다. 원인은 워커 노드의 상태 이상/ 설정 오류/ 코디네이터와 워커 노드 간의 네트워크 통신 문제 경우일 수 있습니다.

워커 노드 상태

  • 코디네이터는 워커 노드들이 정기적으로 보내는 heartbeat 신호를 통해 워커 노드가 정상적으로 운영 중인지 확인합니다. 만약 워커 노드가 코디네이터에 heartbeat를 보내지 못하면, 코디네이터는 해당 워커 노드를 사용할 수 없는 것으로 간주하고 쿼리 처리를 중단합니다.
    • 트랜잭션성 및 장애 복구 기능의 한계
      Trino는 데이터 웨어하우스 및 분석용 분산 SQL 엔진으로 설계되어 트랜잭션성보다는 고속 데이터 처리에 초점을 맞추고 있어, Apache Spark와 같은 내결함성이 강한 엔진만큼 세밀한 태스크 장애 복구를 제공하지 않습니다. 이로 인해 장애가 발생하면 쿼리를 다시 실행해야 할 수 있습니다
  • 워커 노드의 상태가 지속적으로 비활성화된다면, 워커 노드의 리소스 상태(CPU, 메모리)를 확인하고, 트리노 프로세스가 정상적으로 실행되고 있는지 점검할 필요가 있습니다.
  • 워커 노드의 jvm.config 파일에서 메모리 설정을 확인하고, 필요시 리소스를 확장해주어야 합니다. 특히 대규모 쿼리 실행 시 메모리 부족으로 인해 노드가 비활성화될 수 있습니다.

설정 파일 오류 점검

  • Trino의 설정 파일(node.properties, config.properties, jvm.config 등)에서 잘못된 구성으로 인해 워커 노드가 코디네이터와 올바르게 통신하지 못하는 경우도 있습니다.
  • node.environment: 모든 워커 노드와 코디네이터의 node.environment 설정이 동일해야 합니다. 이 설정이 다르면 코디네이터가 해당 워커 노드를 인식하지 못합니다.
  • discovery.uri: 워커 노드의 config.properties 파일에서 discovery.uri 값이 코디네이터의 URI와 일치하는지 확인하세요. 이 URI는 코디네이터의 네트워크 주소 및 포트를 가리켜야 하며, 잘못된 URI로 설정되어 있을 경우 워커 노드가 코디네이터에 연결할 수 없습니다.

네트워크 연결 및 방화벽 문제

  • 코디네이터와 워커 노드 간에 네트워크 통신이 원활하지 않으면 코디네이터는 워커 노드를 사용 불가능한 상태로 인식하게 됩니다.
  • 워커 노드와 코디네이터 간의 포트가 열려 있는지 확인하고, 필요한 경우 네트워크 팀과 협력하여 방화벽 설정을 검토가 필요합니다.
  • 특히 클라우드 환경이나 가상 네트워크를 사용할 경우, 각 노드가 서로 통신할 수 있는 동일한 네트워크 또는 서브넷에 위치해야 합니다.

클러스터 불안정성 및 워커 노드의 주기적 재시작 문제

  • 워커 노드가 주기적으로 중단되거나 재시작하는 경우, 이 에러가 발생할 수 있습니다. 이는 메모리 누수, 리소스 과부하, 혹은 비정상 종료 등의 원인일 수 있습니다.
  • Trino 로그 파일에서 java.lang.OutOfMemoryError 또는 GC overhead limit exceeded 등의 메모리 오류 메시지가 있다면 메모리 설정을 늘리거나, 워커 노드를 추가하여 부하를 분산하는 것이 좋습니다. Zookeeper 설정 문제
  • 만약 Trino 클러스터가 Zookeeper를 사용하여 코디네이터와 워커 노드 간의 정보를 공유하고 있다면, Zookeeper 설정이 잘못될 경우 코디네이터가 워커 노드를 찾지 못할 수 있습니다.
  • Zookeeper에 정상적으로 접속되고 있는지 확인하고, Zookeeper 서버가 안정적으로 운영되고 있는지 확인 필요합니다.

워커 추가

만약 현재 클러스터에 워커 노드가 충분하지 않거나, 대규모 쿼리가 자주 발생하는 환경이라면 추가 워커 노드를 추가하여 부하를 분산하는 것이 좋습니다. Trino는 기본적으로 수평 확장이 가능하므로 워커 노드를 추가하면 클러스터의 성능과 안정성이 향상될 수 있습니다.

마무리

Trino의 아키텍처 개념을 이해하고 자주 발생하는 오류 메시지의 다양한 원인에 대해 정리해 보았습니다. 대규모 데이터 분석 환경에서 쿼리 엔진을 안정적으로 운영하려면, 노드 상태 모니터링과 효율적인 쿼리 최적화를 꾸준히 실천하고, 다양한 에러 처리 전략을 익히는 것이 중요합니다.

기술 스택에 대한 아키텍처 소개를 읽다 보면, 각각의 시스템이나 엔진에서 사용하는 용어는 다르지만 큰 역할은 비슷한 경우가 많습니다. 큰 구조는 비슷해 보이지만, 세부 요소와 설계 철학이 다르다는 점에서 차이를 찾아보는 재미도 있었고, 그런 차이점을 정확히 아는 것이 내가 원하는 기술을 선택하는 데 큰 도움이 된다는 생각이 들었습니다.

참고자료

'DataEngineering' 카테고리의 다른 글

Spark 아키텍처: Driver, Executor 실행 및 환경변수 참조 위치  (0) 2025.03.16
dbt sql modeling  (0) 2025.03.02
Spark tuning  (0) 2024.03.17
[Spark] Spark run in Cluster Mode-YARN  (1) 2024.02.04
[Airflow] Operators  (0) 2024.01.21