#Backend

자면서도 (그리고 비행기 안에서도) 아파치 스파크 실험 실행하기

자면서도 (그리고 비행기 안에서도) 아파치 스파크 실험 실행하기
01

Summary

자면서도 비행기 안에서도! 넷플릭스 엔지니어가 스파크 OOM을 정복한 비밀

브랜치 격리 기반 병렬 실험과 AI 에이전트, 스파크 메모리 튜닝으로 대규모 파이프라인 병목을 해결한 실전 기록

넷플릭스의 핵심 세션 데이터 파이프라인에서 발생한 대규모 OOM 장애를 해결하는 여정을 다룬 아티클입니다. 단순한 코드 최적화를 넘어 브랜치 격리를 통한 동시 병렬 실험 체계 구축, AI 에이전트를 활용한 작업 자동화, 그리고 스파크 메모리 메커니즘을 파고든 깊이 있는 최적화 인사이트를 다룹니다.

  • 01단일 실행 속도 개선 대신 브랜치 기반 환경 격리로 5개 이상의 실험을 동시 실행하는 패러다임 전환
  • 02AI 에이전트를 활용하여 배포, 메트릭 수집, 변인 비교 및 실험 로깅 자동화
  • 03Scala Option 언박싱 및 비필수 이벤트 필드 제거로 Peak Executor 메모리를 112%에서 58%로 절감
  • 04Adaptive Query Execution(AQE)의 누적 Broadcast Hash Join이 메모리를 잠식하는 원인 규명 및 해결
  • 05Window 연산자 전 단계에서 Capping을 수행하여 수십만 건 이벤트 버퍼링 시 발생하는 OOM 차단

RECOMMENDATION

대용량 아파치 스파크 파이프라인을 다루며 데이터 편향(Data Skew)이나 원인 불명의 OOM 장애로 고통받는 데이터 엔지니어 및 백엔드 개발자에게 적극 추천합니다.

The Problem

넷플릭스의 대규모 세션화 파이프라인(member-sessionizer) 개편 중 데이터 불균형(Data Skew)으로 인해 프로덕션 전체 스케일에서만 Executor OOM, Shuffle Spillage, Stage Retry 장애가 발생했습니다. 극단적인 롱테일 데이터 특성상 1% 표본 샘플링으로는 원인이 재현되지 않아 매번 전체 데이터 기반의 테스트가 강제되었습니다.

The Solution

브랜치 기반 데이터 파이프라인 격리 기법(Dataflow 및 Maestro)을 활용하여 여러 변인 실험을 동시 병렬로 실행하는 테스트 루프를 구축했습니다. AI 에이전트를 통해 배포/모니터링을 자동화하고, 스파크 내부 메모리 최적화(Scala Option 제거, 이벤트 구조 경량화, AQE 런타임 Broadcast 문턱값 조정, Window 연산 전 Capping)를 적용했습니다.

The Result

Scala Option 언박싱과 이벤트 경량화를 통해 Peak Executor 메모리 사용량이 슬롯 대비 112%에서 58%로 대폭 감소하고 Disk Spill이 완전 제거되었습니다. 또한 브랜치 격리와 병렬 실험 환경 구축을 통해 24시간 비행 동안 4~5회의 완전한 전체 스케일 실험을 수행하며 문제를 해결했습니다.

Trade-off

파이프라인 최적화를 통해 메모리 공간과 안정성을 확보했으나, 세션 단위로 데이터를 단일 로우에 집계하는 구조적 한계는 여전히 존재합니다. 상류 데이터의 속성이 계속 커질 경우 튜닝만으로는 한계가 있어 향후 근본적인 데이터 모델 변경이 필요합니다.

03

Key Concepts

Concept · 01

Dataflow & Maestro (Branch Isolation)

넷플릭스의 데이터 파이프라인 CLI 및 워크플로우 오케스트레이션 도구로, Git 브랜치 이름을 기반으로 네임스페이스와 테이블을 자동 격리합니다.

  • 브랜치명을 기반으로 워크플로우, 데이터 테이블, 실행 네임스페이스를 자동 생성하여 동시 병렬 실험 간 충돌 방지
  • 별도의 DDL 작성 없이 데이터 스키마 변경 시 자동 반영
Concept · 02

Option Boxing & Unboxing in Spark

Scala의 Option 객체 래핑으로 인해 발생되는 JVM 객체 할당 오버헤드와 이를 원시 타입(Primitive)으로 언박싱하여 메모리를 최적화하는 기법입니다.

  • collect_list 연산 수행 시 Option 래퍼로 인한 JVM 객체 역직렬화 및 GC 압박 확인
  • Non-nullable 필드에서 Option을 제거하여 Peak Executor 메모리를 112%에서 58%로 축소
Concept · 03

AQE (Adaptive Query Execution) Broadcast Hash Join

런타임 통계를 기반으로 스파크 쿼리 실행 계획을 최적화하는 기능으로, 조인 대상 테이블 크기가 기준 이하일 때 Broadcast Join으로 자동 전환합니다.

  • 여러 Sort-Merge Join이 Broadcast Join으로 전환되며 Executor 하나에 약 3.1GB 데이터가 누적 고정되는 현상 확인
  • spark.sql.adaptive.autoBroadcastJoinThreshold 값을 10MB로 하향 조정하여 런타임 메모리 과부하 해소