신뢰성
신뢰성 (Reliability)
아이스버그는 S3에서 실행되는 하이브 테이블이 겪는 정확성 문제를 해결하기 위해 설계됐어요. 이 문서에서는 아이스버그가 어떻게 원자적(atomic) 커밋과 직렬화 가능한 격리(serializable isolation)를 보장하는지, 그리고 파일 목록 나열 대신 메타데이터 트리 구조를 사용해 어떤 성능·신뢰성 이점을 얻는지 설명해드릴게요. 결국 핵심은 스냅샷 기반의 변경 이력과 낙관적 동시성(optimistic concurrency)이에요.
출처: 문서
본문
아이스버그는 S3에서 실행되는 하이브 테이블에 영향을 주는 정확성 문제를 해결하기 위해 설계됐어요.
하이브 테이블은 파티션을 위한 중앙 메타스토어(metastore)와 개별 파일을 위한 파일 시스템을 함께 사용해서 데이터 파일을 추적해요. 그래서 테이블 내용에 대한 원자적인 변경이 불가능하고, 최종 일관성(eventually consistent)을 갖는 S3 같은 스토어는 파일 목록 나열(listing)로 테이블 상태를 재구성하기 때문에 잘못된 결과를 반환할 수 있어요. 또한 작업 계획 시 파티션 수에 비례하는 O(n) 번의 느린 목록 호출을 해야 해요.
아이스버그는 영속적인 트리(persistent tree) 구조를 사용해서 각 스냅샷의 데이터 파일 전체 목록을 추적해요. 모든 쓰기나 삭제는 이전 스냅샷의 메타데이터 트리를 최대한 재사용해서 새 스냅샷을 만들어 내요. 그래서 쓰기 볼륨이 커지지 않아요.
아이스버그 테이블의 유효한 스냅샷들은 현재 스냅샷에 대한 참조와 함께 테이블 메타데이터 파일에 저장돼요. 커밋은 원자적인 연산으로 현재 테이블 메타데이터 파일의 경로를 교체해요. 이렇게 해서 테이블 데이터와 메타데이터에 대한 모든 업데이트가 원자적임을 보장하고, 이것이 직렬화 가능한 격리의 기반이 돼요.
그 결과 신뢰성이 크게 개선돼요.
- 직렬화 가능한 격리: 모든 테이블 변경이 원자적 테이블 업데이트의 선형 이력(linear history)으로 이뤄져요
- 신뢰할 수 있는 읽기: 잠금(lock) 없이도 읽는 쪽은 항상 일관된 스냅샷을 사용해요
- 버전 이력과 롤백: 테이블 스냅샷이 이력으로 보관되고, 작업이 잘못된 데이터를 만들면 테이블을 롤백할 수 있어요
- 안전한 파일 수준 연산: 원자적 변경을 지원하므로 작은 파일을 안전하게 컴팩션하거나 지연된 데이터를 안전하게 추가하는 등 새로운 사용 사례가 가능해져요
이 설계는 성능 면에서도 이점이 있어요.
- O(1) RPC로 계획: 작업을 계획하기 위해 테이블의 O(n) 개 디렉터리를 나열하는 대신, 스냅샷 하나를 읽는 데 O(1) RPC 호출만 필요해요
- 분산 계획: 파일 프루닝(pruning)과 조건 푸시다운(predicate push-down)이 작업에 분산되어 메타스토어가 병목이 되지 않아요
- 더 세밀한 파티셔닝: 분산 계획과 O(1) RPC 호출 덕분에 더 세밀한 파티셔닝을 막던 장벽이 사라져요
동시 쓰기 작업 (Concurrent write operations)
아이스버그는 낙관적 동시성(optimistic concurrency)을 사용해 여러 동시 쓰기를 지원해요.
각 작성자(writer)는 다른 작성자가 동시에 작업하지 않는다고 가정하고, 한 연산에 대한 새 테이블 메타데이터를 써요. 그런 다음 작성자는 새 테이블 메타데이터 파일을 기존 메타데이터 파일과 원자적으로 교체(swap)해서 커밋을 시도해요.
다른 작성자가 커밋해서 원자적 교체가 실패하면, 실패한 작성자는 새 현재 테이블 상태를 기반으로 새 메타데이터 트리를 써서 재시도해요.
재시도 비용 (Cost of retries)
작성자는 변경 내용을 재시도 사이에 재사용할 수 있도록 구조화해서 값비싼 재시도 연산을 피해요.
예를 들어 append는 보통 추가된 데이터 파일에 대한 새 매니페스트 파일을 만들고, 이 매니페스트는 매번 다시 쓰지 않고도 테이블에 추가할 수 있어요.
재시도 검증 (Retry validation)
커밋은 가정(assumptions)과 행동(actions)으로 구성돼요. 충돌이 발생한 후 작성자는 현재 테이블 상태가 가정을 만족하는지 확인해요. 가정이 충족되면 행동을 다시 적용하고 커밋해도 안전해요.
예를 들어 컴팩션이 file_a.avro와 file_b.avro을 merged.parquet으로 다시 쓴다고 해볼게요. 테이블에 file_a.avro와 file_b.avro이 여전히 모두 있다면 이 커밋은 안전해요. 충돌한 커밋으로 두 파일 중 하나라도 삭제됐다면 연산은 반드시 실패해야 해요. 그렇지 않으면 원본 파일을 제거하고 병합된 파일을 추가해도 안전해요.
호환성 (Compatibility)
파일 목록 나열과 이름 변경(rename)을 피함으로써 아이스버그 테이블은 어떤 객체 스토어(object store)와도 호환돼요. 일관된 목록 나열이 필요하지 않아요.