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

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

안녕하세요, AI/Data 팀의 Hyun입니다.

Part 1에서 설계 방향을 공유했다면, Part 2에서는 실제 읽기/서빙 성능 검증부터 Pyiceberg 커스터마이징, 대규모 Spark 처리 최적화, 그리고 최종 비용·성능 결과까지 구현 이야기를 정리해보겠습니다.

1. 구현 과정

1. Athena를 통한 데이터 읽기 성능 검증

본격적인 도입에 앞서 Athena를 통해 Iceberg 테이블의 조회 성능을 테스트했습니다. 결과는 놀라웠습니다. 5년 치 데이터를 포함한 대량의 파일을 조회함에도 불구하고, 스캔 범위와 속도 모두 만족스러웠습니다.

항목

20명 조회 (12만 건)

4명 조회 (5만 건)

Latency

4초

3초

Scan Bytes

1,103 MB

257 MB

2. 실시간 서빙: DynamoDB vs Iceberg

기존 DynamoDB 기반 서빙은 데이터 양에 따른 성능 편차가 심각한 병목 구간이었습니다.

DynamoDB의 한계

  • 불안정한 Latency: 평균 1~2초였으나, 데이터가 많아질 경우 최악의 경우 2분까지 소요.

  • 확장성 부족: 한 번에 많은 데이터를 가져오는 데 한계가 있어 사용자별 편차가 매우 큼.

아래는 DynamoDB의 latency입니다.

Iceberg의 안정성

테스트 결과, Iceberg는 사용자가 몰리는 시점(20명 동시 처리)과 평균적인 시점(4명 처리) 모두 4~5초대의 일정한 성능을 유지하며 뛰어난 안정성을 보였습니다. 

아래 그래프의 왼쪽은 4명 동시처리, 오른쪽은 20명 동시처리시 입니다.


3. Athena의 한계와 Pyiceberg의 도전

Athena는 강력한 도구지만, 실제 운영 환경(In-house)의 대규모 모수에서 돌려보자 예상치 못한 병목이 발생했습니다.

Athena의 발목을 잡은 'DPU 제한'

Athena는 병렬 처리를 위해 DPU(Data Processing Unit)를 사용합니다. 하지만 AWS 계정당 할당된 기본 DPU는 정해져 있고, 이를 초과하면 쿼리가 대기 상태(Queued)에 빠지며 레이턴시가 급격히 늘어납니다.

  • 문제: DPU 여유가 없어 대기 시간이 발생하자, 4초였던 레이턴시가 걷잡을 수 없이 길어짐.

  • 대안: 비용이 비싼 'Provisioned Capacity'를 추가하는 대신, 서버 자원을 활용할 수 있는 Pyiceberg로 조회를 시도했습니다.

Pyiceberg 도입 초기: 또 다른 성능의 늪

기대를 안고 도입한 Pyiceberg는 기본 설정에서 오히려 더 처참한 결과를 보였습니다.

  • 조회 속도: 20명 사용자 조회 시 90초 소요 (단일 프로세스)

  • 메모리 폭주: 병렬 프로세스를 시도하자 메모리 점유율이 20GB까지 치솟으며 시스템 불안정 초래.

    • 5개 Executor (각 2개 처리): 10GB 메모리 사용, 12초 소요

    • 10개 Executor (각 1개 처리): 20GB 메모리 사용, 9초 소요

  • 결론: 단순 I/O 위주 작업임에도 메모리를 과하게 점유하는 비효율적 구조 확인.


4. Pyiceberg 직접 해부와 커스터마이징

"Athena가 빠르다면, 단일 서버에서도 매니페스트를 효율적으로 다루기만 하면 충분히 빠른 성능을 낼 수 있다"는 가설을 세웠습니다. 

이를 위해 Pyiceberg의 스캔방식을 하나하나 해부하고 내부 로직을 커스터마이징했습니다.

① 매니페스트(Manifest) 캐싱: 반복되는 1초 제거

Pyiceberg는 매번 호출 시마다 매니페스트 파일을 새로 읽어옵니다.

매니페스트란? 데이터 파일 경로와 통계(Min/Max)가 담긴 상세 지도로, 조건에 맞는 파일만 골라 읽어 I/O를 줄여주는 핵심 요소입니다.

  • 분석: 전체 테이블은 하루 한 번만 업데이트됩니다. 즉, 매번 새로 읽을 필요가 없습니다.

  • 해결: 매니페스트를 메모리에 캐싱하고 하루에 한 번만 갱신하도록 변경하여, 호출당 1초의 레이턴시를 즉시 제거했습니다.

② 유저 ID - 파일 맵핑 최적화: 90초에서 5.2초로

Pyiceberg의 기본 필터링 로직에서 가장 큰 병목이었던 '무차별적 필터링' 문제를 커스터마이징으로 해결했습니다.

문제점: "인지하지 못하는 비효율"

  • 기존 방식: 20명의 유저를 조회하기 위해 140개 파일을 찾은 뒤, 각 파일 내부의 모든 Row Group(데이터 블록)에 대해 "여기에 20명 중 누구라도 있니?"라고 일일이 대조합니다.

  • 비효율의 핵심: 특정 파일은 특정 유저의 버킷(Bucket)에 속해 있어 해당 유저만 확인하면 됩니다. 하지만 Pyiceberg는 이를 인지하지 못해, 1개의 Row Group만 읽어도 될 상황에서도 최악의 경우 20개를 모두 체크하며 어마어마한 I/O와 연산 낭비를 발생시켰습니다.

