본문 바로가기
BigData/Spark & Spark Tuning

[Spark] cache() vs persist() 차이점 정리 (feat. storage level)

by 스파이디웹 2023. 9. 19.
728x90

cache()

test_df.cache()
# test_df를 캐싱
test_df.storageLevel
# org.apache.spark.storage.StorageLevel = StorageLevel(disk, memory, deserialized, 1 replicas)

persist()

import org.apache.spark.storage.StorageLevel # storage 명시를 위한 library import

test2_df.persist(StorageLevel.MEMORY_AND_DISK) # test2_df에 persist를 하면서 storage lvl을 명시

test2_df.storageLevel
# org.apache.spark.storage.StorageLevel = StorageLevel(disk, memory, deserialized, 1 replicas)

storage level

~Ser 은 원본이 아닌 Serealize 된 형태로 저장한다는 것, 저장용량에서의 이점은 있지만, 저장할 때와 읽을 때 SER, deSER로 인한 CPU사용량 증가가 있음

 

Level
Space Used
CPU Time
In memory
On disk
Nodes with data
MEMORY_ONLY
High
Low
Y
N
1
MEMORY_ONLY_2
High
Low
Y
N
2
MEMORY_ONLY_SER
Low
High
Y
N
1
MEMORY_ONLY_SER_2
Low
High
Y
N
2
MEMORY_AND_DISK
High
Medium
Some
Some
1
MEMORY_AND_DISK_2
High
Medium
Some
Some
2
MEMORY_AND_DISK_SER
Low
High
Some
Some
1
MEMORY_AND_DISK_SER_2
Low
High
Some
Some
2
DISK_ONLY
Low
High
N
Y
1
DISK_ONLY_2
Low
High
N
Y
2

* MEMORY_AND_DISK: 메모리 공간에 더이상 저장할  없는 경우 디스크에 저장

 

위 표의 Storage Level은 아래 다섯가지의 속성의 조합으로 만들어졌다: userDisk, useMemory, useOffHeap, deserialized, replication

  • userDisk : 메모리에 들어가지 않는 파티션은 디스크에 기록된다. 디스크 IO 비용도 크므로 이 옵션을 사용하는 경우는 재연산 비용이 큰 경우가 될 것이다. (재연산의 비용이 크지 않은 경우 일부 파티션을 재연산하는 것이 더 빠를 수도 있다.)
  • useMemory : 메모리에 저장되거나 직접 디스크에 기록된다.
  • useOffHeap : Tachyon과 같은 executor 밖의 외부 시스템에 저장. 메모리이슈가 심각하거나 클러스터가 혼잡한 편이고 파티션이 자꾸 메모리에서 제거된다면 고려해볼만 하다.
  • deserialized : 직렬화되지 않은 Java 객체로 저장된다. MEMORY_ONLY_SER 처럼 suffix로 _SER이 붙는 옵션들은 직렬화를 사용한다.
    (RDD가 메모리에 들어가기 너무 크다면 우선 MEMORY_ONLY_SER 옵션으로 직렬화를 시도해본다. RDD에 빨리 접근하도록 유지하면서도 저장에 필요한 메모리는 줄어든다.)
  • replication : 영속화 데이터의 복사본 개수를 정수로 지정. default = 1.

 

  cache() persist()
공통점 Spark로 데이터를 다룰 때 action 수행 시점마다 로드되지 않고, 한번 로드한 데이터를 메모리상에 상주 시키는 메서드

차이점 RDD와 DF인지에 따라 default storage level이 달라짐

● RDD.cache() 의 default storage level = StorageLevel.MEMORY_ONLY

● DF.cache() default storage level = StorageLevel.MEMORY_AND_DISK
RDD, DF의 storage level을 명시해서 사용해야 함

사용하는 경우

  1. 반복적인 연산
    동일한 데이터세트에 대해 반복적으로 연산을 수행한다면 이 데이터세트를 영속화해두는 것이 좋음. 매번 연산할 때마다 데이터세트가 메모리 내에 존재하고 있는 것이 보장되므로 성능 향상을 기대할 수 있음
  2. 동일 RDD에 대해 여러 번의 액션 호출
  3. 각 파티션의 연산 비용이 너무 큰 경우
    여러번 사용하지 않더라도, 중간 결과를 저장하여 실패 시의 비용을 줄일 수 있음. 일반적으로 좁은 트랜스포메이션은 넓은 트랜스포메이션보다는 빠르지만, 파티션별 모델 훈련이나 매우 컬럼이 많은 행으로 작업하는 등 일부 좁은 트랜스포메이션이 클러스터의 executor의 처리량보다 더 큰 GC 오버헤드나 메모리 부담을 만들어낸다면 체크포인팅이나 off_heap 영속화가 빛을 발할 수 있음

 

 

 

참조:

https://nabillera.tistory.com/entry/Spark-%EA%B3%B5%EB%B6%80-%EA%B5%AC%EC%A1%B0-RDD-Storage-Level

https://jaemunbro.medium.com/apache-spark-rdd-%EC%9E%AC%EC%82%AC%EC%9A%A9%EC%9D%84-%EC%9C%84%ED%95%9C-%EC%98%81%EC%86%8D%ED%99%94-persist-cache-checkpoint-12c121dac8b6

728x90

댓글