스파크 RDD (Resilient Distributed Dataset)란?
Apache Spark는 대규모 데이터 처리를 위한 강력한 분산 컴퓨팅 플랫폼입니다. 그 핵심 구성 요소 중 하나인 **RDD (Resilient Distributed Dataset)**는 스파크의 기본 데이터 처리 단위로, 분산 환경에서 데이터를 효율적으로 처리할 수 있도록 설계되었습니다. 이번 포스팅에서는 스파크 RDD의 개념, 특징, 장점 및 주요 API에 대해 살펴보겠습니다.
1. RDD란 무엇인가?
RDD (Resilient Distributed Dataset)는 불변(Immutable)하고 분산(Distributed)된 데이터셋으로, Spark에서 데이터를 표현하는 기본 단위입니다. RDD는 Spark의 가장 기초적인 데이터 추상화이며, 대규모 데이터를 분산 환경에서 처리할 수 있는 기초를 제공합니다.
주요 특징
- Resilient (복원력):
- 데이터가 손실되더라도, RDD는 복구 메커니즘(혈통 정보, Lineage)을 통해 원래 데이터를 다시 생성할 수 있습니다.
- Distributed (분산):
- 데이터는 여러 노드에 분산 저장됩니다. 이로 인해 대규모 데이터를 병렬로 처리할 수 있습니다.
- Immutable (불변):
- RDD는 생성 후 변경할 수 없습니다. 대신, 기존 RDD에서 새로운 RDD를 만들어내는 방식으로 데이터를 변형합니다.
- Lazy Evaluation (지연 실행):
- RDD 연산은 즉시 실행되지 않고, 액션(Action)이 호출될 때만 실행됩니다. 이는 성능 최적화를 가능하게 합니다.
2. RDD의 장점
- 장애 복구: RDD는 혈통(Lineage) 정보를 통해 데이터를 복구할 수 있어 장애에 강합니다.
- 병렬 처리: 클러스터 내 여러 노드에 데이터를 분산하여 병렬 처리 속도를 극대화합니다.
- 유연성: 다양한 데이터 소스 (HDFS, Cassandra, HBase 등)와 데이터 유형을 지원합니다.
- 효율성: 지연 실행과 캐싱을 통해 리소스 사용을 최적화합니다.
3. RDD 생성 방법
RDD는 주로 두 가지 방식으로 생성됩니다:
- 외부 데이터 소스에서 생성
- HDFS, S3, HBase 등의 외부 저장소에서 데이터를 읽어 RDD를 생성할 수 있습니다.
- 컬렉션에서 생성
- 로컬 Scala, Python, Java 컬렉션을 SparkContext의 parallelize 메서드를 사용해 RDD로 변환할 수 있습니다.
예제
4. RDD의 주요 연산 (Transformations & Actions)
RDD 연산은 크게 두 가지로 나뉩니다:
4.1 Transformations (변환 연산)
Transformations는 기존 RDD에서 새로운 RDD를 생성합니다. 지연 실행되며, 결과는 Action이 호출될 때만 평가됩니다.
Transformation설명예제
map | 각 요소에 함수를 적용하여 새로운 RDD 생성 | rdd.map(lambda x: x * 2) |
filter | 조건에 맞는 요소만 포함하는 RDD 생성 | rdd.filter(lambda x: x % 2 == 0) |
flatMap | 요소를 개별 요소로 변환 | rdd.flatMap(lambda x: (x, x**2)) |
distinct | 중복 제거 | rdd.distinct() |
join | 두 RDD를 조인 | rdd1.join(rdd2) |
4.2 Actions (액션 연산)
Actions는 RDD의 결과를 반환하거나 저장합니다. 즉시 실행됩니다.
Action설명예제
collect | 모든 데이터를 드라이버로 반환 | rdd.collect() |
count | 요소의 개수를 반환 | rdd.count() |
take | 상위 n개 요소 반환 | rdd.take(3) |
saveAsTextFile | RDD를 텍스트 파일로 저장 | rdd.saveAsTextFile("output") |
reduce | 병합 연산 수행 | rdd.reduce(lambda x, y: x + y) |
5. RDD의 혈통 (Lineage)과 캐싱
- 혈통(Lineage): RDD는 연산 이력을 추적하여 장애 시 데이터를 복구할 수 있습니다. 이는 Spark UI에서도 시각적으로 확인할 수 있습니다.
- 위 예제에서 filtered_rdd는 혈통 정보로 rdd -> map -> filter 과정을 유지합니다.
-
python코드 복사rdd = sc.parallelize([1, 2, 3, 4]) mapped_rdd = rdd.map(lambda x: x * 2) filtered_rdd = mapped_rdd.filter(lambda x: x > 5)
- 캐싱(Caching): 반복적으로 사용되는 RDD는 cache()나 persist()를 사용해 메모리에 저장할 수 있습니다. 이는 성능을 크게 향상시킵니다.
-
python코드 복사cached_rdd = rdd.cache()
6. RDD vs DataFrame vs Dataset
Spark에서는 RDD 외에도 DataFrame과 Dataset을 제공합니다. 각각의 장단점을 이해하고 적절한 도구를 선택하는 것이 중요합니다.
특성RDDDataFrameDataset
타입 | 타입 불명 | Row 기반 | 타입 지정 가능 |
API | 함수형/객체 지향 | SQL과 유사한 API 제공 | 함수형/SQL 혼합 |
성능 | 느림 (직접 처리) | 최적화된 Catalyst 사용 | Catalyst 사용 |
유연성 | 가장 유연함 | 중간 | 타입 지정 시 제약 있음 |
7. 결론
RDD는 Spark의 기본 데이터 추상화로서 분산 데이터 처리의 강력한 기반을 제공합니다. 하지만 Spark 2.x 이후로는 DataFrame과 Dataset이 성능과 사용 편의성 측면에서 더 많이 사용됩니다. RDD는 여전히 복잡한 사용자 정의 연산이나 낮은 수준의 데이터 처리가 필요할 때 유용합니다.