80TB 데이터 비용 10배 절감기: DynamoDB에서 Apache Iceberg로의 여정 - Part 1

DynamoDB+S3 이중 저장 구조를 S3 기반 Iceberg 단일 테이블로 통합해 비용을 1/10로 낮추고 서빙 안정성을 끌어올린 대규모 마이그레이션
hyun's avatar
Jan 22, 2026
80TB 데이터 비용 10배 절감기: DynamoDB에서 Apache Iceberg로의 여정 - Part 1

안녕하세요, AI/Data 팀의 Hyun입니다. 최근 저희 팀은 월 약 $18,000의 비용을 절감하면서도 서비스 안정성을 높인 대규모 데이터 마이그레이션 프로젝트를 진행했습니다.

80TB의 데이터를 어떻게 요리해서 저렴하고 빠른 저장소로 옮겼는지 그 설계 과정을 공유합니다.

1. 기존 구조 및 비용 분석: "편리함의 대가, 월 $18,000"

해당 데이터는 ACS(신용대안평가) 시스템에서 사용자의 신용을 평가하기 위해 수집되는 핵심 데이터로, ML 모델 학습, 서빙, 모니터링 등에 사용됩니다. 기존에는 목적에 따라 두 저장소에 데이터를 중복 저장하고 있었습니다.

  • DynamoDB (서빙용): 빠른 조회가 가능하지만 비용이 매우 비쌉니다. 80TB를 담아두기엔 저장 및 쓰기 비용 부담이 너무 컸습니다. (월 약 $16,389)

  • S3 (배치/분석용): 가격은 저렴하지만, 데이터 규모가 커질수록 특정 유저를 찾는 속도가 느려 서빙용으로는 부적합했습니다. (월 $1,968)


💡 요구사항 정의: "비용은 낮게, 성능은 충분하게"

단순히 저장소만 바꾸는 것이 아니라, 비즈니스에 최적화된 새로운 기준을 정의했습니다.

  1. 비용 절감: 월 $18,357에 달하는 운영비를 획기적으로 낮출 것

  2. 성능 확보: 실시간 단건 조회 시 평균 5초 이내의 응답 속도 유지

  3. 통합 관리: 분석(Athena/Spark)과 서빙(Python)에서 모두 사용 가능한 단일 테이블 구축

  4. 데이터 형태: 일 3억 개(60~70GB)씩 쌓이는 insert-only 형태의 80TB 거대 데이터 처리

우리의 목표는 명확했습니다. "S3의 비용으로 DynamoDB급의 서빙 성능을 내는 것"이었습니다.

2. 설계의 핵심: "수집에서 저장까지, 논리적 흐름의 완성"

S3에서 데이터를 빠르게 읽기 위한 핵심은 '읽어야 할 파일의 용량과 개수를 최소화'하는 것입니다. 데이터가 수집되어 전체 테이블로 확장되는 과정을 3단계로 설계했습니다.

[Step 1] 읽는 용량 줄이기: Parquet Rowgroup 최적화

가장 먼저 해결해야 할 과제는 파일 하나가 아무리 커도 필요한 부분만 핀셋처럼 골라 읽는 것이었습니다.

  • Rowgroup 조절: Parquet 포맷 파일 내부에는 'Row Group'이라는 데이터 조각들이 있습니다. 데이터를 유저별로 정렬(Sort)해서 저장하면 특정 유저의 데이터는 하나의 Rowgroup에 몰리게 됩니다.

  • 핀셋 읽기: 저는 이 단위를 32MB로 아주 작게 설정했습니다. 덕분에 10GB짜리 큰 파일이라도, 어떤 유저를 조회하든 딱 32MB 조각 하나만 읽으면 조회가 끝나도록 구성했습니다.

[Step 2] 당일 테이블: 1분마다 쌓이는 데이터 정리 (Bucketing)

Flink를 통해 1분마다 s3에 새로운 파일이 생성됩니다.

  • 5분 단위 병합(Compaction): 1분마다 생성되는 파일을 그대로 두면 파일을 여닫는 성능이 급격히 떨어집니다. 이를 방지하기 위해 5분마다 작은 파일들을 하나로 합쳐 파일 개수를 최소화했습니다.

  • 버켓(Bucket) 도입: 데이터를 '번호표가 붙은 양동이'에 나눠 담는 방식입니다. 하루치 데이터를 통째로(60GB) 관리하면 매번 병합할 때마다 전체를 다시 처리해야 하는 비용 부담이 크기 때문에 도입했습니다. 예를 들어 200개의 양동이를 준비해 사용자 ID 규칙에 따라 1번, 201번, 401번 사용자의 데이터를 '1번 양동이'에만 담기로 약속하면, 양동이 하나당 크기가 300MB 정도로 작아져 관리 효율이 올라가고 조회 시에도 특정 양동이만 열면 되어 매우 빨라집니다.

[Step 3] 전체 테이블 확장: 80TB 데이터 통합 관리

당일 데이터는 관리가 쉽지만, 데이터가 쌓이면 파일 수가 다시 기하급수적으로 늘어납니다. 이를 해결하기 위해 전체 데이터를 저장하는 전체 테이블을 추가했습니다.

3. 최종 설계 결과: "단 11개의 파일만 읽으면 끝"

이러한 단계적 설계를 통해, 한 유저의 전체 데이터 이력을 조회하는 로직은 다음과 같이 단순해졌습니다.

  1. 과거 5년치: 연도별 테이블에서 각 연도당 1개씩, 총 5개 파일

  2. 올해 누적분: 전체 테이블의 올해치 버켓에서 1개 파일

  3. 당일 실시간분: 당일 테이블에서 5분 단위로 병합 중인 최대 5개 파일

결과적으로 총 11개의 파일만 병렬로 읽으면 수년간의 데이터를 순식간에 가져올 수 있게 되었습니다. 유저 한 명을 찾기 위해 11개 정도의 파일을 병렬로 읽는 것은 성능상 전혀 부담이 되지 않습니다.

4. 마무리

여기까지가 Part 1입니다. 핵심은 단순한 저장소 교체가 아니라, “필요한 데이터만 아주 적게 읽게 만드는 구조”를 설계한 것이었습니다.

Rowgroup(32MB) + Bucketing + Compaction + 연도 파티션을 조합해, 유저 한 명 조회도 최대 11개 파일만 병렬로 읽는 형태로 단순화했습니다.

Part 2에서는 실제 구현(파이프라인/컴팩션), 구현 중 겪은 난관, 그리고 비용·성능 결과를 짧게 정리해 공유하겠습니다.

Share article