Trino Fault-tolerant Execution 심화 — Exchange Manager 와 재시도 정책
장시간 ETL 배치 도중 워커가 죽어도 쿼리를 살리는 Trino 의 FTE 를 깊게 들여다봅니다. QUERY vs TASK 재시도 정책, exchange manager(스풀 저장소) 구성, 스팟 인스턴스 운영, 그리고 대화형 쿼리에서 켜면 안 되는 이유까지.
Trino 의 기본 실행 모델은 "all-or-nothing" 입니다. 쿼리를 구성하는 태스크 중 하나라도 실패하면 쿼리 전체가 실패합니다. 짧은 대화형 쿼리에서는 다시 던지면 그만이지만, 몇 시간짜리 ETL 배치가 마지막 단계에서 워커 한 대가 죽어 통째로 날아간다면 이야기가 다릅니다.
Fault-tolerant Execution(FTE) 은 이 문제를 해결합니다. 중간 결과를 외부 스토리지에 스풀해 두고, 실패한 단위만 다른 워커에서 재시도합니다. 이 글은 FTE 가 내부적으로 어떻게 동작하는지, 어떻게 설정하는지, 그리고 언제 켜고 언제 꺼야 하는지를 정리합니다.
1. 왜 FTE 가 필요한가 — 기본 실행 모델의 한계
일반 모드에서 Trino 는 스테이지 간 데이터를 메모리/네트워크로 직접 스트리밍(streaming exchange)합니다. 빠르지만, 중간 데이터가 어디에도 보존되지 않습니다.
[일반 모드] Stage1 ──메모리 스트리밍──> Stage2 ──> Stage3
워커 한 대라도 죽으면 → 전체 쿼리 FAIL → 처음부터 다시데이터 규모가 크고 실행이 길수록 "도중에 워커가 죽을 확률"이 올라갑니다. 스팟 인스턴스를 쓰면 회수(reclaim)로 워커가 수시로 사라지므로 이 확률은 더 커집니다. 긴 배치를 매번 처음부터 재실행하는 것은 비용과 시간 모두 낭비입니다.
2. FTE 의 핵심 아이디어 — 중간 결과 스풀
FTE 는 스테이지 간 데이터를 직접 스트리밍하는 대신, exchange manager 를 통해 외부 스토리지(S3/GCS/HDFS 등)에 스풀합니다. 중간 결과가 보존되므로, 워커가 죽어도 그 지점부터 다시 시작할 수 있습니다.
[FTE 모드] Stage1 ──> [Exchange: S3 스풀] ──> Stage2 ──> [Exchange: S3 스풀] ──> Stage3
워커가 죽으면 → 스풀된 중간 결과로 실패한 부분만 재시도| 일반(streaming) | FTE(spooling) | |
|---|---|---|
| 스테이지 간 데이터 | 메모리/네트워크 직접 전달 | exchange manager 가 외부 스토리지에 스풀 |
| 워커 소실 시 | 쿼리 전체 실패 | 실패 단위만 재시도 |
| 지연(latency) | 낮음 | 스풀 I/O 만큼 증가 |
| 적합 | 대화형 쿼리 | 장시간 ETL 배치 |
3. 두 가지 재시도 정책 — QUERY vs TASK
FTE 는 retry-policy 로 재시도 단위를 정합니다.
# etc/config.properties
retry-policy=TASK| 정책 | 재시도 단위 | 동작 | 적합 |
|---|---|---|---|
QUERY | 쿼리 전체 | 실패 시 쿼리를 통째로 다시 실행 | 짧은 쿼리가 많은 대화형 클러스터 |
TASK | 개별 태스크 | 실패한 태스크만 다른 워커에서 재시도 | 장시간·대규모 ETL 배치 |
QUERY 정책
쿼리가 실패하면 코디네이터가 자동으로 전체를 재실행합니다. 사용자는 실패를 모르고 결과만 받습니다. 짧은 쿼리에 적합하고, exchange manager 없이도(작은 결과는 코디네이터 메모리에) 동작할 수 있지만, 큰 쿼리에는 exchange manager 가 권장됩니다.
TASK 정책
쿼리를 구성하는 개별 태스크 단위로 재시도합니다. 반드시 exchange manager 가 필요합니다. 장시간 배치에서 한 워커가 죽어도 그 워커가 하던 태스크만 살아있는 다른 워커로 넘겨 재실행하므로, 전체를 다시 돌리지 않습니다. 또한 TASK 모드는 적응형 태스크 스케줄링이 가능해, 워커 수가 변해도(오토스케일·스팟) 유연하게 대응합니다.
규칙: 대화형 클러스터는
QUERY, ETL/배치 클러스터는TASK. 하나의 클러스터에서 둘을 섞고 싶다면 세션 레벨로 전환할 수 있습니다 —SET SESSION retry_policy = 'TASK'.
4. Exchange Manager 구성
TASK 정책(그리고 큰 QUERY)에는 exchange manager 가 필수입니다. 스풀 저장소를 지정합니다.
# etc/exchange-manager.properties
exchange-manager.name=filesystem
exchange.base-directories=s3://trino-exchange/spool
exchange.encryption-enabled=trueS3 자격증명·엔드포인트는 파일시스템 설정을 따릅니다.
# 같은 파일 또는 config 에서 S3 접근 설정
exchange.s3.region=ap-northeast-2
exchange.s3.endpoint=https://s3.ap-northeast-2.amazonaws.com스풀 저장소 선택
| 저장소 | 장점 | 고려사항 |
|---|---|---|
| S3 / GCS / Azure Blob | 무제한 용량, 클러스터와 분리 | 네트워크 지연, 요청 비용 |
| HDFS | 온프레미스 기존 자산 활용 | NameNode 부하 |
| 로컬 디스크(여러 워커 공유 X) | 빠름 | 워커 소실 시 스풀도 소실 → FTE 무의미 |
핵심: 스풀 저장소는 워커와 생명주기가 분리되어야 합니다. 워커가 죽었을 때 스풀이 남아있어야 재시도가 가능하기 때문에, 로컬 디스크는 부적합하고 오브젝트 스토리지가 정석입니다.
여러 저장소 분산
대규모 클러스터에서는 스풀 I/O 가 병목이 될 수 있어, 여러 디렉터리/버킷에 분산합니다.
exchange.base-directories=s3://trino-exchange-1/spool,s3://trino-exchange-2/spool5. 관련 튜닝 파라미터
FTE 의 동작을 세밀하게 조정하는 옵션들입니다.
| 파라미터 | 역할 |
|---|---|
fault-tolerant-execution-task-memory | TASK 모드에서 태스크당 메모리 추정치(스케줄링 단위) |
fault-tolerant-execution-target-task-input-size | 태스크 입력 목표 크기 (태스크 분할 입도) |
fault-tolerant-execution-target-task-split-count | 태스크당 split 목표 수 |
fault-tolerant-execution-max-task-split-count | 태스크당 split 상한 |
exchange.compression-enabled | 스풀 데이터 압축으로 I/O·비용 절감 |
query.low-memory-killer.policy | 메모리 부족 시 죽일 대상 선정 정책 |
압축은 거의 항상 켜는 것이 이득입니다(네트워크·스토리지 비용 절감). 태스크 입력 크기는 너무 작으면 오버헤드가, 너무 크면 재시도 비용이 커지므로 워크로드에 맞춰 조정합니다.
6. FTE 와 스팟 인스턴스 — 비용 절감의 핵심
FTE 의 가장 강력한 활용처는 스팟 인스턴스로 워커를 운영하는 것입니다.
온디맨드 워커 100% → 안정적이지만 비쌈
스팟 워커 + FTE(TASK) → 회수돼도 태스크 재시도로 완주, 비용 최대 70~90% 절감스팟 회수로 워커가 갑자기 사라져도, 스풀된 중간 결과 덕분에 살아있는 워커가 태스크를 이어받습니다. Kubernetes 환경이라면 코디네이터는 온디맨드, 워커는 스팟 + FTE 조합이 정석입니다. (Kubernetes 배포는 별도 글 "Trino 를 Kubernetes 에 배포하기"에서 다뤘습니다.)
7. 트레이드오프 — FTE 를 켜면 잃는 것
FTE 는 공짜가 아닙니다.
- 지연 증가: 모든 스테이지 경계에서 외부 스토리지에 쓰고 다시 읽으므로, 짧은 쿼리는 오히려 느려집니다. 밀리초~초 단위 대화형 쿼리에는 부적합합니다.
- 스토리지 비용/요청: S3 PUT/GET 요청과 저장 용량 비용이 발생합니다. 압축으로 완화하세요.
- 운영 복잡도: exchange manager, 스풀 버킷, 권한, 정리(lifecycle) 정책을 관리해야 합니다.
| 워크로드 | 권장 |
|---|---|
| BI 대시보드, 대화형 분석 | FTE 끄기 (streaming) |
| 짧은 쿼리 다수 | QUERY (선택) |
| 장시간 ETL, 대규모 조인/집계 | TASK + exchange manager |
| 스팟 워커 클러스터 | TASK + exchange manager (필수에 가까움) |
8. 검증 — FTE 가 실제로 동작하는지
-- 현재 세션의 재시도 정책 확인
SHOW SESSION LIKE 'retry_policy';
-- 세션 단위로 전환 (대화형 클러스터에서 무거운 배치 하나만 FTE 로)
SET SESSION retry_policy = 'TASK';실행 후 코디네이터 Web UI 의 Query Detail 에서 재시도된 태스크가 있었는지, exchange 가 spooling 으로 동작했는지 확인할 수 있습니다. 스팟 회수 테스트로 워커를 의도적으로 죽여보고 쿼리가 완주하는지 검증하는 것을 권장합니다.
9. 스풀 저장소 정리 (Lifecycle)
스풀 데이터는 쿼리 종료 시 Trino 가 정리하지만, 비정상 종료·중단으로 고아 객체가 남을 수 있습니다. 버킷에 lifecycle 정책(예: prefix spool/ 의 객체를 1~3일 후 자동 삭제)을 걸어 비용 누수를 막으세요.
S3 Lifecycle Rule: prefix "spool/", expire after 2 days10. 정리
| 항목 | 일반 모드 | FTE 모드 |
|---|---|---|
| 실패 처리 | 쿼리 전체 실패 | 태스크/쿼리 단위 재시도 |
| 중간 데이터 | 메모리 스트리밍 | exchange manager 스풀 |
| 지연 | 낮음 | 스풀 I/O 만큼 증가 |
| 스팟 운영 | 위험 | 안전 (큰 비용 절감) |
| 적합 워크로드 | 대화형 | 장시간 배치 |
FTE 는 "안정성을 위해 약간의 지연을 지불"하는 기능입니다. 대화형 클러스터에는 켜지 말고, 장시간 ETL 과 스팟 기반 배치 클러스터에는 TASK 정책 + 오브젝트 스토리지 exchange manager 로 구성하세요. 스풀 압축을 켜고 버킷에 lifecycle 정책을 걸면, 안정성과 비용 두 마리를 모두 잡을 수 있습니다.
이 글은 Trino 440번대 기준으로 작성되었습니다. 대규모 배치의 안정화나 스팟 기반 비용 최적화가 필요하시면 언제든 문의해 주세요.
— Data Dynamics 엔지니어링 팀