포스트

Apache Spark 리소스 최적화 - 하루 800만 건의 잡에서 얻은 교훈

목차

  1. 개요
  2. 배경
  3. 핵심 내용
  4. 의미와 시사점
  5. 결론
  6. Reference

개요

Salesforce Engineering이 Apache Spark 리소스 최적화 경험을 정리한 글을 공개했습니다. Salesforce Data 360은 하루 약 800만 건의 Spark 워크로드를 실행하며, 짧은 실행부터 수 시간에 걸쳐 테라바이트 단위 데이터를 처리하는 워크로드까지 다양합니다. Spark 워크로드가 계속 성공하는데도 컴퓨팅 비용은 증가하는 상황에서, 팀은 다음 목표를 세웠습니다.

  • 사용되지 않는 용량을 메모리 압박이나 shuffle 병목과 구분할 것
  • 성능과 안정성을 유지할 것
  • 애플리케이션 코드 변경 없이 근거를 수집할 것

근거 없이 CPU, 메모리, executor를 줄이면 실행이 느려지거나, 비용이 큰 재시도가 발생하거나, 프로덕션 장애로 이어질 수 있기 때문입니다.

배경

성공한 잡도 리소스를 낭비한다

글에서 드는 예시는 executor 40개를 요청한 잡입니다. 이 잡은 성공적으로 완료되지만, 시작 시점에 대부분의 executor에는 할 일이 없습니다. 그 결과 장애 없이도 pod churn, node churn, 그리고 사용되지 않는 용량이 발생합니다. 팀은 이 패턴을 실제 Data 360 워크로드에서 발견했습니다.

기존에 시도한 두 가지 방식은 충분하지 않았습니다.

방식한계
고정 리소스 프로파일제출 전 할당량을 정하는 데는 도움이 되지만 실행 중 동작을 보여주지 못함
테넌트·데이터 볼륨 기반 추정제출 전 할당량을 정하는 데는 도움이 되지만 실행 중 동작을 보여주지 못함

글의 핵심 메시지는 “성공적인 완료는 동작하는 설정의 증거일 뿐, 효율적인 설정의 증거가 아니다”라는 것입니다.

핵심 내용

애플리케이션 변경 없는 텔레메트리 수집

Data Processing Controller(DPC)는 Data 360의 수집(ingestion), 세그먼테이션, 활성화(activation)를 지원하는 관리형 Spark 제출의 공통 게이트웨이입니다. Agentforce 상호작용 역시 이 플랫폼으로 데이터를 보냅니다.

팀은 애플리케이션 코드와 독립적으로 실행을 관찰할 수 있는 Spark listener hook을 활용했습니다. 오픈소스 DataFlint Spark 플러그인을 확장하고, DPC가 제출을 구성할 때 이 플러그인을 주입하는 방식입니다. 각 Spark driver의 listener가 텔레메트리를 수집해 Kafka를 거쳐 중앙 Apache Iceberg 레이크하우스로 내보냅니다.

수집 파이프라인에는 다음과 같은 안전장치가 있습니다.

  • 전용 listener-bus 큐 사용
  • 계측(instrumentation)이 설정·초기화에 실패해도 제출은 계속 진행
  • export 실패와 텔레메트리 누락을 감시하는 알림

오해를 부르는 메트릭 피하기

불완전한 애플리케이션, 누락된 레코드, 잘못 집계된 재시도는 분석 결과를 왜곡합니다. 또한 전체 플릿 평균으로는 특정 워크로드를 대표할 수 없습니다.

항목주의점
재시도재시도된 stage는 추가로 과금되는 작업이지만, 모든 시도를 별개의 논리적 작업으로 세면 성공 실행 분석이 왜곡됨
Spillmemory spill과 disk spill은 같은 압박 이벤트를 설명하므로 독립적인 바이트로 합산하면 오해를 부름

팀은 이런 의미 체계를 반영한 큐레이션 분석 계층 Silver를 만들었습니다. Silver는 애플리케이션, 잡, stage attempt, executor 및 관련 도메인을 모델링합니다. 적용 규칙은 다음과 같습니다.

  • Right-sizing은 정의된 워크로드·환경 범위 안에서 완료된 Spark 애플리케이션 실행만 사용
  • 안정성 조사는 실패와 재시도도 함께 검토
  • 누락되거나 부분적인 측정값은 명시적으로 표시

