TechY's blog
Always think Tech and Y

Apache Spark를 알아보자

|

Data engineer 가 되기 위해 필요한 기술 스택들을 하나씩 알아보다보니, Spark라는 processing framework이 많이 나오는 것 같아서, 한번 가볍게 훑어보기로 했다. 해당 포스트는 정리와 메모 용도이기 때문에, 오역이 있을 수 있어, 계속적인 수정과 추가가 될 예정이다.

참고 자료 :

우선 distributed system이 무엇인지에 대해서 간략하게 알아본다.

mutiple entities talking to one another in some way, while also perfomring their own operations

다수의 entity가 있고, 이들이 서로 “상호작용” 하면서 각자의 “연산”을 하는 것을 distributed system라고 한다. 여기서 entity는 우리의 관심 아래에서는 process 가 될 수 있겠다. entity를 일반화하고 공식화하기 위해서 이를 그래프 이론에 있는 node, edge 로 치환하여 {entity:node, communication:edge} 로 사용한다.

큰 부하가 요구되는 operation이 여러 가지의 node로 나뉘어지고, operation 자체의 속도나 양은 줄게 된다.

하지만, single system에는 존재하지 않았던 node 간 communication 시간이 발생하면서 bottleneck으로 작용할 수 있게 된다. 또한, 발생 가능한 문제로써, sequence가 중요한 경우, 각 node들의 분리된 연산이 끝나고 join 되는 과정에서 distributed system 자체의 clock를 쓴다고 하는데, 이 방법이 완전 무결한 것은 아니라고 한다.

Spark 운영 방식 중 분산 처리 부분을 알아보자.

  • Partitioned data

데이터를 하나가 아닌 여러 개의 노드로 나누기 위해서는 데이터 또한 나뉘어져야 한다. 쉽게 생각해서, 판다스 데이터 프레임이 종 또는 횡으로 파티션 되는 것을 생각해볼 수 있다.

  • Fault Tolerance

분산 처리에서 노드들은 서로 communication하면서 연산이 진행되는데, 갑자기 한 노드가 에러가 나면서 작업이 실패하게 되어도 계속해서 프로그램을 진행하는 것을 의미한다. 이는 Spark 의 RDD 를 통해 구현된다 고 하는데, 이는 뒤에서 더 알아본다.

  • Lazy Evaluation

Spark의 분산 처리는 lazy evaluation을 진행하게 되는데, 여기서 evaluation은 각각의 코드 라인들이 어떤 것을 의미하고 어떤 결과를 낳는지에 대한 것이다. lazy evaluation이란, evaluation의 시점이 code expression의 결과값이 나오고 나서, 이를 추적함으로써, 컴파일 과정을 평가하는 것인데, 이는 유의미하고 실질적인 평가만을 보장하므로써, 프로그램을 더욱 효율적으로 만든다고 한다.

다음으로는 Spark 의 구성 요소들에 대해서 알아본다.

  • RDD (Resilient Distributed Datsets)

이는 Spark의 주요 데이터 구조로써, 불변한 성질을 가지고 있으며 파티션된 컬렉션(tuple, objects) 들의 기록라고 한다. 이러한 기록들은 분산 시스템으로 올라가 연산이 진행된다. RDD 데이터셋의 특징 중 하나는 스키마가 없다는 것인데, 쉽게 말해 컬럼이 없다. 따라서 형태가 리스트처럼 보이게 된다. 이에 따라, 다른 데이터셋보다 상대적으로 가독성이 떨어진다.

  • Spark DataFrames

RDD 의 특성을 다 가지고 있는 데이터셋이다. 똑같이 불변한 성질을 가지고 있다. 다만 스키마가 존재한다. 즉, RDD가 pd.Series 였다면, Spark DataFrame 은 pd.DataFrame 과 같은 성질을 가진다. (그래도 데이터 프레임과는 다른 성질을 띄고 있다.) 이에 따라, 더 높은 수준의 추상화를 지원하게 된다. ex) PySpark

  • Spark DataSets

static data type을 가지고 있는 Spark DataFrame으로, 자연스레 성능의 우위를 가지고 있지만, dynamic dtype을 지원하는 파이썬에서는 사용할 수 없다.

  • Transformation

특정 함수(연산)를 RDD에 적용을 하면, RDD는 불변하기 때문에, 새로운 RDD를 결과값으로 뱉게 된다.
어떤 tranformation 을 사용하느냐에 따라, narrow 와 wide가 나뉘어지게 되고, 이 기준은 파티션 데이터가 하나(single parent RDD)가 쓰이냐 아니면 다수(multiple partitions of RDD)가 쓰이냐에 있다. 이렇게 변환되어 나온 자식 RDD는 RDD lineage 라는 것에 올라간다. (다음에 다룬다.)

Alt text

Alt text

  • Actions

이전에 나온 Transformation은 “데이터 + 연산 = 변환된 데이터” 의 양상이었다. Actions의 경우 “데이터 + 연산 = 값” 의 형태로 여기서 “값” 은 데이터의 변형이 아닌, 의미를 가진 value가 된다. 예로 들어, 문장 내에 ‘안녕’ 이 몇 개가 있나 와 같은 것을 의미한다. 따라서, Actions의 경우 입력으로 RDD를 받지만 결과값으로 RDD를 가지지는 않는다.

  • Lineage Graph

Transformation 또는 Actions은 Graph를 생성하게 된다. 이는 logical execution plan이라고 불리기도 하는데, 컴파일러에게 어떤 RDD부터 컴파일을 시작할지에 대한 정보를 주는 그래프를 의미한다. 이 그래프는 Spark 의 특성 중 하나인 fault tolerance 와 관련이 있는데, 한 노드가 에러가 나면, 노드가 기존에 해야했어야 할 것으로 추정되는 정보가 lineage graph에 다른 곳으로 카피되어 저장된다.

Further works

  • 스파크를 실제로 써보자
  • 스파크를 공부하다보니, MapReduce 라는 참고 문헌과 같은 기술이 존재한다. 이를 공부해보자.

Comments