ADR-0041: 학습 데이터셋 export 다운로드 — part 단위 API 스트리밍 프록시
- 상태: 승인
- 날짜: 2026-08-06
- 관련: ADR-0027(데이터셋 레이어), ADR-0039(스토리지 쿼터), 이슈 #2989 M1, 설계
docs/DESIGN_DATASET_DOWNLOAD.md
맥락
데이터셋 export 는 완료 시 export_uri(S3 URI)만 반환했다. prod SeaweedFS 는 ClusterIP
전용이라 외부 사용자는 산출물에 접근할 수 없었고(S3 자격 배포 문제), presigned
URL 도 같은 이유로 동작하지 않는다(에픽 #2989 결정). 산출물은 단일 객체가 아니라
part-0001.jsonl+ (50k 행/part) prefix 이며, export_uri 는 슬래시로 끝나는
prefix 다.
결정
- 다운로드 = JWT 인가·감사를 통과하는 API 스트리밍 프록시
(
GET .../exports/{eid}/download) — blob 프록시(S3 비노출)와 동형. S3 외부 노출·presigned 비채택 (에픽 축과 정합). - part 단위 서빙 (
?part=N+X-Export-Part-Count헤더) — 서버 이어붙임 스트리밍은 Content-Length/Range 계산에 전 part HEAD 가 필요해 정합이 깨진다. 이어붙임은 클라이언트(CLI) 책임: part 를 순차로 받아 단일 파일로 저장. - Range 는 part 내 단일 바이트 범위만 (
bytes=a-b/a-/-suffix) — 206 +Content-Range. 형식 오류·다중 범위·불만족 범위는 전부 416 (조용한 전체 200 폴백은 클라이언트 이어받기를 오염시키므로 금지).parse_byte_range는 M4 video 뷰어(blob Range)가 재사용할 유틸. - 행 0건 completed export (part 0개 — run_export 의
if buf가드 실측): 빈 200 +X-Export-Part-Count: 0. part 부재 + row_count>0 은 502 (GC/불일치). - S3 접근은 svc 레벨 sync 헬퍼(list/head/stream)로 감싼다 — boto3 직접 호출은
테스트에서 스텁 불가(CI 30s 타임아웃). 스트리밍은
iter_chunks(256KB) 로 전체 메모리 적재 금지. - 파일명(
<name>-v<N>[-partNNNN].jsonl)은 사용자 입력이므로 mlflow 프록시의 Content-Disposition 인젝션 방어(제어문자=통째 대체 + RFC5987)를 동형 적용.
비채택 대안
- presigned URL — SeaweedFS ClusterIP 전용, 외부에서 원리적으로 불가.
- 서버측 part 이어붙임 단일 스트림 — Range/Content-Length 정합 붕괴, 중간 part 소실 시 부분 성공이 은폐됨.
- export 를 단일 객체로 재설계 — 대형 export 의 메모리/재시도 특성 악화, 기존 산출물과 비호환.
결과
- CLI
gend dataset download(재사용 기본·--fresh·--with-blobs) 가 이 API 를 소비 — S3 자격 배포 없이 HF-CLI 급 pull 완성 (M1). - M2(업로드 CLI)·M3(청크 업로드)·M4(video Range 뷰어)가 같은 유틸/패턴 위에 선다.