RDD의 내부 구성을 잠깐 생각해보자. RDD는 Spark에서 추상화 데이터 모델이다. 때문에 분산 처리된 데이터의 집합이기도 하다.
그러므로 위와 같이 표현될 수 있다. 즉, RDD는 각 노드의 파티션에 분산되어 있다.
(예를 들어, groupByKey 메소드의 결과는 Shuffling된 Pair RDD가 될 것이며, Pair RDD는 각 노드의 파티션에 골고루 분산되어 있다.)
여기서 Lineage에서 처럼 A -> B의 관계를 RDD -> RDD로 위의 그림을 좀 더 확장하면, 아래와 같다.
사전에 작업된 RDD를 부모 RDD, 이를 바탕으로 작업된 RDD를 자식 RDD로 정의하며 자식 RDD를 만들게한 map 메소드를 Dependency라 한다.
개념적으로 이제 짚고 넘어가는 것이긴한데, 그 동안 사용했던 RDD Transformation 관련 메소드들은 모두 Dependency 개념을 탑재한 것이다.
그리고 이 개념이 내부적으로 Spark의 성능을 결정하는 Shuffling을 만든다.
좀더 Dependency에 대해 알아보면, 세부적으로 Narrow, Wide Dependency로 나뉜다.
- Narrow Dependency : 부모 RDD 파티션이 자식 RDD 파티션과 최대 1:1로 대응된다. (Shuffling이 거의 발생하지 않으며, 빠르다.)
Narrow Dependency
- Wide Dependency : 부모 RDD 파티션이 자식 RDD 파티션과 N:1로 대응된다. (Shuffling이 많은 데이터에 발생하며, 느리다.)
Wide Dependency
대략 그림만 봐도 이해 할 수 있을 것이다. Wide Dependency는 자식 RDD의 여러 파티션의 데이터와 대응시켜야 하므로 Shuffling이 많이 발생 할 수 밖에 없다.
Spark의 메소드에 따라 Dependency가 다르게 보여지는데, 아래 표를 확인해보자.
Narrow Dependency |
Wide Dependency |
map |
cogroup |
mapValues |
groupWith |
flatMap |
join |
filter |
leftOuterJoin |
groupByKey | |
| reduceByKey |
| distinct |
(위에 표기된 것 외에도 다양한 메소드들이 존재한다.)
이외에도 Spark 스케줄러는 RDD Dependency를 통해 RDD를 추적한다. (즉, 이전 작업 RDD가 무엇인지)
이를 위해 내부적으로는 Dependency 객체가 존재하는데, dependencies 메소드를 통해 해당 객체를 알 수 있다.
val dependencyObject = sc
.parallelize(List(1,2,3,4,5))
.map(a => (a, 1))
.groupByKey()
.dependencies
그런데 Dependency의 종료에 따라 결과가 조금 다를 수 있다.
- Narrow Dependency 일 때는, OneToOneDependency, PruneDependency, RangeDependency
- Wide Dependency 일 때는, ShuffleDependency
간단히 확인해보면, 아래와 같은 결과가 출력된다.
(4) ShuffledRDD[17] at groupByKey at <console>:30 [] +-(4) MapPartitionsRDD[15] at map at <console>:27 [] | ParallelCollectionRDD[14] at parallelize at <console>:25 [] |
(위에서 언급한 것처럼 groupByKey는 Wide Dependency 바탕의 메소드로 ShuffledRDD이다.)
위의 출력된 결과는 Logical Execution Plan으로 Spark에서는 Lineage로 불린다.
사실 새로운 것도 아니고, 단순히 Dependency 따라 RDD를 나열한 것 뿐이다. 때문에 Lineage를 보통 DAG(Directed Acyclic Graph)로 표현한다. (아래 그림 참조)
이렇게 Spark가 RDD를 Lineage의 형태로 구성하는 장점 중 하나는 fault tolerance 특징을 가질 수 있기 때문이다.
즉, Spark는 작업 중 장애가 발생했을 때, 장애가 발생한 부분 부터 다시 시작 할 수 있다.
지금까지 RDD Dependency를 알아보았다.
생각해보면 RDD와 RDD의 의존성을 표현하지만 서로 간의 관계를 통해 Spark의 성능 향상, 장애 대응 또한 접목 시킬 수 있을 정도로 중요한 개념이다.
'IT > Spark' 카테고리의 다른 글
Spark - Spark SQL (0) | 2020.02.08 |
---|---|
Spark - Structured Data (0) | 2020.02.06 |
Spark - Partitioning (0) | 2020.02.04 |
Spark - Shuffling (0) | 2020.02.03 |
Spark - Pair RDD (0) | 2020.02.01 |
댓글