• 티스토리 홈
  • 프로필사진
    31514
  • 방명록
  • 공지사항
  • 태그
  • 블로그 관리
  • 글 작성
31514
  • 프로필사진
    31514
    • 분류 전체보기 (109)
      • Book (66)
        • Learning SQL (9)
        • SQL 레벨업 (8)
        • 견고한 데이터 엔지니어링 (5)
        • 운영체제 (2)
        • 스파크 완벽 가이드 (9)
        • 파이썬 코딩의 기술 (29)
        • 분산 컴퓨팅 (4)
      • 개발 (25)
      • 기타 (10)
        • 출퇴근 공부 간단 정리 (7)
      • ELK (6)
  • 방문자 수
    • 전체:
    • 오늘:
    • 어제:
  • 최근 댓글
      등록된 댓글이 없습니다.
    • 최근 공지
      • 31514의 이전 블로그는 여기로!
      등록된 공지가 없습니다.
    # Home
    # 공지사항
    #
    # 태그
    # 검색결과
    # 방명록
    • [스파크 완벽 가이드] Spark 성능 튜닝 가이드
      2024년 10월 14일
      • 31514
      • 작성자
      • 2024.10.14.:16

      이 글에서는 잡의 실행 속도를 높이기 위한 몇 가지 방법을 알아보겠습니다.

      스파크의 잡을 최적화할 수 있는 방법은 크게 다음과 같이 두 가지가 존재합니다.

      1. 속성 값을 설정하거나 런타임 환경을 변경하는 간접적인 방법
      2. 개별 스파크 잡, 스테이지, 태스크를 튜닝하거나 코드 설계를 변경하는 직접적인 방법

      그리고 이를 확인하기 위해 좋은 모니터링 도구와 잡 이력 추적 환경을 구성하는 것이 중요합니다.

       

      간접적인 성능 향상 기법

      1. 좋은 설계 방안

      • 구조적 API로 만들 수 없는 사용자 정의 트랜스포메이션(RDD 트랜스포메이션/UDF)을 사용해야 한다면, 해당 부분만 파이썬과 R을 피하자.
      • 직접 RDD를 작성하면 Spark SQL 엔진의 최적화 혜택을 받을 수 없다.
      • UDF 사용은 최대한 자제하는 것이 좋다.
        • UDF는 데이터를 JVM 객체로 변환하고 쿼리에서 레코드당 여러 번 수행되므로 많은 자원을 소모하기 때문이다.

       

      2. RDD 객체 직렬화

      • Kyro를 사용하면 간결하고 효율적인 직렬화를 할 수 있다.

       

      3. 클러스터 설정

      • 하드웨어와 사용 환경에 따라 변화하는 클러스터에 대응하기 위해 머신 자체의 성능을 모니터링 하자.
      • 애플리케이션이 더이상 사용하지 않는 자원을 클러스터에 반환하고, 필요할 때 다시 요청하는 기능을 고려하자.
        • spark.dynamicAllocation.enabled 속성 값을 True로 변경

       

      4. 스케줄링

      • spark.scheduler.mode 속성 값을 FAIR로 변경하면 여러 사용자가 자원을 더 효율적으로 공유할 수 있다.
      • --max-executor-cores 인수를 사용하면 애플리케이션에 필요한 익스큐터의 코어 수를 조절할 수 있다.

       

      5. 보관용 데이터

      효율적인 읽기를 위해 저장소 시스템과 데이터 포맷을 적절히 선택해야 한다.

       

      <파일 기반 장기 데이터 저장소>

      • 데이터를 바이너리 형태로 저장하려면 구조적 API를 사용하자.
      • CSV 파일보다 Parquet를 사용하자.

       

      <분할 가능한 파일 포맷과 압축>

      • 포맷 선택 시 분할 가능한지 확인하자.
        • 여러 태스크가 파일의 서로 다른 부분을 동시에 읽어서 모든 코어를 활용할 수 있다.
      • 분할 불가 : JSON, ZIP, TAR
      • 분할 가능 : gzip, bzip2, lz4

       

      <테이블 파티셔닝>

      • 데이터의 날짜 필드 같은 키를 기준으로 개별 디렉터리에 파일을 저장하여 파티셔닝하자.

       

      <버켓팅>

      • 데이터를 버켓팅하면 사용자가 조인이나 집계를 수행하는 방식에 따라 데이터를 사전 분할할 수 있다.
      • 전체 파티션에 데이터를 균등하게 복사하여 Skew를 방지할 수 있다.

       

      <파일 수>

      • 데이터를 파티션이나 버켓으로 구성하려면 파일 수와 저장하려는 파일 크기도 고려해야 한다.
        • 작은 파일을 많이 저장하는 경우 - 네트워크와 잡의 스케줄링 부하
        • 큰 파일을 조금 저장하는 경우 - 병렬성 증가 및 태스크 수행 시간 증가
      • maxRecordPerFile 옵션을 적용하면 write 메서드를 사용할 때 파일당 저장 레코드 수를 지정할 수 있다.

       

      <데이터 지역성>

      • 데이터가 위치한 물리적 위치와 그 데이터를 처리하는 컴퓨팅 자원의 물리적 위치가 가까울수록 성능이 향상된다.

       

      <통계 수집>

      • 쿼리 옵티마이저에게 정보를 제공하기 위해서 통계(테이블 수준 + 컬럼 수준)을 수집해야 한다.
      • 테이블 수준 통계 수집 명령어
      ANAYLYZE TABLE table_name COMPUTE STATISTICS
      • 컬럼 수준 통계 수집 명령어
      ANAYLYZE TABLE table_name COMPUTE STATISTICS FOR
      COLUMNS col1, col2, ...

       

      6. 셔플 설정

      • Spark의 외부 셔플 서비스를 설정하면 머신에서 실행되는 익스큐터가 바쁜 상황에서도 원격 머신에서 셔플 데이터를 읽을 수 있다.
      • 하지만 코드가 복잡해지고 유지가 어려워져서 운영 환경에는 부적합하다.

       

      7. 메모리 부족과 가비지 컬렉션

      메모리 부족의 원인은 다음과 같습니다.

      1. 메모리를 너무 많이 사용하는 경우
      2. 가비지 컬렉션이 자주 수행되는 경우
      3. JVM 내에 많은 객체가 있어서 가비지 컬렉션이 미사용 객체를 정리하는 경우

      3번의 경우 구조적 API를 사용하면 JVM 내에 객체를 생성하지 않으므로 해결할 수 있습니다.

       

      <가비지 컬렉션 통계 모으기>

      spark.executor.extraJavaOptions 속성에 스파크 JVM 옵션으로 -verbose:gc -XX:+printGCDetails -XX:+printGCTimeStamps 값을 추가합니다.

       

      <JVM 메모리 관리 기초 지식>

      자바 힙 공간은 Young 영역과 Old 영역으로 나누어진다.

      Young 영역은 수명이 짧은 객체, Old 영역은 수명이 긴 객체를 유지한다.

      Young 영역은 Eden, Survivor1, Survivor2로 나누어진다.

       

      <가비지 컬렉션 수행 절차>

      1. Eden 영역이 가득 차면 Eden 영역에 대한 마이너 가비지 컬렉션 실행
      2. Eden 영역에서 살아남은 객체와 Survivor1 영역의 객체는 Survivor2로 복제
      3. Survivor1과 Survivor2 영역 교체
      4. 객체가 오래되었거나 Survivor2가 가득 차면 Old 영역으로 이동
      5. Old 영역이 거의 가득 차면 풀 가비지 컬렉션 발생

      풀 가비지 컬렉션은 가장 느린 가비지 컬렉션 연산입니다.

       

      <가비지 컬렉션 튜닝을 위한 목표>

      1. 수명이 긴 캐시 데이터 셋을 Old 영역에 저장한다.
      2. Young 영역의 충분한 공간을 유지한다.

       

      <튜닝 방법>

      • 가비지 컬렉션 통계 수집 후 발생 빈도를 확인하자.
        • 풀 가비지 컬렉션이 자주 발생하면 spark.memory.fraction을 사용해서 캐싱에 사용되는 메모리 양을 줄이자.
      • 마이너 가비지 컬렉션은 빈번한데, 메이저 가비지 컬렉션은 드물다면 Eden 영역에 메모리를 더 할당하자.
      • 사용자 태스크가 HDFS에서 데이터를 읽는다면 데이터 블록 크기로 사용할 메모리 양을 추정할 수 있다.
      • G1GC 가비지 컬렉터는 가비지 컬렉션이 병목 현상을 일으키고 각 영역의 크기를 늘려도 더 이상 부하를 줄일 수 없는 상황에서 사용하자.

       

      직접적인 성능 향상 기법

      1. 병렬화

      • 특정 스테이지의 처리 속도를 높이려면 병렬성을 높여야한다.
      • spark.default.parallelism과 spark.sql.shuffle.partitions 값을 클러스터 코어 수에 따라 설정한다.
      • 처리해야 할 데이터의 양이 많다면 코어 당 최소 2~3개의 태스크를 할당한다.

       

      2. 향상된 필터링

      • 스파크 잡에서 필터링을 가장 먼저 수행하거나, 파티셔닝과 버켓팅 기법을 최대한 이른 타이밍에 활용하는 것이 가장 좋다.

       

      3. 파티션 재분배와 병합

      • 파티션 재분배는 셔플을 수행하지만, 데이터가 클러스터 전체에 균등하게 분배되므로 잡의 전체 실행 단계를 최적화할 수 있다.
      • 가능한 적은 양의 데이터를 셔플하는 것이 좋다.
        • 따라서 셔플 대신 동일 노드의 파티션을 하나로 합치는 coalesce 메서드 실행해 파티션 수를 줄인다.
      • 파티션 재분배는 부하를 유발하지만, 애플리케이션의 전체적인 성능과 스파크 잡의 병렬성을 높일 수 있다.
      • 잡이 여전히 느리다면 사용자 정의 파티셔닝 기법을 활용하자.

       

      4. 임시 데이터 저장소 - 캐싱

      • 만약 같은 데이터 셋을 계속 사용한다면 캐싱으로 최적화할 수 있다.
      • 하지만 캐싱을 사용할 때 직렬화, 역직렬화, 저장소 자원 소모를 고려해야 한다.
      • 캐싱은 cache 메서드를 사용하여 수행할 수 있지만, 지연 처리이기 때문에 적용하기 위해 액션이 필요하다.
      • persist 메서드를 사용하면 캐시 영역을 지정할 수 있어, 보다 정교한 제어가 가능하다.

       

      <캐싱 예제>

      DF1 데이터프레임에 GROUP BY를 하여 3개의 데이터프레임을 생성해보자.

      이때 소요되는 시간은 7초인걸 확인할 수 있다.

       

      하지만 캐시를 적용하면 어떨까?

      실행 시간이 2초로 줄어든 것을 확인할 수 있다.

      지금은 데이터의 양이 많지 않아서 별로 체감되지 않지만, 대용량 데이터를 다룰 때는 유용할 거 같다.

       

      5. 조인

      • 동등 조인은 최적화하기 쉬우므로 우선적으로 사용하자.
      • 조인 순서를 변경하는 것도 성능을 높이기 쉽다.
        • 내부 조인을 사용해 필터링하는 것과 동일한 효과를 볼 수 있다.
      • 브로드캐스트 조인 힌트를 사용하면 스파크카 쿼리 실행 계획을 생성할 때 지능적으로 세울 수 있다.
      • 카데시안 조인과 전체 외부 조인은 자제하고 테이블 통계와 버켓팅을 통해 조인 성능을 높이자.

       

      6. 집계

      • 집계 전에 충분히 많은 수의 파티션을 가질 수 있도록 데이터를 필터링하자.

       

      7. 브로드캐스트 변수

      • 사용자 애플리케이션에서 사용되는 다수의 UDF에서 큰 데이터 조각을 사용한다면, 이 데이터 조각을 개별 노드에 전송해 읽기 전용 복사본으로 저장하자.
        • 잡마다 데이터 조각을 재전송하는 과정을 건너뛸 수 있다.

       

      성능 최적화 우선순위

      • 파티셔닝과 효율적인 바이너리 포맷을 사용해 가능하면 작은 데이터를 읽는다.
      • 충분한 병렬성을 보장하고, Skew 현상을 방지한다.
      • 구조적 API를 최대한 활용한다.

       

      Spark Monitoring Tool을 사용하여 가장 오래 실행되는 Stage를 최적화

      'Book > 스파크 완벽 가이드' 카테고리의 다른 글

      [스파크 완벽 가이드] 15장 - 스파크 애플리케이션의 생애주기  (0) 2024.10.21
      [스파크 완벽 가이드] 18장 - 모니터링  (0) 2024.10.17
      [스파크 완벽 가이드] 17장 - 스파크 배포 환경  (0) 2024.10.16
      [스파크 완벽 가이드] 9장 - 데이터소스  (0) 2024.10.15
      [스파크 완벽 가이드] 스파크 간단히 살펴보기  (0) 2024.10.14
      다음글
      다음 글이 없습니다.
      이전글
      이전 글이 없습니다.
      댓글
    조회된 결과가 없습니다.
    스킨 업데이트 안내
    현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
    ("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)
    목차
    표시할 목차가 없습니다.
      • 안녕하세요
      • 감사해요
      • 잘있어요

      티스토리툴바