# 2.1.1 Spark Intro

[Apache Spark](https://spark.apache.org/) 는 데이터 처리를 위한 범용 프레임워크 입니다. 데이터 파이프라인을 위해 많이 사용되며, 산업 표준에 가깝습니다.&#x20;

### Languages and Libraries

![Apache Spark Languages and Libraries (https://www.datanami.com/2019/03/08/a-decade-later-apache-spark-still-going-strong/)](https://530470138-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lmdl6Kr60tPfvS6xNHH%2Fuploads%2FOFK1wq2GNvwEcwQqzycH%2Fimage.png?alt=media\&token=245afbe8-d81a-4223-ab5e-d6096e2176f5)

Scala 이외에도 Python, R 등 다양한 언어를 지원하며 데이터 처리를 위한 라이브러리가 많이 존재합니다.  ([Spark 관련 Third Party 프로젝트 목록](https://spark.apache.org/third-party-projects.html))

* [PySpark](http://spark.apache.org/docs/latest/api/python/)
* [SparkR (R on Spark)](https://spark.apache.org/docs/latest/sparkr.html)
* [Spark MLLib (머신러닝 라이브러리)](https://spark.apache.org/docs/latest/ml-guide.html)
* [GraphX (그래프 데이터 처리 라이브러리)](https://spark.apache.org/docs/latest/graphx-programming-guide.html)

### Supported API Levels

![Spark APIs (Slide)](https://530470138-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lmdl6Kr60tPfvS6xNHH%2Fuploads%2FZ7mK4ENfobrnc3COBzr7%2Fimage.png?alt=media\&token=ae847794-f5e6-49a5-b2a6-ba8b9be833c8)

Spark SQL / Dataframe / Dataset API 등 다양한 형태의 API 를 제공해 사용자 편의 및 개발 환경에 따라 자유롭게 선택할 수 있습니다.&#x20;

### Storage Connectors

![Spark Integration (https://www.datamechanics.co/apache-spark)](https://530470138-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lmdl6Kr60tPfvS6xNHH%2Fuploads%2FRBuAK3ehoc5aaqVJpdcY%2Fimage.png?alt=media\&token=9f9ed19e-5590-422f-af29-716db8b64dad)

다양한 Storage 와 연동되는 Connector 가 존재합니다.&#x20;

* [Kafka Connector](https://spark.apache.org/docs/latest/structured-streaming-kafka-integration.html)
* [ElasticSearch Connector](https://www.elastic.co/guide/en/elasticsearch/hadoop/current/spark.html)
* [MongoDB Connector](https://docs.mongodb.com/spark-connector/current/)
* [Redis Connector](https://github.com/RedisLabs/spark-redis)
* [Cassandra Connector](https://github.com/datastax/spark-cassandra-connector)

### Cluster Managers

![Spark Cluster Manager (Link)](https://530470138-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lmdl6Kr60tPfvS6xNHH%2Fuploads%2FrsqUwsjpN3GT57ZtKm9R%2Fimage.png?alt=media\&token=a556b167-119c-4409-8d35-99b8d23a4082)

![Spark Shell - Scala](https://530470138-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lmdl6Kr60tPfvS6xNHH%2Fuploads%2F5lP5TBRJhpK6alt2xPV7%2Fimage.png?alt=media\&token=cb93554b-e71b-4dda-a633-3a1560108655)

![Spark Shell - PySpark](https://530470138-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lmdl6Kr60tPfvS6xNHH%2Fuploads%2F0imjdTUPYiuHgdza5Wug%2Fimage.png?alt=media\&token=25d404f8-5be7-4ec8-bf1d-bd4ee8d31a8f)

![Spark Shell - SQL](https://530470138-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lmdl6Kr60tPfvS6xNHH%2Fuploads%2Fh4aDIbZAXjbrJQZbCzsb%2Fimage.png?alt=media\&token=b38c8127-7d2a-4b11-ad0e-d293794841c5)

![Jupyrer Notebook w/ Spark Kernel](https://530470138-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lmdl6Kr60tPfvS6xNHH%2Fuploads%2FyfH1ImufbCXaJnG19nIc%2Fimage.png?alt=media\&token=f8400e0a-c759-4274-b07f-91b49a9cc59a)

* 다양한 실행 모드 및 환경을 지원해 어느 환경에서나 사용할 수 있습니다.
  * Spark Shell / Jupyter Notebook
  * Local Mode / Client Mode / Cluster Mode
  * Spark Batch / Stream Streaming
  * Standalone / Yarn / Kubernetes Environment

### Summary

![Spark Usage (Link)](https://530470138-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lmdl6Kr60tPfvS6xNHH%2Fuploads%2FhDZyIr0yQYnboXMs2QiJ%2Fimage.png?alt=media\&token=2030e940-ba39-4ddd-b1a6-4de20e30f8b6)

요약하면 Spark 는&#x20;

* 여러 환경과 모드를 지원하며
* 다양한 커넥터를 이용해 데이터를 추출 및 저장이 가능하고
* 사용자 편의에 맞추어 언어와 API, 그리고 라이브러리를 선택해
* 분산처리를 수행할 수 있는 **범용** 데이터 처리 도구입니다.

```python
spark
  .read                     // 데이터를 읽어옵니다.
  .format("jdbc")           // "jdbc" 뿐 아니라 "kafka" 등 다양한 Format 을 사용할 수 있습니다
  
  .join(...)                // 다른 데이터와 Join (병합) 합니다.

  .where(...)               // 데이터 Row 필터링하거나
  .selectExpr(...)          // 필요한 Column 만 선택합니다.
  
  repartition(5, "col1")    // 얼마나 / 어떤 기준으로 분산해 처리할지를 정의합니다
  .groupBy(...)             // 집계 연산을 수행합니다 
  .agg(...)    
  
  repartition(...)          // 얼마나 / 어떤 기준으로 분산해 저장할지를 정의합니다.
  .write
  .format("kafka")        // 데이터를 Parquet Format 
  .option(...)              // 원하는 옵션을 주어
  .save(...)                // 저장합니다.
  
  
  
```

예를 들어 위 코드에서는 Spark 를 이용해

* JDBC (MySQL) Driver 로 데이터를 읽어
* 다른 데이터와 Join 하고
* Row 필터링 / Column 선택 등을 수행한 뒤
* 원하는 기준으로 집계 연산 (Group By) 를 수행하고
* 마지막으로는 Kafka 로 내보냅니다.

이 과정에서 사용자는 Spark 만 알아도 다양한 저장소 (Hive, S3, Kafka, MySQL) 와 다양한 Format (Avro, Parquet, CSV) 을 이용할 수 있고, Pandas 프레임워크 또는 RDB 의 SQL 이 제공하는 거의 유사한 API 와 문법을 이용해 데이터를 가공할 수 있습니다.

또한 컴퓨팅은 분산처리되어 발생하므로, 기존의 단일 머신에서 수행되는 Pandas 컴퓨팅 / RDB SQL 컴퓨팅 보다 더 큰 데이터를 빠른 시간 내에 처리할 수 있습니다.

### Question&#x20;

다음 질문은 전통적인 RDB 와 Spark 의 컴퓨팅 관점에서의 차이를 보여줍니다. &#x20;

> RDB 를 사용하는것과 Spark 를 사용하는것은 어떤 차이점이 있나요? RDB 와 다르게 Spark 의 explain() 결과는 충분하지 않은 것 같습니다. 일반적으로 Spark 작업은 어떻게 튜닝하나요?

![MySQL vs Spark (Link)](https://530470138-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lmdl6Kr60tPfvS6xNHH%2Fuploads%2FID7mURBSpj1qmMGkvW6p%2Fimage.png?alt=media\&token=c8fd8075-9490-4098-a0d9-5989dd2660c3)

![MySQL vs Spark (Link)](https://530470138-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lmdl6Kr60tPfvS6xNHH%2Fuploads%2FqDYFk0Ue1KwYY2bDogCy%2Fimage.png?alt=media\&token=43ff0e4f-0352-46cb-8147-09194d35ce28)

RDB 에서 실행되는 쿼리와 Spark 작업은 다음의 차이점이 있습니다.

* 서비스로 나가는 RDB 쿼리는 많아야 수개 테이블을 조인하지만, Spark Job 은 수십개의 테이블을 Join 할 수 있습니다.
  * 서비스로 나가는 RDB 쿼리는 수십-수백 millis 내로 결과를 내야하지만, Spark Job 은 작업에 따라 짧게는 5분, 머신러닝 집계는 수십 시간까지 걸릴 수 있습니다.
  * 서비스로 나가는 RDB 쿼리는 단일머신에서 수행되고 RDB 의 메모리는 많아봐야 ‘인스턴스 전체’ 에서 최대 수백기가지만, Spark 작업은 ‘하나의 Job’ 이 수백기가 / 수테라의 메모리를 사용할 수 있습니다.
  * 서비스로 나가는 RDB 쿼리는 단일머신에서 수행되므로, 중간 집계를 위한 네트워크 이동이 없습니다. 반면 Spark 작업은 분산처리가 기본이며, Shuffle 로 인한 네트워크 데이터 이동은 물론 메모리 부족으로 인한 Disk Spill 이 발생할 수 있습니다.
  * RDB 는 일반적으로 단일머신에서 고성능을 내기 위한 언어로 만들어졌지만, Spark 는 JVM 위에서 동작합니다.
  * RDB 는 ‘쿼리’ 단위로 튜닝이 일반적으로 쿼리 실행 시간이 중요한 요소가 되며, 테이블의 DDL (인덱스) 등을 DBA 와 같이 논의할 수 있습니다. 반면 Spark 는 하나의 작업에 걸리는 소요 시간이 긴 만큼 ‘작업’ 단위로 튜닝이 될 수 있습니다. 작업 내에서의 일부 Spark SQL 의 국소적인 최적화는 큰 의미가 없을수도 있습니다.
    * 서비스 백엔드 엔지니어는 QueryDSL / JPQL 등으로 감싸진 ‘쿼리’ 를 수백개 작성하고, 운영할 수 있겠지만 데이터 엔지니어는 개별 Table 에 데이터를 적재하는 ‘Spark Job’ 을 한명의 엔지니어가 수백-수천개 관리할 수 있습니다.

따라서 다음의 관점으로 튜닝이 진행됩니다.

리소스 측면에서 실행하는 컴퓨팅 종류에 따라 Driver 및 Executor 의 CPU / Memory 설정과 인스턴스 타입, 그리고 Network / Disk 등 리소스가 충분한지 확인합니다.

* Disk Spill / Shuffle Write 등이 메모리에 비해 과다할 경우 혹은 GC 가 너무 잦게 발생할 경우 메모리를 늘립니다.
* 머신러닝 등 컴퓨팅이 많이 필요한 Spark Job 은 CPU 를 늘릴 수 있습니다. 일반적으로는 작업마다 다른 EC2 인스턴스 타입을 사용하게끔 데이터 인프라가 설계됩니다. (머신러닝은 c5.8xlarge, 일반 집계는 r5.4xlarge 등)
* 네트워크 대역폭이 모자랄 경우 c5n, r5n 등 네트워크 전용 인스턴스 타입을 고려할 수 있습니다. 다만 AWS 특정 Region / Zone 에서는 지원되지 않을 수 있습니다.
* Disk 가 모자랄 경우 Spill 이 더이상 불가능해 Executor 가 종료될 수 있으므로 Shuffle Write / Memory 부족으로 인한 Spill 등 Disk 사용량을 모니터링 해 부족하면 Executor 숫자를 늘려 사이즈를 분산하거나, 더 큰 사이즈의 Disk (AWS EBS) 를 사용할 수 있습니다. 필요에 따라 높은 성능의 IO 를 가진 EBS 클래스를 선택할 수 있습니다.
* RDB 는 리소스를 변경하려면 (Spec Up) Downtime 이 필요하지만, Spark 는 Node 를 쉽게 버튼 눌러 추가하면 됩니다. 따라서 리소스를 추가하는데 부담을 갖지 말고, 내 시간을 아끼는 것에 더 집중하는 편이 낫습니다.

<br>