해결책: "유저 ID - 파일 경로 1:1 매핑"

  • 커스텀 로직: 유저 ID와 파일의 관계를 미리 매핑하여, “A 유저의 파일에서는 오직 A 유저만 찾아라"고 타겟팅했습니다.

  • 정밀 타격: 읽어야 할 Row Group을 정확히 한정함으로써 불필요한 데이터 읽기를 원천 차단했습니다.

결과: 이 최적화와 병렬 스레드 처리를 결합해 90초였던 조회 시간을 5.2초까지 단축시켰습니다.

  • 위에는 실제 서빙에서 읽는데 걸리는 평균/최대 시간입니다.

  • Latency가 늘어나는 구간이 있는데요. 한 process에 동시 처리 유저수가 급증할 때, 발생하고 있습니다.

💡 "그렇다면 Athena가 여전히 더 빠른 것 아닌가요?"

맞습니다. Athena는 약 4초대로 여전히 강력합니다. 하지만 Athena가 빠른 이유는 수많은 DPU(병렬 처리 유닛)를 동원해 물리적인 힘으로 밀어붙였기 때문입니다(DPU 부족 시 성능이 급락하는 이유이기도 합니다).

반면, 제가 적용한 방식은 단일 Core에서 다중 스레드만 활용하여 거둔 성과입니다. 비싼 DPU 자원을 펑펑 쓰지 않고도, 로직의 효율성만으로 Athena의 성능에 근접했다는 점에서 운영 비용과 안정성 측면의 큰 승리라고 볼 수 있습니다.

③ Python 3.11 업그레이드

기본적인 CPU 처리 성능 향상을 위해 Python 3.8에서 3.11로 버전을 올렸습니다. 덕분에 '필터 조건에 부합하는 파일 찾기'와 같은 내부 연산 속도가 전반적으로 개선되었습니다.

5. 대규모 데이터 처리: Spark Join 및 ACS 최적화

분석 환경에서도 Iceberg 도입 효과는 극명했습니다.

Spark Join 전략

다양한 Join 방식을 테스트한 결과, 유저 ID를 Broadcast 하여 Join하는 방식이 가장 우수한 성능을 보였습니다.

ACS Monitoring & Learning 성능 변화

  • 모니터링 (10만 유저): * 기존: 80TB 전수 조사, 800 Core로도 메모리 부족 발생. 1년씩 끊어서 30분 소요.

    • 현재: 400 Core로 15분 만에 안정적 처리. 

  • 학습 (500만 유저): * 기존: 1,200 Core, 20,000개 버켓이라는 기형적 리소스로 간신히 구동.

    • 현재: 400 Core, 250개 버켓으로 33분 만에 가볍게 완료.


2. 결과: 비용은 1/10로, 성능은 더 안정적으로

  • 비용 절감: 월 $18,357 → $1,554 (약 91.5% 절감)

조회 성능: 특정 유저 데이터 조회 시 평균 5초 확보

1. 비용의 핵심: 파일 병합(Compaction)

현재 전체 운영 비용의 약 50%가 '파일 병합' 작업에서 발생하고 있습니다.

  • 이유: 방대한 양의 데이터를 실시간에 가깝게 빠르게 읽기 위해, 아주 작은 단위까지 파일을 조밀하게 합치는 ‘타이트한 병합 전략'을 선택했기 때문입니다.

  • 현황: 저장 공간이나 순수 읽기 비용보다 병합을 위한 컴퓨팅 자원 소모가 가장 큰 비중을 차지합니다.

2. 성능과 비용의 트레이드오프 (Trade-off)

데이터 엔지니어링 설계에서 병합(Compaction)과 조회(Read) 사이의 균형은 가장 어려운 숙제 중 하나입니다.

  • 타이트한 병합 (Current Strategy):

    • 장점: 조회 시 열어야 할 파일 수가 최소화되어 Latency가 매우 짧아지고 조회 비용이 감소합니다.

    • 단점: 파일을 합치는 과정이 잦아져 컴팩션 비용(Write/Compute)이 급증합니다.

  • 느슨한 병합:

    • 장점: 병합 주기를 늘려 운영 비용을 대폭 절감할 수 있습니다.

    • 단점: 조회 시 읽어야 할 파일 파편이 많아져 조회 속도가 느려지고 Latency가 불안정해집니다.

3. 프로젝트를 통해 얻은 교훈: 요구사항 정의의 중요성

결국 가장 효율적인 시스템이란 비용과 성능 사이의 최적의 균형점(Sweet Spot)을 찾는 것입니다. 이번 프로젝트를 진행하며 제가 느낀 가장 중요한 점은 다음과 같습니다.

"설계 전, 비즈니스 요구사항을 명확히 정의하는 것이 모든 최적화의 시작이다."

  • 우리가 필요한 것이 0.1초를 다투는 실시간성인지, 아니면 조금 느리더라도 비용 효율적인 배치 처리인지에 따라 병합 전략은 완전히 달라집니다.

  • 요구사항이 명확할 때 비로소 불필요한 자원 낭비를 막고, 목적에 가장 부합하는 아키텍처를 완성할 수 있습니다.

3. 마무리

긴 글 끝까지 읽어주셔서 감사합니다. 😊

이번 글이 대규모 데이터를 비용 효율적으로 운영하려는 분들께 작은 참고가 되었으면 합니다.

Share article