비용은 Spark 애플리케이션마다 driver pod 비용과 모든 executor pod 비용을 합산해 정의하며, 이를 통해 변경 전후 비교가 가능해집니다.

낭비인가 병목인가

팀은 Data 360 상위 10개 워크로드를 서비스 비용(cost to serve), CPU 유휴 시간, task를 하나도 수행하지 않은 executor(zero-task executor) 기준으로 순위를 매겼습니다.

Silver는 Trino를 통해 노출되며, agentic 프로파일링 스킬이 자연어 질문으로부터 SQL을 생성합니다. 답변에는 SQL, 수식, 가정이 함께 포함되어 엔지니어가 근거를 직접 검토할 수 있습니다.

진단에 사용한 신호는 다음과 같습니다.

신호해석
유용한 작업이 없는 executor더 작은 초기 할당을 테스트할 근거
task를 받은 executor의 높은 CPU 유휴 시간할당된 CPU의 상당 부분이 사용되지 않음
관측된 최대 CPU·메모리, executor 동시성, spill 동작함께 검토하는 보조 지표
shuffle이 많은 작업의 fetch failure별도의 안정성 조사 대상

다만 CPU 사용률이 낮다는 사실만으로 용량을 제거해도 된다고 단정할 수는 없습니다. zero-task executor 역시 정확히 몇 개로 줄여야 하는지를 알려주지는 않습니다.

프로덕션 검증

팀은 두 가지 변경을 검증했습니다.

구분변경 내용관찰 결과
변경 1initialExecutors를 4로 축소, Spark dynamic allocation 유지한 달 이상 프로덕션 운영, 허용할 수 없는 runtime·재시도·실패 회귀 없이 낭비 제거
변경 2executor 유휴 시간이 90%를 넘는 별도 코호트에서 최대 executor 한도를 약 20% 축소, 나머지 프로파일은 유지한 달 이상 관찰, runtime·spill·재시도·실패 모두 허용 범위

두 변경 모두 해당 워크로드에서만 검증된 것이며 범용 설정이 아니라는 점을 글은 명시합니다.

롤아웃은 하위 환경을 거쳐 프로덕션으로 단계적으로 진행했으며, 다음 항목을 확인했습니다.

영역확인 지표
애플리케이션p95 runtime, 재시도, OOM, spill
플랫폼(Kubernetes)pod churn, node churn, IP-prefix 소비량, etcd 부하

결과

대상 Data 360 워크로드 전반에서 다음 결과를 얻었습니다.

  • 변경 전후 4주 구간을 맞춰 비교했을 때 주간 컴퓨팅 비용 run rate가 31% 감소
  • 같은 환경에서 DPC 잡 시작 건수는 7% 넘게 증가

단, 이는 통제된 실험이 아닌 전후 비교이므로 동시에 진행된 다른 변경이 영향을 주었을 수 있다고 저자들은 밝힙니다.

의미와 시사점

이 사례에서 눈여겨볼 점은 리소스를 줄이는 결정을 추정이 아닌 실행 데이터에 근거해 내렸다는 것입니다. 공통 제출 게이트웨이에 플러그인을 주입하는 방식으로 개별 애플리케이션 수정 없이 플릿 전체의 텔레메트리를 확보했습니다. 또한 재시도와 spill의 집계 방식처럼 메트릭 의미 체계를 Silver 계층에 명시해, 잘못된 수치가 sizing 권고로 이어지는 것을 막았습니다.

팀은 다음 단계로 두 가지를 검토하고 있습니다.

  • SQL이나 자연어 스킬 없이도 공통 인사이트를 볼 수 있도록 Silver 위에 워크로드 단위 집계(rollup) 구축
  • DPC가 검증된 권고를 자동 적용해 관찰, 진단, 최적화의 루프를 더 촘촘하게 만드는 방안

결론

글이 제시하는 실천 방법은 다음과 같습니다.

  1. 비용이 큰 반복 워크로드 하나에서 시작
  2. 완료되고 비교 가능한 실행들을 대상으로 요청 용량과 실제 유용한 작업량을 비교
  3. 유휴 상태의 원인을 조사한 뒤 표적화된 변경을 테스트
  4. 확장하기 전에 runtime, spill, 재시도, 실패와 함께 비용을 평가

하루 800만 건의 실행 규모가 없어도 이 교훈은 그대로 적용할 수 있습니다. 추정치는 가설로 다루고, 이후 실행 결과로 확인하는 것이 핵심입니다.

Reference