

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# Amazon S3를 사용하여 Spark 성능 개선
<a name="emr-spark-s3-performance"></a>

Amazon EMR은 Amazon S3에 저장된 데이터를 쿼리, 읽기 및 쓰기 위해 Spark를 사용할 때 성능을 최적화하는 기능을 제공합니다.

[S3 Select](https://aws.amazon.com/blogs/aws/s3-glacier-select/)는 Amazon S3로 처리를 '푸시다운'하여 일부 애플리케이션의 CSV 및 JSON 파일에 대한 쿼리 성능을 향상시킬 수 있습니다.

EMRFS Amazon S3 최적화 커미터는 [OutputCommitter](https://hadoop.apache.org/docs/current/api/org/apache/hadoop/mapreduce/OutputCommitter.html) 클래스의 대안으로, EMRFS의 멀티파트 업로드 기능을 사용하여 Spark, DataFrames 및 Datasets를 사용하여 Parquet 파일을 Amazon S3에 쓸 때 성능을 향상시킵니다.

**Topics**
+ [S3 Select와 함께 Spark를 사용하여 쿼리 성능 향상](emr-spark-s3select.md)
+ [EMR Spark MagicCommitProtocol](emr-spark-magic-commit-protocol.md)
+ [EMRFS S3 최적화 커미터 사용](emr-spark-s3-optimized-committer.md)
+ [EMRFS S3 최적화된 커밋 프로토콜 사용](emr-spark-s3-optimized-commit-protocol.md)
+ [EMRFS로 Amazon S3 요청 재시도](emr-spark-emrfs-retry.md)

# S3 Select와 함께 Spark를 사용하여 쿼리 성능 향상
<a name="emr-spark-s3select"></a>

**중요**  
신규 고객은 더 이상 Amazon S3 Select를 사용할 수 없습니다. Amazon S3 Select 기존 고객은 평소처럼 이 기능을 계속 사용할 수 있습니다. [자세히 알아보기](https://aws.amazon.com/blogs/storage/how-to-optimize-querying-your-data-in-amazon-s3/) 

Amazon EMR 릴리스 5.17.0 이상에서는 Amazon EMR 기반 Spark에서 [S3 Select](https://aws.amazon.com/blogs/aws/s3-glacier-select/)를 사용할 수 있습니다. *S3 Select*를 사용하면 애플리케이션이 객체에서 데이터 하위 집합만 검색할 수 있습니다. Amazon EMR의 경우 처리를 위해 대형 데이터 세트를 필터링하는 계산 작업이 클러스터에서 Amazon S3로 '푸시다운'되어 일부 애플리케이션의 성능이 향상되고 Amazon EMR과 Amazon S3 사이에 전송되는 데이터의 양이 줄어듭니다.

S3 Select는 `s3selectCSV` 및 `s3selectJSON` 값을 사용하여 데이터 형식을 지정하는 CSV 및 JSON 파일에서 지원됩니다. 자세한 내용과 예제는 [코드에서 S3 Select 지정](#emr-spark-s3select-specify) 섹션을 참조하세요.

## S3 Select가 애플리케이션에 적합한가요?
<a name="emr-spark-s3select-apps"></a>

S3 Select 사용 여부에 관계없이 애플리케이션을 벤치마킹하여 애플리케이션에 적합한지 여부를 확인하는 것이 좋습니다.

다음 지침을 사용하여 애플리케이션과 함께 S3 Select를 사용할 수 있는지 확인하세요.
+ 쿼리가 원본 데이터 세트 중 반 이상을 필터링합니다.
+ Amazon S3 및 Amazon EMR 클러스터 간 네트워크 연결의 전송 속도와 가용 대역폭이 양호합니다. Amazon S3는 HTTP 응답을 압축하지 않으므로 압축된 입력 파일의 경우 응답 크기가 증가할 수 있습니다.

## 고려 사항 및 제한 사항
<a name="emr-spark-s3select-considerations"></a>
+ 고객 제공 암호화 키를 사용하는 Amazon S3 서버 측 암호화(SSE-C) 및 클라이언트 측 암호화는 지원되지 않습니다.
+ `AllowQuotedRecordDelimiters` 속성이 지원되지 않습니다. 이 속성이 지정되면 쿼리가 실패합니다.
+ UTF-8 형식의 CSV 및 JSON 파일만 지원됩니다. 여러 줄의 CSV는 지원되지 않습니다.
+ 비압축 또는 gzip 파일만 지원됩니다.
+ `nanValue`, `positiveInf`, `negativeInf` 및 손상된 레코드와 관련된 옵션(예: failfast 및 dropmalformed 모드)은 지원되지 않습니다.
+ 10진수 안에 쉼표(,)를 사용하는 것은 지원되지 않습니다. 예를 들어, `10,000`은 지원되지 않고 `10000`은 지원됩니다.
+ 마지막 줄의 설명 문자는 지원되지 않습니다.
+ 파일 끝의 빈 줄은 처리되지 않습니다.
+ 다음과 같은 필터는 Amazon S3로 푸시다운되지 않습니다.
  + `COUNT()` 및 `SUM()` 등의 집계 함수
  + 속성에 대해 `CAST()`를 사용하는 필터링 예를 들어 `CAST(stringColumn as INT) = 1`입니다.
  + 객체이거나 복잡한 속성을 가진 필터 예를 들어 `intArray[1] = 1, objectColumn.objectNumber = 1`입니다.
  + 값이 리터럴 값이 아닌 필터 예: `intColumn1 = intColumn2`
  + 문서화된 제한 사항으로 [S3 Select 지원 데이터 형식](https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-glacier-select-sql-reference-data-types.html)만 지원됩니다.

## 코드에서 S3 Select 지정
<a name="emr-spark-s3select-specify"></a>

다음 예제는 Scala, SQL, R 및 PySpark를 사용하여 CSV에 대해 S3 Select를 지정하는 방법을 보여줍니다. JSON에 대해 S3 Select를 동일한 방식으로 사용할 수 있습니다. 옵션 목록, 기본값 및 제한 사항을 보려면 [옵션](#emr-spark-s3select-specify-options) 섹션을 참조하세요.

------
#### [ PySpark ]

```
spark
  .read
  .format("s3selectCSV") // "s3selectJson" for Json
  .schema(...) // optional, but recommended
  .options(...) // optional
  .load("s3://path/to/my/datafiles")
```

------
#### [ R ]

```
read.df("s3://path/to/my/datafiles", "s3selectCSV", schema, header = "true", delimiter = "\t")
```

------
#### [ Scala ]

```
spark
  .read
  .format("s3selectCSV") // "s3selectJson" for Json
  .schema(...) // optional, but recommended
  .options(...) // optional. Examples:  
  // .options(Map("quote" -> "\'", "header" -> "true")) or
  // .option("quote", "\'").option("header", "true")
  .load("s3://path/to/my/datafiles")
```

------
#### [ SQL ]

```
CREATE TEMPORARY VIEW MyView (number INT, name STRING) USING s3selectCSV OPTIONS (path "s3://path/to/my/datafiles", header "true", delimiter "\t")
```

------

### 옵션
<a name="emr-spark-s3select-specify-options"></a>

`s3selectCSV` 및 `s3selectJSON`을 사용하는 경우 다음 옵션을 사용할 수 있습니다. 지정되지 않은 경우 기본값이 사용됩니다.

#### S3selectCSV와 옵션
<a name="emr-spark-s3select-specify-options-csv"></a>


| 옵션 | 기본값 | 사용법 | 
| --- | --- | --- | 
|  `compression`  |  `"none"`  |  압축 사용 여부를 나타냅니다. `"none"` 외에도 `"gzip"`만 지원됩니다.  | 
|  `delimiter`  |  ","  |  필드 구분 기호를 지정합니다.  | 
|  `quote`  |  `'\"'`  |  따옴표 문자를 지정합니다. 빈 문자열 지정은 지원되지 않으며 잘못된 XML 오류가 발생합니다.  | 
|  `escape`  |  `'\\'`  |  이스케이프 문자를 지정합니다.  | 
|  `header`  |  `"false"`  |  `"false"` 는 헤더가 없음을 나타냅니다. `"true"`는 헤더가 첫 번째 줄에 있음을 나타냅니다. 첫 번째 줄의 헤더만 지원되며 헤더 앞의 빈 줄은 지원되지 않습니다.  | 
|  설명  |  `"#"`  |  설명 문자를 지정합니다. 설명 표시기는 비활성화할 수 없습니다. 즉, `\u0000`의 값은 지원되지 않습니다.  | 
|  `nullValue`  |  ""  |    | 

#### selectJSON과 옵션
<a name="emr-spark-s3select-specify-options-json"></a>


| 옵션 | 기본값 | 사용법 | 
| --- | --- | --- | 
|  `compression`  |  `"none"`  |  압축 사용 여부를 나타냅니다. `"none"` 외에도 `"gzip"`만 지원됩니다.  | 
|  `multiline`  |  "false"  |  `"false"`는 JSON이 S3 Select `LINES` 형식인 것으로 지정합니다. 즉, 입력 데이터의 각 줄에 단일 JSON 객체가 들어 있음을 의미합니다. `"true"`는 JSON이 S3 Select `DOCUMENT` 형식인 것으로 지정합니다. 이는 JSON 객체가 입력 데이터의 여러 줄에 걸쳐 있을 수 있음을 의미합니다.  | 

# EMR Spark MagicCommitProtocol
<a name="emr-spark-magic-commit-protocol"></a>

EMR 6.15.0부터는 S3A 파일 시스템을 사용할 때 MagicCommitProtocol이 Spark용 기본 FileCommitProtocol이 됩니다.

## MagicCommitProtocol
<a name="magic-commit-protocol"></a>

MagicCommitProtocol은 Amazon S3A 파일 시스템을 사용할 때 Amazon S3에 EMR Spark를 사용하여 파일을 쓰는 데 최적화된 [FileCommitProtocol](https://dlcdn.apache.org/spark/docs/2.4.2/api/java/org/apache/spark/internal/io/FileCommitProtocol.html)의 대체 구현입니다. 이 프로토콜은 작업 커밋 단계 중 Amazon S3에서 이름 바꾸기 작업을 피함으로써 애플리케이션 성능을 개선합니다.

MagicCommitProtocol은 S3A 파일 시스템을 사용할 때 Amazon Elastic Map Reduce(EMR)에서 실행되는 Spark에서 사용하는 기본 FileCommitProtocol 구현입니다. MagicCommitProtocol은 내부적으로 [MagicV2Committer](https://docs.aws.amazon.com/emr/latest/ReleaseGuide/s3a-magicv2-committer.html)를 사용하여 Amazon S3에 파일 쓰기를 수행합니다.

정적 삽입 작업의 경우 MagicCommitProtocol은 작업 커밋 단계 중에 작업의 출력 위치에 파일을 기록합니다. 반대로 동적 삽입 덮어쓰기 작업의 경우 작업 시도로 작성된 파일은 작업 커밋 시 작업의 출력 위치에만 나타납니다. 이는 작업 커밋 호출 시 커밋 메타데이터를 Spark 드라이버로 다시 내보내면 가능합니다.

## MagicCommitProtocol 활성화
<a name="enabling-magic-commit-protocol"></a>

MagicCommitProtocol은 S3A 파일 시스템을 사용할 때 Amazon Elastic Map Reduce(EMR)에서 실행되는 Spark에 대해 기본적으로 활성화됩니다.

S3A 파일 시스템을 사용하려면 다음 중 하나를 수행할 수 있습니다.

1. 테이블, 파티션 또는 디렉터리를 정의할 때 파일 스키마를 `s3a://`로 사용합니다.

1. core-site.xml에서 `fs.s3.impl=org.apache.hadoop.fs.s3a.S3AFileSystem` 구성을 설정합니다.

## MagicCommitProtocol 비활성화
<a name="disabling-magic-commit-protocol"></a>

1. `SparkConf`로 하드 코딩하여 `spark.sql.execution.datasources.SQLEmrOptimizedCommitProtocol.leverageMagicCommitProtocol`을 false로 설정하거나, Spark 셸의 `--conf` 파라미터 또는 `spark-submit` 및 `spark-sql` 도구 또는 `conf/spark-defaults.conf`로 전달할 수 있습니다. 자세한 내용은 Apache Spark 설명서에서 [Spark configuration](https://spark.apache.org/docs/latest/configuration.html)을 참조하세요.

   다음 예제에서는 `spark-sql` 명령을 실행하는 동안 MagicCommitProtocol을 비활성화하는 방법을 보여줍니다.

   ```
   spark-sql \
     --conf spark.sql.execution.datasources.SQLEmrOptimizedCommitProtocol.leverageMagicCommitProtocol=false \
   -e "INSERT OVERWRITE TABLE target_table SELECT * FROM source_table;"
   ```

1. `spark-defaults` 구성 분류를 사용하여 `spark.sql.execution.datasources.SQLEmrOptimizedCommitProtocol.leverageMagicCommitProtocol` 속성을 false로 설정합니다. 자세한 내용은 [애플리케이션 구성](https://docs.aws.amazon.com/emr/latest/ReleaseGuide/emr-configure-apps.html)을 참조하세요.

## MagicCommitProtocol 고려 사항
<a name="magic-commit-considerations"></a>
+ 정적 파티션 삽입의 경우, Spark 실행기에서 MagicCommitProtocol은 작업이 커밋되거나 중단될 때까지 작업 시도에서 작성된 각 파일에 대해 소량의 메모리를 사용합니다. 대부분의 작업에서 사용되는 메모리 양은 무시할 수 있습니다. Spark 드라이버에는 추가 메모리 요구 사항이 없습니다.
+ 동적 파티션 삽입의 경우 Spark 드라이버에서 MagicCommitProtocol은 작업이 커밋되거나 중단될 때까지 각 커밋된 파일의 메타데이터 정보를 저장하는 메모리가 필요합니다. 대부분의 작업에서 기본 Spark 드라이버 메모리 설정은 무시해도 됩니다.

  많은 수의 파일을 작성하는 장기 실행 작업이 있는 작업의 경우 커밋 프로토콜이 소비하는 메모리가 눈에 띄고 Spark(특히 Spark 실행기)에 할당된 메모리를 조정해야 할 수도 있습니다. Spark 드라이버의 `spark.driver.memory` 속성과 Spark 실행기의 `spark.executor.memory` 속성을 사용하여 메모리를 튜닝할 수 있습니다. 참고로, 100,000개의 파일을 작성하는 단일 작업에는 일반적으로 200MB의 메모리가 추가로 필요합니다. 자세한 내용은 Apache Spark Configuration 설명서에서 [Application properties](https://spark.apache.org/docs/latest/configuration.html#application-properties)를 참조하세요.

# EMRFS S3 최적화 커미터 사용
<a name="emr-spark-s3-optimized-committer"></a>

EMRFS S3 최적화된 커미터는 EMRFS를 사용할 때 Amazon S3에 파일을 쓰는 데 최적화된 대체 [OutputCommitter](https://hadoop.apache.org/docs/current/api/org/apache/hadoop/mapreduce/OutputCommitter.html) 구현입니다. EMRFS S3 최적화 커미터는 작업 커밋 단계 중 Amazon S3에서 수행된 나열 및 이름 바꾸기 조작을 피함으로써 애플리케이션 성능을 향상시킵니다. 커미터는 Amazon EMR 릴리스 버전 5.19.0 이상에서 사용 가능하며 Amazon EMR 5.20.0 이상에서 기본적으로 활성화됩니다. 이 커미터는 Spark, DataFrames 또는 데이터 세트를 사용하는 Spark 작업에 사용됩니다. Amazon EMR 6.4.0부터 이 커미터는 Parquet, ORC 및 텍스트 기반 형식(CSV 및 JSON 포함)을 비롯한 모든 일반적인 형식에 사용할 수 있습니다. Amazon EMR 6.4.0 이전 릴리스의 경우 Parquet 형식만 지원됩니다. 커미터가 사용되지 않는 상황이 있습니다. 자세한 내용은 [EMRFS S3 최적화 커미터의 요구 사항](emr-spark-committer-reqs.md) 단원을 참조하십시오.

**Topics**
+ [EMRFS S3 최적화 커미터의 요구 사항](emr-spark-committer-reqs.md)
+ [EMRFS S3 최적 커미터 및 멀티파트 업로드](emr-spark-committer-multipart.md)
+ [작업 튜닝 고려 사항](emr-spark-committer-tuning.md)
+ [Amazon EMR 5.19.0에서 EMRFS S3 최적화 커미터 활성화](emr-spark-committer-enable.md)

# EMRFS S3 최적화 커미터의 요구 사항
<a name="emr-spark-committer-reqs"></a>

EMRFS S3 최적화 커미터는 다음과 같은 상황에서 사용됩니다.
+ Spark, DataFrames 또는 Datasets를 사용하여 Amazon S3에 파일을 작성하는 Spark 작업을 실행하는 경우. Amazon EMR 6.4.0부터 이 커미터는 Parquet, ORC 및 텍스트 기반 형식(CSV 및 JSON 포함)을 비롯한 모든 일반적인 형식에 사용할 수 있습니다. Amazon EMR 6.4.0 이전 릴리스의 경우 Parquet 형식만 지원됩니다.
+ Amazon EMR에서 멀티파트 업로드는 활성화됩니다. 기본값입니다. 자세한 내용은 [EMRFS S3 최적 커미터 및 멀티파트 업로드](emr-spark-committer-multipart.md) 단원을 참조하십시오.
+ Spark의 기본 제공 파일 형식 지원이 사용됩니다. 기본 제공 파일 형식 지원은 다음 상황에서 사용됩니다.
  + Hive 메타스토어 테이블의 경우 Parquet 테이블에 대해 `spark.sql.hive.convertMetastoreParquet`을 `true`로 설정하거나, Amazon EMR 6.4.0 이상에서 Orc 테이블에 대해 `spark.sql.hive.convertMetastoreOrc`를 `true`로 설정하는 경우. 기본 설정입니다.
  + 예를 들어, 작업을 파일 형식 데이터 소스 또는 테이블에 쓰는 경우 `USING parquet` 절과 함께 대상 테이블이 생성됩니다.
  + 작업이 파티션 분할되지 않은 Hive 메타스토어 Parquet 테이블에 쓸 경우. Spark의 기본 제공 Parquet 지원은 파티션 분할된 Hive 테이블을 지원하지 않습니다. 이 제한 사항은 알려져 있습니다. 자세한 내용은 Apache Spark, DataFrames 및 Datasets 설명서의 [Hive metastore Parquet table conversion](https://spark.apache.org/docs/latest/sql-data-sources-parquet.html#hive-metastore-parquet-table-conversion)(Hive 메타스토어 Parquet 테이블 변환)을 참조하세요.
+ 기본 파티션 위치(예: `${table_location}/k1=v1/k2=v2/`)에 쓰는 Spark 작업 작업에서는 커미터를 사용합니다. 작업이 사용자 지정 파티션 위치에 쓰는 경우(예: `ALTER TABLE SQL` 명령을 사용하여 사용자 지정 파티션 위치를 설정하는 경우) 커미터는 사용되지 않습니다.
+ Spark에는 다음 값을 사용해야 합니다.
  + `spark.sql.parquet.fs.optimized.committer.optimization-enabled` 속성을 `true`로 설정해야 합니다. 이 설정은 Amazon EMR 5.20.0 이상에서 기본 설정입니다. Amazon EMR 5.19.0에서 기본값은 `false`입니다. 이 값의 구성에 대한 자세한 내용은 다음([Amazon EMR 5.19.0에서 EMRFS S3 최적화 커미터 활성화](emr-spark-committer-enable.md))을 참조하세요.
  + 파티셔닝되지 않은 Hive 메타스토어 테이블에 쓰는 경우 Parquet 및 Orc 파일 형식만 지원됩니다. 파티셔닝되지 않은 Parquet Hive 메타스토어 테이블에 쓸 경우 `spark.sql.hive.convertMetastoreParquet`을 `true`로 설정해야 합니다. 파티셔닝되지 않은 Orc Hive 메타스토어 테이블에 쓸 경우 `spark.sql.hive.convertMetastoreOrc`를 `true`로 설정해야 합니다. 기본 설정입니다.
  + `spark.sql.parquet.output.committer.class`를 `com.amazon.emr.committer.EmrOptimizedSparkSqlParquetOutputCommitter`로 설정해야 합니다. 기본 설정입니다.
  + `spark.sql.sources.commitProtocolClass`를 `org.apache.spark.sql.execution.datasources.SQLEmrOptimizedCommitProtocol` 또는 `org.apache.spark.sql.execution.datasources.SQLHadoopMapReduceCommitProtocol`로 설정해야 합니다. Amazon EMR 5.x 시리즈 버전 5.30.0 이상 및 Amazon EMR 6.x 시리즈 버전 6.2.0 이상에서 `org.apache.spark.sql.execution.datasources.SQLEmrOptimizedCommitProtocol`이 기본 설정입니다. 이전 Amazon EMR 버전에서는 `org.apache.spark.sql.execution.datasources.SQLHadoopMapReduceCommitProtocol`이 기본 설정입니다.
  + Spark 작업이 동적 파티션 열을 포함하는 파티션 분할된 Parquet 데이터 세트를 덮어쓸 경우 `partitionOverwriteMode` 쓰기 옵션과 `spark.sql.sources.partitionOverwriteMode`를 `static`으로 설정해야 합니다. 기본 설정입니다.
**참고**  
`partitionOverwriteMode` 쓰기 옵션은 Spark 2.4.0에서 소개되었습니다. Amazon EMR 릴리스 5.19.0에 포함된 Spark 버전 2.3.2의 경우 `spark.sql.sources.partitionOverwriteMode` 속성을 설정합니다.

## EMRFS S3 최적화 커미터를 사용하지 않는 경우
<a name="emr-spark-committer-reqs-anti"></a>

일반적으로 EMRFS S3 최적화 커미터를 다음 상황에서 사용하지 않습니다.


****  

| 상황 | 커미터가 사용되지 않는 이유 | 
| --- | --- | 
| HDFS에 기록하는 경우 | 커미터는 EMRFS를 사용하는 Amazon S3에 대한 쓰기만 지원합니다. | 
| S3A 파일 시스템을 사용하는 경우 | 커미터는 EMRFS만 지원합니다. | 
| MapReduce 또는 Spark의 RDD API를 사용하는 경우 | 커미터는 SparkSQL, DataFrame 또는 데이터 세트 API 사용만 지원합니다. | 

다음 Scala 예제에서는 EMRFS S3 최적화 커미터의 사용을 전체적으로(첫 번째 예제) 또는 부분적으로(두 번째 예제) 차단하는 몇 가지 추가 상황을 보여줍니다.

**Example - 동적 파티션 덮어쓰기 모드**  
다음 Scala 예제에서는 Spark에 다른 커밋 알고리즘을 사용하도록 지시합니다. 그러면 EMRFS S3 최적화된 커미터도 사용하지 못합니다. 코드는 데이터를 쓰는 해당 파티션만 덮어쓰도록 `partitionOverwriteMode` 속성을 `dynamic`으로 설정합니다. 그러면 동적 파티션 열이 `partitionBy`에 의해 지정되고 쓰기 모드가 `overwrite`로 설정됩니다.  

```
val dataset = spark.range(0, 10)
  .withColumn("dt", expr("date_sub(current_date(), id)"))

dataset.write.mode("overwrite")
  .option("partitionOverwriteMode", "dynamic")
  .partitionBy("dt")
  .parquet("s3://amzn-s3-demo-bucket1/output")
```
EMRFS S3 최적화 커미터를 사용하지 않도록 세 가지 설정을 모두 구성해야 합니다. 이렇게 하면 Spark는 Spark의 커밋 프로토콜에 지정된 다른 커밋 알고리즘을 실행합니다. 5.30.0 이전의 Amazon EMR 5.x 릴리스와 6.2.0 이전의 Amazon EMR 6.x 릴리스에서 커밋 프로토콜은 Spark의 스테이징 디렉터리를 사용합니다. 이 디렉터리는 `.spark-staging`으로 시작하는 출력 위치 아래에 생성된 임시 디렉터리입니다. 알고리즘은 파티션 디렉터리의 이름을 순차적으로 변경하여 성능을 떨어뜨릴 수 있습니다. Amazon EMR 릴리스 5.30.0 이상과 6.2.0 이상에 대한 자세한 내용은 [EMRFS S3 최적화된 커밋 프로토콜 사용](emr-spark-s3-optimized-commit-protocol.md) 섹션을 참조하세요.  
Spark 2.4.0의 알고리즘은 다음 단계를 수행합니다.  

1. 작업 시도에서 출력을 Spark의 스테이징 디렉터리 아래의 파티션 디렉터리(예: `${outputLocation}/spark-staging-${jobID}/k1=v1/k2=v2/`)에 작성합니다.

1. 작성된 각 파티션에 대해 작업 시도에서 상대 파티션 경로(예: `k1=v1/k2=v2`)를 추적합니다.

1. 작업이 성공적으로 완료되면 추적된 모든 상대적 파티션 경로를 드라이버에 제공합니다.

1. 모든 작업이 완료된 후 작업 커밋 단계에서 성공적인 작업 시도가 Spark의 스테이징 디렉터리에 쓴 모든 파티션 디렉터리를 수집합니다. Spark는 디렉터리 트리 이름 변경 작업을 사용하여 각 디렉터리의 이름을 순차적으로 최종 출력 위치로 변경합니다.

1. 스테이징 디렉터리는 작업 커밋 단계가 완료되기 전에 삭제됩니다.

**Example - 사용자 지정 파티션 위치**  
이 예에서 Scala 코드는 두 개의 파티션으로 삽입됩니다. 한 파티션은 사용자 지정 파티션 위치를 갖습니다. 다른 파티션은 기본 파티션 위치를 사용합니다. EMRFS S3 최적화 커미터는 기본 파티션 위치를 사용하는 파티션에 작업 출력을 쓸 때만 사용됩니다.  

```
val table = "dataset"
val location = "s3://bucket/table"
                            
spark.sql(s"""
  CREATE TABLE $table (id bigint, dt date) 
  USING PARQUET PARTITIONED BY (dt) 
  LOCATION '$location'
""")
                            
// Add a partition using a custom location
val customPartitionLocation = "s3://bucket/custom"
spark.sql(s"""
  ALTER TABLE $table ADD PARTITION (dt='2019-01-28') 
  LOCATION '$customPartitionLocation'
""")
                            
// Add another partition using default location
spark.sql(s"ALTER TABLE $table ADD PARTITION (dt='2019-01-29')")
                            
def asDate(text: String) = lit(text).cast("date")
                            
spark.range(0, 10)
  .withColumn("dt",
    when($"id" > 4, asDate("2019-01-28")).otherwise(asDate("2019-01-29")))
  .write.insertInto(table)
```
Scala 코드는 다음 Amazon S3 객체를 생성합니다.  

```
custom/part-00001-035a2a9c-4a09-4917-8819-e77134342402.c000.snappy.parquet
custom_$folder$
table/_SUCCESS
table/dt=2019-01-29/part-00000-035a2a9c-4a09-4917-8819-e77134342402.c000.snappy.parquet
table/dt=2019-01-29_$folder$
table_$folder$
```
사용자 지정 위치의 파티션에 쓸 때 Spark는 앞의 예와 비슷한 커밋 알고리즘을 사용합니다. 이에 대해서는 아래에서 간단히 설명합니다. 앞의 예제와 같이 이 알고리즘은 이름을 순차적으로 변경하여 성능에 부정적인 영향을 줄 수 있습니다.  

1. 사용자 지정 위치의 파티션에 출력을 쓸 경우 작업은 최종 출력 위치에 생성된 Spark의 스테이징 디렉터리에 있는 파일에 씁니다. 파일 이름에는 파일 충돌을 방지하기 위해 무작위 UUID가 포함됩니다. 작업 시도는 각 파일의 추적과, 필요한 최종 출력 경로를 보존합니다.

1. 작업이 성공적으로 완료되면 드라이버에 파일과 해당 출력 경로를 제공합니다.

1. 모든 작업이 완료된 후 작업 커밋 단계에서는 사용자 지정 위치에 파티션에 대해 써진 모든 파일의 이름을 최종 출력 경로로 순차적으로 변경합니다.

1. 스테이징 디렉터리는 작업 커밋 단계가 완료되기 전에 삭제됩니다.

# EMRFS S3 최적 커미터 및 멀티파트 업로드
<a name="emr-spark-committer-multipart"></a>

EMRFS S3 최적화 커미터를 사용하려면 Amazon EMR에 대한 멀티파트 업로드를 활성화해야 합니다. 멀티파트 업로드는 기본적으로 사용하도록 설정되어 있습니다. 필요한 경우 다시 활성화할 수 있습니다. 자세한 내용은 *Amazon EMR 관리 안내서*의 [Amazon S3에 대한 멀티파트 업로드 구성](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-plan-upload-s3.html#Config_Multipart)을 참조하세요.

EMRFS S3 최적화 커미터는 멀티파트 업로드의 트랜잭션과 유사한 특성을 사용하여 작업을 시도할 때 작성된 파일이 작업 커밋 시 작업 출력 위치에만 나타나는지 확인합니다. 이 방법으로 멀티파트 업로드를 사용하면 커미터는 기본 FileOutputCommitter 알고리즘 버전 2보다 작업 커밋 성능을 향상시킵니다. EMRFS S3 최적화 커미터를 사용할 경우, 일반적인 멀티파트 업로드 동작과의 몇 가지 주요한 차이점을 고려해야 합니다.
+ 멀티파트 업로드는 파일 크기에 관계없이 항상 수행됩니다. 이는 `fs.s3n.multipart.uploads.split.size` 속성이 멀티파트 업로드가 트리거되는 파일 크기를 제어하는 EMRFS의 기본 동작과 다릅니다.
+ 멀티파트 업로드는 작업이 커밋되거나 중단될 때까지 더 오랜 기간 동안 불완전한 상태로 유지됩니다. 이는 지정된 파일 작성을 마칠 때 멀티파트 업로드가 완료되는 EMRFS의 기본 동작과 다릅니다.

이러한 차이로 인해 Spark Executor JVM이 충돌하거나 작업이 실행 중이고 Amazon S3에 데이터를 쓰는 경우 불완전한 멀티파트 업로드가 남아 있게 됩니다. 이러한 이유로 EMRFS S3 최적화 커미터를 사용할 때는 실패한 멀티파트 업로드를 관리하는 모범 사례를 따르세요. 자세한 내용은 *Amazon EMR 관리 안내서*에서 Amazon S3 버킷 사용에 대한 [모범 사례](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-plan-upload-s3.html#emr-bucket-bestpractices)를 참조하세요.

# 작업 튜닝 고려 사항
<a name="emr-spark-committer-tuning"></a>

EMRFS S3 최적화 커미터는 작업이 커밋되거나 중단될 때까지 작업 시도 시 작성된 각 파일에 대해 소량의 메모리를 사용합니다. 대부분의 작업에서 사용되는 메모리 양은 무시할 수 있습니다. 많은 수의 파일을 작성하는 장기 실행 작업이 있는 작업의 경우 커미터가 소비하는 메모리가 눈에 띄고 Spark 실행기에 할당된 메모리를 조정해야 할 수도 있습니다. `spark.executor.memory` 속성을 사용하여 실행기 메모리를 튜닝할 수 있습니다. 참고로, 100,000개의 파일을 작성하는 단일 작업에는 일반적으로 100MB의 메모리가 추가로 필요합니다. 자세한 내용은 Apache Spark Configuration 설명서에서 [Application properties](https://spark.apache.org/docs/latest/configuration.html#application-properties)를 참조하세요.

# Amazon EMR 5.19.0에서 EMRFS S3 최적화 커미터 활성화
<a name="emr-spark-committer-enable"></a>

Amazon EMR 5.19.0을 사용할 경우 클러스터를 만들 때 `spark.sql.parquet.fs.optimized.committer.optimization-enabled` 속성을 `true`로 직접 설정할 수 있습니다. Amazon EMR을 사용할 때는 Spark에서 설정할 수 있습니다.

## 클러스터 생성 시 EMRFS S3 최적화 커미터 활성화
<a name="w2aac62c61c17c13b5"></a>

`spark-defaults` 구성 분류를 사용하여 `spark.sql.parquet.fs.optimized.committer.optimization-enabled` 속성을 `true`로 설정합니다. 자세한 내용은 [애플리케이션 구성](emr-configure-apps.md) 단원을 참조하십시오.

## Spark에서 EMRFS S3 최적화 커미터 활성화
<a name="w2aac62c61c17c13b7"></a>

`SparkConf`로 하드 코딩하여 `spark.sql.parquet.fs.optimized.committer.optimization-enabled`를 `true`로 설정하고 Spark 셸의 `--conf` 파라미터 또는 `spark-submit` 및 `spark-sql` 도구 또는 `conf/spark-defaults.conf`로 전달할 수 있습니다. 자세한 내용은 Apache Spark 설명서에서 [Spark configuration](https://spark.apache.org/docs/latest/configuration.html)을 참조하세요.

다음 예제에서는 spark-sql 명령을 실행하는 동안 커미터를 활성화하는 방법을 보여줍니다.

```
spark-sql \
  --conf spark.sql.parquet.fs.optimized.committer.optimization-enabled=true \
  -e "INSERT OVERWRITE TABLE target_table SELECT * FROM source_table;"
```

# EMRFS S3 최적화된 커밋 프로토콜 사용
<a name="emr-spark-s3-optimized-commit-protocol"></a>

EMRFS S3 최적화된 커밋 프로토콜은 EMRFS를 사용할 때 Spark 동적 파티션 덮어쓰기로 Amazon S3에 파일을 쓰는 데 최적화된 대체 [FileCommitProtocol](https://spark.apache.org/docs/2.2.0//api/java/org/apache/spark/internal/io/FileCommitProtocol.html) 구현입니다. 이 프로토콜은 Spark 동적 파티션 덮어쓰기 작업 커밋 단계 중 Amazon S3에서 이름 바꾸기 작업을 피함으로써 애플리케이션 성능을 개선합니다.

[EMRFS S3 최적화된 커미터](emr-spark-s3-optimized-committer.html)는 이름 바꾸기 작업을 피함으로써 성능도 향상시킵니다. 하지만 커밋 프로토콜의 개선 사항이 동적 파티션 덮어쓰기 사례만 대상으로 하는 반면 이 기능은 동적 파티션 덮어쓰기 사례에 유효하지 않습니다.

커밋 프로토콜은 Amazon EMR 릴리스 버전 5.30.0 이상 및 6.2.0 이상에서 사용 가능하며 기본적으로 사용 가능합니다. Amazon EMR은 릴리스 5.31.0부터 병렬 처리 개선 기능을 추가했습니다. 이 프로토콜은 Spark, DataFrame 또는 데이터 세트를 사용하는 Spark 작업에 사용됩니다. 커밋 프로토콜이 사용되지 않는 상황이 있습니다. 자세한 내용은 [EMRFS S3 최적화 커밋 프로토콜의 요구 사항](emr-spark-committer-reqs.md) 단원을 참조하십시오.

**Topics**
+ [EMRFS S3 최적화 커밋 프로토콜의 요구 사항](emr-spark-commit-protocol-reqs.md)
+ [EMRFS S3 최적화 커밋 프로토콜 및 멀티파트 업로드](emr-spark-commit-protocol-multipart.md)
+ [작업 튜닝 고려 사항](emr-spark-commit-protocol-tuning.md)

# EMRFS S3 최적화 커밋 프로토콜의 요구 사항
<a name="emr-spark-commit-protocol-reqs"></a>

EMRFS S3 최적화 커밋 프로토콜은 다음 조건을 충족하는 경우에 사용됩니다.
+ Spark, DataFrame 또는 데이터 세트를 사용하여 파티셔닝된 테이블을 덮어쓰는 Spark 작업을 실행할 경우.
+ 파티션 덮어쓰기 모드가 `dynamic`인 Spark 작업을 실행합니다.
+ Amazon EMR에서 멀티파트 업로드는 활성화됩니다. 기본값입니다. 자세한 내용은 [EMRFS S3 최적화 커밋 프로토콜 및 멀티파트 업로드](emr-spark-commit-protocol-multipart.md) 단원을 참조하십시오.
+ EMRFS의 파일 시스템 캐시가 활성화되었습니다. 기본값입니다. `fs.s3.impl.disable.cache` 설정이 `false`로 설정되어 있는지 확인합니다.
+ Spark의 기본 제공 데이터 소스 지원이 사용됩니다. 기본 제공 데이터 소스 지원은 다음 상황에서 사용됩니다.
  + 작업에서 기본 제공 데이터 소스 또는 테이블에 쓰는 경우.
  + 작업에서 Hive 메타스토어 Parquet 테이블에 쓰는 경우. `spark.sql.hive.convertInsertingPartitionedTable` 및 `spark.sql.hive.convertMetastoreParquet` 모두 true로 설정된 경우에 수행됩니다. 기본 설정입니다.
  + 작업에서 Hive 메타스토어 ORC 테이블에 쓰는 경우. `spark.sql.hive.convertInsertingPartitionedTable` 및 `spark.sql.hive.convertMetastoreOrc` 모두 `true`로 설정된 경우에 수행됩니다. 기본 설정입니다.
+ 기본 파티션 위치에 쓰는 Spark 작업(예: `${table_location}/k1=v1/k2=v2/`)에서는 커밋 프로토콜을 사용합니다. 작업이 사용자 지정 파티션 위치에 쓰는 경우(예: `ALTER TABLE SQL` 명령을 사용하여 사용자 지정 파티션 위치를 설정하는 경우) 프로토콜은 사용되지 않습니다.
+ Spark에는 다음 값을 사용해야 합니다.
  + `spark.sql.sources.commitProtocolClass`를 `org.apache.spark.sql.execution.datasources.SQLEmrOptimizedCommitProtocol`로 설정해야 합니다. 이는 Amazon EMR 릴리스 5.30.0 이상 및 6.2.0 이상 릴리스에서 기본 설정입니다.
  + `partitionOverwriteMode` 쓰기 옵션 또는 `spark.sql.sources.partitionOverwriteMode`를 `dynamic`으로 설정해야 합니다. 기본 설정은 `static`입니다.
**참고**  
`partitionOverwriteMode` 쓰기 옵션은 Spark 2.4.0에서 소개되었습니다. Amazon EMR 릴리스 5.19.0에 포함된 Spark 버전 2.3.2의 경우 `spark.sql.sources.partitionOverwriteMode` 속성을 설정합니다.
  + Spark 작업이 Hive 메타스토어 Parquet 테이블을 덮어쓰는 경우 `spark.sql.hive.convertMetastoreParquet`, `spark.sql.hive.convertInsertingPartitionedTable` 및 `spark.sql.hive.convertMetastore.partitionOverwriteMode`를 `true`로 설정해야 합니다. 기본 설정이 있습니다.
  + Spark 작업이 Hive 메타스토어 ORC 테이블을 덮어쓰는 경우 `spark.sql.hive.convertMetastoreOrc`, `spark.sql.hive.convertInsertingPartitionedTable` 및 `spark.sql.hive.convertMetastore.partitionOverwriteMode`를 `true`로 설정해야 합니다. 기본 설정이 있습니다.

**Example - 동적 파티션 덮어쓰기 모드**  
이 Scala 예제에서는 최적화가 트리거됩니다. 먼저 `partitionOverwriteMode` 속성을 `dynamic`으로 설정합니다. 이렇게 하면 데이터를 쓰는 대상 파티션만 덮어씁니다. 그런 다음, `partitionBy`를 사용하여 동적 파티션 열을 지정하고 쓰기 모드를 `overwrite`로 설정합니다.  

```
val dataset = spark.range(0, 10)
  .withColumn("dt", expr("date_sub(current_date(), id)"))

dataset.write.mode("overwrite")                 // "overwrite" instead of "insert"
  .option("partitionOverwriteMode", "dynamic")  // "dynamic" instead of "static"  
  .partitionBy("dt")                            // partitioned data instead of unpartitioned data
  .parquet("s3://amzn-s3-demo-bucket1/output")    // "s3://" to use Amazon EMR file system, instead of "s3a://" or "hdfs://"
```

## EMRFS S3 최적화 커밋 프로토콜을 사용하지 않는 경우
<a name="emr-spark-commit-protocol-reqs-anti"></a>

일반적으로 EMRFS S3 최적화 커밋 프로토콜은 오픈 소스 기본 Spark 커밋 프로토콜(`org.apache.spark.sql.execution.datasources.SQLHadoopMapReduceCommitProtocol`)과 동일하게 작동합니다. 다음과 같은 상황에서는 최적화가 수행되지 않습니다.


****  

| 상황 | 커밋 프로토콜이 사용되지 않는 이유 | 
| --- | --- | 
| HDFS에 기록하는 경우 | 커밋 프로토콜은 EMRFS를 사용하는 Amazon S3에 대한 쓰기만 지원합니다. | 
| S3A 파일 시스템을 사용하는 경우 | 커밋 프로토콜은 EMRFS만 지원합니다. | 
| MapReduce 또는 Spark의 RDD API를 사용하는 경우 | 커밋 프로토콜은 SparkSQL, DataFrame 또는 데이터 세트 API 사용만 지원합니다. | 
| 동적 파티션 덮어쓰기가 트리거되지 않는 경우 | 커밋 프로토콜은 동적 파티션 덮어쓰기 사례만 최적화합니다. 그 밖의 사례는 [EMRFS S3 최적화 커미터 사용](emr-spark-s3-optimized-committer.md) 섹션을 참조하세요. | 

다음 Scala 예제에서는 EMRFS S3 최적화 커밋 프로토콜이 `SQLHadoopMapReduceCommitProtocol`로 위임하는 몇 가지 추가 상황을 보여줍니다.

**Example - 사용자 지정 파티션 위치가 있는 동적 파티션 덮어쓰기 모드**  
이 예제에서 Scala 프로그램은 동적 파티션 덮어쓰기 모드에서 두 개의 파티션을 덮어씁니다. 한 파티션은 사용자 지정 파티션 위치를 갖습니다. 다른 파티션은 기본 파티션 위치를 사용합니다. EMRFS S3 최적화 커미터는 기본 파티션 위치를 사용하는 파티션만 개선합니다.  

```
val table = "dataset"
val inputView = "tempView"
val location = "s3://bucket/table"
                            
spark.sql(s"""
  CREATE TABLE $table (id bigint, dt date) 
  USING PARQUET PARTITIONED BY (dt) 
  LOCATION '$location'
""")

// Add a partition using a custom location
val customPartitionLocation = "s3://bucket/custom"
spark.sql(s"""
  ALTER TABLE $table ADD PARTITION (dt='2019-01-28') 
  LOCATION '$customPartitionLocation'
""")

// Add another partition using default location
spark.sql(s"ALTER TABLE $table ADD PARTITION (dt='2019-01-29')")

def asDate(text: String) = lit(text).cast("date")   
                       
spark.range(0, 10)
  .withColumn("dt",
    when($"id" > 4, asDate("2019-01-28")).otherwise(asDate("2019-01-29")))
  .createTempView(inputView)
  
// Set partition overwrite mode to 'dynamic'
spark.sql(s"SET spark.sql.sources.partitionOverwriteMode=dynamic")
  
spark.sql(s"INSERT OVERWRITE TABLE $table SELECT * FROM $inputView")
```
Scala 코드는 다음 Amazon S3 객체를 생성합니다.  

```
custom/part-00001-035a2a9c-4a09-4917-8819-e77134342402.c000.snappy.parquet
custom_$folder$
table/_SUCCESS
table/dt=2019-01-29/part-00000-035a2a9c-4a09-4917-8819-e77134342402.c000.snappy.parquet
table/dt=2019-01-29_$folder$
table_$folder$
```
이전 Spark 버전에서 사용자 지정 파티션 위치에 데이터를 쓰면 데이터가 손실될 수 있습니다. 이 예제에서는 `dt='2019-01-28'` 파티션이 손실됩니다. 자세한 내용은 [SPARK-35106](https://issues.apache.org/jira/browse/SPARK-35106)을 참조하세요. 이 문제는 Amazon EMR 릴리스 5.33.0 이상(6.0.x 및 6.1.x 제외)에서 수정되었습니다 .

사용자 지정 위치의 파티션에 쓸 때 Spark는 앞의 예와 비슷한 커밋 알고리즘을 사용합니다. 이에 대해서는 아래에서 간단히 설명합니다. 앞의 예제와 같이 이 알고리즘은 이름을 순차적으로 변경하여 성능에 부정적인 영향을 줄 수 있습니다.

Spark 2.4.0의 알고리즘은 다음 단계를 수행합니다.

1. 사용자 지정 위치의 파티션에 출력을 쓸 경우 작업은 최종 출력 위치에 생성된 Spark의 스테이징 디렉터리에 있는 파일에 씁니다. 파일 이름에는 파일 충돌을 방지하기 위해 무작위 UUID가 포함됩니다. 작업 시도는 각 파일의 추적과, 필요한 최종 출력 경로를 보존합니다.

1. 작업이 성공적으로 완료되면 드라이버에 파일과 해당 출력 경로를 제공합니다.

1. 모든 작업이 완료된 후 작업 커밋 단계에서는 사용자 지정 위치에 파티션에 대해 써진 모든 파일의 이름을 최종 출력 경로로 순차적으로 변경합니다.

1. 스테이징 디렉터리는 작업 커밋 단계가 완료되기 전에 삭제됩니다.

# EMRFS S3 최적화 커밋 프로토콜 및 멀티파트 업로드
<a name="emr-spark-commit-protocol-multipart"></a>

EMRFS S3 최적화 커밋 프로토콜에서 동적 파티션 덮어쓰기 최적화를 사용하려면 Amazon EMR에서 멀티파트 업로드를 활성화해야 합니다. 멀티파트 업로드는 기본적으로 사용하도록 설정되어 있습니다. 필요한 경우 다시 활성화할 수 있습니다. 자세한 내용은 *Amazon EMR 관리 안내서*의 [Amazon S3에 대한 멀티파트 업로드 구성](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-plan-upload-s3.html#Config_Multipart)을 참조하세요.

동적 파티션 덮어쓰기 중에 EMRFS S3 최적화 커밋 프로토콜은 멀티파트 업로드의 트랜잭션과 유사한 특성을 사용하여 작업을 시도할 때 작성된 파일이 작업 커밋 시 작업 출력 위치에만 나타나도록 합니다. 이러한 방식으로 멀티파트 업로드를 사용하면 커밋 프로토콜은 기본 `SQLHadoopMapReduceCommitProtocol`보다 작업 커밋 성능을 더 개선합니다. EMRFS S3 최적화 커밋 프로토콜을 사용할 경우, 일반적인 멀티파트 업로드 동작과의 몇 가지 주요한 차이점을 고려해야 합니다.
+ 멀티파트 업로드는 파일 크기에 관계없이 항상 수행됩니다. 이는 `fs.s3n.multipart.uploads.split.size` 속성이 멀티파트 업로드가 트리거되는 파일 크기를 제어하는 EMRFS의 기본 동작과 다릅니다.
+ 멀티파트 업로드는 작업이 커밋되거나 중단될 때까지 더 오랜 기간 동안 불완전한 상태로 유지됩니다. 이는 지정된 파일 작성을 마칠 때 멀티파트 업로드가 완료되는 EMRFS의 기본 동작과 다릅니다.

이러한 차이로 인해 작업이 실행 중이고 Amazon S3에 데이터를 쓰는 동안 Spark 실행기 JVM이 충돌하거나 강제 종료되거나 작업 실행 중에 Spark 드라이버 JVM이 충돌하거나 강제 종료되는 경우 불완전한 멀티파트 업로드가 남을 가능성이 큽니다. 이러한 이유로 EMRFS S3 최적화 커밋 프로토콜을 사용할 때는 실패한 멀티파트 업로드를 관리하는 모범 사례를 따릅니다. 자세한 내용은 *Amazon EMR 관리 안내서*에서 Amazon S3 버킷 사용에 대한 [모범 사례](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-plan-upload-s3.html#emr-bucket-bestpractices)를 참조하세요.

# 작업 튜닝 고려 사항
<a name="emr-spark-commit-protocol-tuning"></a>

Spark 실행기에서 EMRFS S3 최적화 커밋 프로토콜은 작업이 커밋되거나 중단될 때까지 작업 시도 시 작성된 각 파일에 대해 소량의 메모리를 사용합니다. 대부분의 작업에서 사용되는 메모리 양은 무시할 수 있습니다.

Spark 드라이버에서 EMRFS S3 최적화 커밋 프로토콜에는 작업이 커밋되거나 중단될 때까지 각 커밋된 파일의 메타데이터 정보를 저장하기 위한 메모리가 필요합니다. 대부분의 작업에서 기본 Spark 드라이버 메모리 설정은 무시해도 됩니다.

많은 수의 파일을 작성하는 장기 실행 작업이 있는 작업의 경우 커밋 프로토콜이 소비하는 메모리가 눈에 띄고 Spark(특히 Spark 실행기)에 할당된 메모리를 조정해야 할 수도 있습니다. Spark 드라이버의 `spark.driver.memory` 속성과 Spark 실행기의 `spark.executor.memory` 속성을 사용하여 메모리를 튜닝할 수 있습니다. 참고로, 100,000개의 파일을 작성하는 단일 작업에는 일반적으로 100MB의 메모리가 추가로 필요합니다. 자세한 내용은 Apache Spark Configuration 설명서에서 [Application properties](https://spark.apache.org/docs/latest/configuration.html#application-properties)를 참조하세요.

# EMRFS로 Amazon S3 요청 재시도
<a name="emr-spark-emrfs-retry"></a>

이 주제에서는 EMRFS를 사용하여 Amazon S3에 요청할 때 사용할 수 있는 재시도 전략에 대한 정보를 제공합니다. 요청 비율이 증가하면 S3는 새 속도를 지원하도록 조정을 시도합니다. 이 과정에서 S3는 요청을 제한하고 `503 Slow Down` 오류를 반환할 수 있습니다. S3 요청의 성공률을 높이기 위해 `emrfs-site` 구성에서 속성을 구성하여 재시도 전략을 조정할 수 있습니다.

다음과 같은 방법으로 재시도 전략을 조정할 수 있습니다.
+ 기본 지수 백오프 재시도 전략의 최대 재시도 한도를 늘립니다.
+ 가산 증가 및 지수 감소(AIMD) 재시도 전략을 활성화하고 구성합니다. AIMD는 Amazon EMR 릴리스 6.4.0 이상에서 지원됩니다.

## 기본 지수 백오프 전략 사용
<a name="emr-spark-emrfs-retry-exponential-backoff"></a>

기본적으로 EMRFS는 지수 백오프 전략을 사용하여 Amazon S3 요청을 재시도합니다. 기본 EMRFS 재시도 제한은 15회입니다. S3 `503 Slow Down` 오류를 방지하기 위해 새 클러스터를 생성할 때, 실행 중인 클러스터에서 또는 애플리케이션 런타임에 재시도 한도를 늘릴 수 있습니다.

재시도 한도를 늘리려면 `fs.s3.maxRetries` 구성에서 `emrfs-site`의 값을 변경해야 합니다. 다음 예제 구성은 `fs.s3.maxRetries`를 사용자 지정 값(30)으로 설정합니다.

```
[
    {
      "Classification": "emrfs-site",
      "Properties": {
        "fs.s3.maxRetries": "30"
      }
    }
]
```

구성 객체 작업에 대한 자세한 내용은 [애플리케이션 구성](emr-configure-apps.md) 섹션을 참조하세요.

## AIMD 재시도 전략 사용
<a name="emr-spark-emrfs-retry-aimd"></a>

Amazon EMR 릴리스 6.4.0 이상에서 EMRFS는 가산 증가 및 지수 감소(AIMD) 모델을 기반으로 하는 대체 재시도 전략을 지원합니다. AIMD 재시도 전략은 대형 Amazon EMR 클러스터를 사용할 때 특히 유용합니다.

AIMD는 최근 성공한 요청에 대한 데이터를 사용하여 사용자 지정 요청 비율을 계산합니다. 이 전략을 사용하면 제한된 요청 수와 요청당 필요한 총 시도 횟수를 줄일 수 있습니다.

AIMD 재시도 전략을 활성화하려면 다음 예제와 같이 `emrfs-site` 구성에서 `fs.s3.aimd.enabled` 속성을 `true`로 설정해야 합니다.

```
[
    {
      "Classification": "emrfs-site",
      "Properties": {
        "fs.s3.aimd.enabled": "true"
      }
    }
]
```

구성 객체 작업에 대한 자세한 내용은 [애플리케이션 구성](emr-configure-apps.md) 섹션을 참조하세요.

## 고급 AIMD 재시도 설정
<a name="emr-spark-emrfs-retry-advanced-properties"></a>

다음 테이블에 나열된 속성을 구성하여 AIMD 재시도 전략을 사용할 때 재시도 동작을 세분화할 수 있습니다. 대부분의 사용 사례에서는 기본값을 사용하는 것이 좋습니다.


**고급 AIMD 재시도 전략 속성**  

| 속성 | 기본값  | 설명 | 
| --- | --- | --- | 
| fs.s3.aimd.increaseIncrement | 0.1 | 연속 요청 성공 시 요청 비율이 얼마나 빨리 증가하는지를 제어합니다. | 
| fs.s3.aimd.reductionFactor | 2 | Amazon S3에서 503 응답을 반환할 때 요청 비율이 얼마나 빨리 감소하는지를 제어합니다. 기본 계수(2)를 사용하면 요청 비율이 절반으로 줄어듭니다. | 
| fs.s3.aimd.minRate | 0.1 | 요청이 S3에 의해 지속적으로 제한되는 경우 요청 비율의 하한을 설정합니다. | 
| fs.s3.aimd.initialRate | 5500 | 초기 요청 비율을 설정합니다. 이 속도는 fs.s3.aimd.increaseIncrement 및 fs.s3.aimd.reductionFactor에 지정한 값에 따라 달라집니다.초기 속도는 GET 요청에도 사용되며 PUT 요청의 경우 비례적으로 조정됩니다(3,500/5,500). | 
| fs.s3.aimd.adjustWindow | 2 | 요청 비율을 조정하는 빈도를 제어합니다(단위: 응답 수). | 
| fs.s3.aimd.maxAttempts | 100 | 요청을 시도할 수 있는 최대 시도 횟수를 설정합니다. | 