目录是把一个名字连到一个元数据文件的原子指针
한국어 원문으로 표시합니다.
한 줄 요약
카탈로그는 '표 이름 → 지금 metadata.json 경로' 한 칸을 들고 있고, 그 칸을 읽은 값이 그대로일 때만 바꾸는 조건부 교체로 커밋의 원자성과 동시 쓰기의 심판을 맡는다. 이름·위치·파일은 서로 다른 층이다.
왜 카탈로그가 필요했나
앞 모듈에서 본 것처럼 Iceberg 표의 상태는 metadata.json 한 파일로 정해진다. 그런데 metadata 파일은 커밋마다 새로 생긴다. 그러면 누군가는 "지금 것이 어느 파일인가" 를 알려 줘야 하고, 두 작가가 동시에 커밋할 때 한쪽만 받아 줘야 한다.
초기에는 파일 시스템이 이 일을 했다. 스펙의 파일 시스템 표 방식은 v<V>.metadata.json 이라는 정해진 이름으로 이름 바꾸기(rename) 를 시도해, 먼저 성공한 쪽이 이기게 한다. HDFS 처럼 rename 이 원자적인 곳에서는 통한다. 하지만 스펙은 이제 이 방식을 폐기 예정으로 적고, 객체 저장소와 로컬 파일 시스템에서 안전하지 않다고 경고한다. S3 에는 원자적 rename 이 없기 때문이다.
어떻게 동작하나 — 조건부 교체
그래서 표준은 메타스토어 표 방식이 되었다. 포인터를 DB 나 서비스에 두고 check-and-put 으로 바꾼다.
- 지금 metadata(버전 V)를 읽는다.
- 그것을 바탕으로 새 metadata
<V+1>-<uuid>.metadata.json을 쓴다. - 카탈로그에 "포인터가 아직 V 면 V+1 로 바꿔 달라" 고 요청한다.
- 성공하면 커밋 완료. 실패하면 누군가 먼저 V+1 을 만든 것이니 1단계부터 다시 한다.
이 계약을 지키는 구현이 여럿 있다.
| 카탈로그 | 포인터가 사는 곳 | 조건부 교체 |
|---|---|---|
| JDBC | DB 표 iceberg_tables 의 한 줄 |
metadata_location 이 읽은 값과 같을 때만 UPDATE |
| REST | 카탈로그 서버 | 서버가 요구 조건을 검사하고 커밋 |
| Hive 메타스토어 | HMS 표 속성 metadata_location |
메타스토어 잠금과 함께 교체 |
JDBC 카탈로그 문서는 연결할 DB 가 원자적 트랜잭션을 지원해야 원자적 커밋과 직렬화 읽기가 보장된다고 적는다. 이 코스의 실습 환경은 SQLite 파일 하나에 이 표를 두고, Spark(Java 의 JdbcCatalog)와 pyiceberg(SqlCatalog)가 같은 파일을 연다. 서버를 띄우지 않고도 두 엔진이 한 카탈로그를 나눠 쓴다.
REST 카탈로그 명세는 커밋을 요구 조건(requirements)과 변경(updates) 두 부분으로 나눈다. assert-ref-snapshot-id 같은 요구 조건을 서버가 먼저 검사하고, 맞지 않으면 409 CommitFailedException 을 돌려주며 클라이언트는 다시 시도할 수 있다. 서버가 커밋을 받으니 클라이언트가 저장소 자격 증명을 직접 들 필요가 줄고, 여러 표를 한 번에 원자적으로 커밋하는 경로도 있다.
Hive 메타스토어는 기존 Hive 생태계와 이어 붙이기 좋다. Hive 문서의 예처럼 포인터가 HMS 의 표 속성 metadata_location 에 들어 있다. 다만 HMS 는 Iceberg 가 아니라 Hive 를 위해 만든 서비스라 운영할 부품이 늘고, 같은 문서는 여러 표에 걸친 INSERT 가 원자적이지 않다고 적는다.
이름·위치·파일은 다른 층이다
카탈로그 한 줄은 이름과 metadata 경로만 잇는다. 그래서 다음이 성립한다.
- 이름 바꾸기는 그 줄의 이름만 고친다. 표 위치와 파일은 그대로다. 이름이 바뀐 표가 옛 이름의 디렉터리를 계속 쓰는 것이 정상이다.
- PURGE 없는 DROP TABLE 은 그 줄만 지운다. metadata 와 데이터 파일은 디스크에 남는다.
- register_table 은 이미 있는 metadata.json 에 새 이름을 붙인다. metadata 파일이 스키마·스냅샷·파일 목록을 전부 들고 있으니 경로 하나로 표가 되살아난다. 같은 문서는 한 metadata 를 두 카탈로그에 동시에 등록하면 갱신이 사라지고 표가 손상될 수 있다고 경고한다 — 포인터가 둘이면 심판도 둘이기 때문이다.
현장에서 만나는 모습
카탈로그 옮기기. Hive 메타스토어에서 REST 카탈로그로 옮길 때 데이터는 한 바이트도 움직이지 않는다. 표마다 지금 metadata 경로를 읽어 새 카탈로그에 등록하고, 옛 카탈로그에서는 PURGE 없이 지운다. 옮기는 동안 두 카탈로그가 같은 표에 쓰지 않게 막는 것이 핵심이다.
실수로 지운 표. DROP TABLE 뒤에 공간이 줄지 않아 당황하는 사람과, 반대로 다 날아갔다고 포기하는 사람이 있다. PURGE 가 없었다면 metadata 파일 경로 하나로 되살릴 수 있다.
실무에서 진짜 중요한 것
- 카탈로그의 일은 조건부 교체다. 원자적으로 바꿀 수 없는 저장소 위에서는 표가 깨진다.
- 엔진이 여럿이면 카탈로그는 하나여야 한다. 같은 표를 두 카탈로그가 가리키면 커밋이 서로를 덮는다.
- 이름은 카탈로그에만 있다. 이름을 바꿔도 파일은 옮겨지지 않는다.
- PURGE 는 되돌릴 수 없다. PURGE 없는 DROP 은 metadata 경로만 있으면 되살릴 수 있다.
다음 실습에서 할 것
Spark 가 JDBC 카탈로그(SQLite)에 표를 만들고, pyiceberg 로 같은 카탈로그를 열어 그 표를 보고 새 표를 만든 뒤, Spark 가 두 엔진의 표를 조인한다. 커밋 전후로 카탈로그 한 줄의 현재·이전 경로가 어떻게 움직이는지 적고, 표 이름을 바꿔 위치가 그대로인 것을 확인하고, PURGE 없이 지운 뒤 남은 파일을 세고, register_table 로 metadata 파일 하나에서 표를 되살린다.