

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

# Apache Spark
<a name="emr-spark"></a>

[Apache Spark](https://aws.amazon.com/emr/features/spark/)는 Amazon EMR 클러스터에서 기계 학습, 스트림 처리 또는 그래픽 분석을 수행하는 데 도움이 되는 분산 처리 프레임워크 및 프로그래밍 모델입니다. Apache Hadoop과 마찬가지로, Spark는 빅 데이터 워크로드에 일반적으로 사용되는 오픈 소스 분산형 처리 시스템입니다. 하지만 Spark와 Hadoop MapReduce 간에는 다른 몇 가지 큰 차이가 있습니다. Spark에는 최적화된 비순환 방향 그래프(DAG) 실행 엔진이 있고 메모리 안에 데이터를 능동적으로 캐시하므로 특히 특정 알고리즘 및 대화형 쿼리의 성능이 향상됩니다.

Spark는 기본적으로 Scala, Python 및 Java로 작성된 애플리케이션을 지원합니다. 여기에는 SQL용 여러 통합 라이브러리([Spark](https://spark.apache.org/sql/)), 기계 학습([MLlib](https://spark.apache.org/mllib/)), 스트림 처리([Spark streaming](https://spark.apache.org/streaming/)) 및 그래프 처리([GraphX](https://spark.apache.org/graphx/))도 포함됩니다. 이러한 도구를 사용하면 다양한 사용 사례에 대해 Spark 프레임워크를 보다 쉽게 활용할 수 있습니다.

Amazon EMR 클러스터에 다른 Hadoop 애플리케이션과 함께 Spark를 설치할 수 있으며, Amazon EMR 파일 시스템(EMRFS)을 활용하여 Amazon S3에서 데이터에 직접 액세스할 수도 있습니다. Hive도 Spark와 통합되므로 HiveContext 객체를 사용하여 Spark에서 Hive 스크립트를 실행할 수 있습니다. Hive 컨텍스트는 spark-shell에 `sqlContext`로 포함됩니다.

Spark로 EMR 클러스터를 설정하고 샘플 데이터 세트를 분석하는 예제 자습서는 AWS 뉴스 블로그의 [자습서: Amazon EMR 시작하기](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-gs.html)를 참조하세요.

Apache Spark 문제 해결 에이전트를 사용하여 EC2 및 EMR Serverless의 EMR에서 Apache Spark 애플리케이션의 문제를 해결할 수 있습니다. 자세한 내용은 단원을 참조하십시오[Amazon EMR용 Apache Spark 문제 해결 에이전트란?](spark-troubleshoot.md).

**중요**  
Amazon EMR 릴리스 5.16.0부터 사용할 수 있는 Apache Spark 버전 2.3.1은 [CVE-2018-8024](https://nvd.nist.gov/vuln/detail/CVE-2018-8024) 및 [CVE-2018-1334](https://nvd.nist.gov/vuln/detail/CVE-2018-1334)를 처리합니다. Spark의 이전 버전을 Spark 버전 2.3.1 이상으로 마이그레이션하는 것이 좋습니다.

다음 테이블에는 Amazon EMR이 Spark를 통해 설치하는 구성 요소와 함께 Amazon EMR 7.x 시리즈의 최신 릴리스에 포함된 Spark의 버전이 나열되어 있습니다.

이 릴리스에서 Spark와 함께 설치된 구성 요소의 버전은 [릴리스 7.12.0 구성 요소 버전을 참조하세요](emr-7120-release.md).


**emr-7.12.0용 Spark 버전 정보**  

| Amazon EMR 릴리스 레이블 | Spark 버전 | Spark와 함께 설치된 구성 요소 | 
| --- | --- | --- | 
| emr-7.12.0 | Spark 3.5.6-amzn-1 | delta, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-hdfs-zkfc, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 

다음 테이블에는 Amazon EMR이 Spark를 통해 설치하는 구성 요소와 함께 Amazon EMR 6.x 시리즈의 최신 릴리스에 포함된 Spark의 버전이 나열되어 있습니다.

이 릴리스에서 Spark와 함께 설치된 구성 요소의 버전은 [릴리스 6.15.0 구성 요소 버전](emr-6150-release.md)을 참조하세요.


**emr-6.15.0용 Spark 버전 정보**  

| Amazon EMR 릴리스 레이블 | Spark 버전 | Spark와 함께 설치된 구성 요소 | 
| --- | --- | --- | 
| emr-6.15.0 | Spark 3.4.1-amzn-2 | aws-sagemaker-spark-sdk, delta, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 

**참고**  
Amazon EMR 릴리스 6.8.0은 Apache Spark 3.3.0과 함께 제공됩니다. 이번 Spark 릴리스에서는 Apache Log4j 2 및 `log4j2.properties` 파일을 사용하여 Spark 프로세스에서 Log4j를 구성합니다. 클러스터에서 Spark를 사용하거나 사용자 지정 구성 파라미터를 사용하여 EMR 클러스터를 생성하고 Amazon EMR 릴리스 6.8.0으로 업그레이드하려는 경우 Apache Log4j 2의 새로운 `spark-log4j2` 구성 분류 및 키 형식으로 마이그레이션해야 합니다. 자세한 내용은 [Apache Log4j 1.x에서 Log4j 2.x로 마이그레이션](emr-spark-configure.md#spark-migrate-logj42) 단원을 참조하십시오.

다음 테이블에는 Amazon EMR이 Spark를 통해 설치하는 구성 요소와 함께 Amazon EMR 5.x 시리즈의 최신 릴리스에 포함된 Spark의 버전이 나열되어 있습니다.

이 릴리스에서 Spark와 함께 설치된 구성 요소의 버전은 [릴리스 5.36.2 구성 요소 버전](emr-5362-release.md)을 참조하세요.


**emr-5.36.2용 Spark 버전 정보**  

| Amazon EMR 릴리스 레이블 | Spark 버전 | Spark와 함께 설치된 구성 요소 | 
| --- | --- | --- | 
| emr-5.36.2 | Spark 2.4.8-amzn-2 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 

**Topics**
+ [Apache Spark가 설치된 클러스터 생성](emr-spark-launch.md)
+ [Amazon EMR 6.x에서 Docker를 사용하여 Spark 애플리케이션 실행](emr-spark-docker.md)
+ [Amazon EMR에서 Spark와 함께 AWS Glue 데이터 카탈로그 사용](emr-spark-glue.md)
+ [Amazon EMR에서 Spark를 사용하여 AWS Glue Data Catalog의 다중 카탈로그 계층 구조 작업](emr-multi-catalog.md)
+ [Spark 구성](emr-spark-configure.md)
+ [Amazon EMR용 Apache Spark 문제 해결 에이전트란?](spark-troubleshoot.md)
+ [Spark 성능 최적화](emr-spark-performance.md)
+ [Spark 결과 조각 캐싱](emr-spark-fragment-result-caching.md)
+ [Apache Spark용 Nvidia RAPIDS 액셀러레이터 사용](emr-spark-rapids.md)
+ [Spark 쉘에 액세스](emr-spark-shell.md)
+ [기계 학습에 Amazon SageMaker Spark 사용](emr-spark-sagemaker.md)
+ [Spark 애플리케이션 작성](emr-spark-application.md)
+ [Amazon S3를 사용하여 Spark 성능 개선](emr-spark-s3-performance.md)
+ [Spark 단계 추가](emr-spark-submit-step.md)
+ [Spark 애플리케이션 기록 보기](emr-spark-application-history.md)
+ [Spark 웹 UI에 액세스](emr-spark-webui.md)
+ [Spark 구조화된 스트리밍 Amazon Kinesis Data Streams 커넥터 사용](emr-spark-structured-streaming-kinesis.md)
+ [Amazon EMR에서 Apache Spark용 Amazon Redshift 통합 사용](emr-spark-redshift.md)
+ [Spark 릴리스 기록](Spark-release-history.md)
+ [Amazon EMR에서 구체화된 뷰 사용](emr-spark-materialized-views.md)

# Apache Spark가 설치된 클러스터 생성
<a name="emr-spark-launch"></a>

다음 절차에서는 Amazon EMR 콘솔에서 **고급 옵션**을 사용하여 설치된 [Spark](https://aws.amazon.com/big-data/what-is-spark/)로 클러스터를 생성합니다.

**고급 옵션**을 사용하여 클러스터 설정을 추가적으로 사용자 지정하고 단계를 제출하여 애플리케이션을 프로그래밍 방식으로 설치한 다음, 사용자 지정 애플리케이션을 실행할 수 있습니다. 클러스터 생성 옵션을 사용하여 AWS Glue를 Spark SQL 메타스토어로 사용하도록 선택할 수 있습니다. 자세한 정보는 [Amazon EMR에서 Spark와 함께 AWS Glue 데이터 카탈로그 사용](emr-spark-glue.md)을 참조하세요.

**Spark가 설치된 클러스터를 시작하려면**

1. [https://console.aws.amazon.com/emr](https://console.aws.amazon.com/emr/) Amazon EMR 콘솔을 엽니다.

1. **빠른 옵션**을 사용하려면 **클러스터 생성**을 선택합니다.

1. **클러스터 이름**을 입력합니다. 클러스터 이름에는 <, >, \$1, \$1 또는 `(백틱) 문자를 포함할 수 없습니다.

1.  **소프트웨어 구성**에서 **릴리스** 옵션을 선택합니다.

1.  **애플리케이션**에서 **Spark** 애플리케이션 번들을 선택합니다.

1.  필요에 따라 다른 옵션을 선택한 다음 **클러스터 생성**을 선택합니다.
**참고**  
클러스터를 생성할 때 Spark를 구성하려면 [Spark 구성](emr-spark-configure.md) 섹션을 참조하세요.

**를 사용하여 Spark가 설치된 클러스터를 시작하려면 AWS CLI**
+ 다음 명령을 사용하여 클러스터를 생성합니다.

  ```
  aws emr create-cluster --name "Spark cluster" --release-label emr-7.12.0 --applications Name=Spark \
  --ec2-attributes KeyName=myKey --instance-type m5.xlarge --instance-count 3 --use-default-roles
  ```

**참고**  
가독성을 위해 Linux 줄 연속 문자(\$1)가 포함됩니다. Linux 명령에 사용하거나 제외할 수 있습니다. Windows에서는 제외시키거나 캐럿(^)으로 바꿉니다.

**SDK for Java를 사용하여 Spark가 설치된 클러스터를 시작하는 방법**

`SupportedProductConfig`에 사용된 `RunJobFlowRequest`와 함께 Spark를 애플리케이션으로 지정합니다.
+ 다음은 Java를 사용하여 Spark가 설치된 클러스터를 생성하는 방법을 보여주는 예제입니다.

  ```
  import com.amazonaws.AmazonClientException;
  import com.amazonaws.auth.AWSCredentials;
  import com.amazonaws.auth.AWSStaticCredentialsProvider;
  import com.amazonaws.auth.profile.ProfileCredentialsProvider;
  import com.amazonaws.services.elasticmapreduce.AmazonElasticMapReduce;
  import com.amazonaws.services.elasticmapreduce.AmazonElasticMapReduceClientBuilder;
  import com.amazonaws.services.elasticmapreduce.model.*;
  import com.amazonaws.services.elasticmapreduce.util.StepFactory;
  
  public class Main {
  
          public static void main(String[] args) {
                  AWSCredentials credentials_profile = null;
                  try {
                          credentials_profile = new ProfileCredentialsProvider("default").getCredentials();
                  } catch (Exception e) {
                          throw new AmazonClientException(
                                          "Cannot load credentials from .aws/credentials file. " +
                                                          "Make sure that the credentials file exists and the profile name is specified within it.",
                                          e);
                  }
  
                  AmazonElasticMapReduce emr = AmazonElasticMapReduceClientBuilder.standard()
                                  .withCredentials(new AWSStaticCredentialsProvider(credentials_profile))
                                  .withRegion(Regions.US_WEST_1)
                                  .build();
  
                  // create a step to enable debugging in the AWS Management Console
                  StepFactory stepFactory = new StepFactory();
                  StepConfig enabledebugging = new StepConfig()
                                  .withName("Enable debugging")
                                  .withActionOnFailure("TERMINATE_JOB_FLOW")
                                  .withHadoopJarStep(stepFactory.newEnableDebuggingStep());
  
                  Application spark = new Application().withName("Spark");
  
                  RunJobFlowRequest request = new RunJobFlowRequest()
                                  .withName("Spark Cluster")
                                  .withReleaseLabel("emr-5.20.0")
                                  .withSteps(enabledebugging)
                                  .withApplications(spark)
                                  .withLogUri("s3://path/to/my/logs/")
                                  .withServiceRole("EMR_DefaultRole")
                                  .withJobFlowRole("EMR_EC2_DefaultRole")
                                  .withInstances(new JobFlowInstancesConfig()
                                                  .withEc2SubnetId("subnet-12ab3c45")
                                                  .withEc2KeyName("myEc2Key")
                                                  .withInstanceCount(3)
                                                  .withKeepJobFlowAliveWhenNoSteps(true)
                                                  .withMasterInstanceType("m4.large")
                                                  .withSlaveInstanceType("m4.large"));
                  RunJobFlowResult result = emr.runJobFlow(request);
                  System.out.println("The cluster ID is " + result.toString());
          }
  }
  ```

# Amazon EMR 6.x에서 Docker를 사용하여 Spark 애플리케이션 실행
<a name="emr-spark-docker"></a>

**참고**  
설명된 절차는 Amazon EMR 버전 6.x에서만 작동합니다.

Amazon EMR 6.0.0을 사용하는 경우 Spark 애플리케이션이 클러스터의 개별 Amazon EC2 인스턴스에 종속 항목을 설치하는 대신 Docker 컨테이너를 사용하여 라이브러리 종속 항목을 정의할 수 있습니다. 도커로 Spark를 실행하려면 먼저 도커 레지스트리를 구성하고 Spark 애플리케이션을 제출할 때 추가 파라미터를 정의해야 합니다. 자세한 내용은 [Docker 통합 구성](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-plan-docker.html)을 참조하세요.

애플리케이션이 제출되면 YARN이 도커를 호출하여 지정된 도커 이미지를 가져와서 도커 컨테이너 내에서 Spark 애플리케이션을 실행합니다. 이를 통해 종속 항목을 쉽게 정의하고 분리할 수 있습니다. 작업 실행에 필요한 라이브러리를 사용하여 Amazon EMR 클러스터에서 인스턴스를 부트스트랩하거나 준비하는 시간이 단축됩니다.

## Docker에서 Spark를 실행할 때의 고려 사항
<a name="emr-spark-docker-considerations"></a>

도커로 Spark를 실행하기 전에 다음 사전 요구 사항을 충족하는지 확인하세요.
+ `docker` 패키지와 CLI는 코어 및 작업 노드에만 설치해야 합니다.
+ Amazon EMR 6.1.0 이상에서는 다음 명령을 사용하여 프라이머리 노드에 Docker를 설치할 수도 있습니다.
  + 

    ```
    sudo yum install -y docker
    sudo systemctl start docker
    ```
+ `spark-submit` 명령은 항상 Amazon EMR 클러스터의 프라이머리 인스턴스에서 실행해야 합니다.
+ 클러스터를 시작할 때 추가 파라미터를 정의하는 `container-executor` 분류 키와 함께 분류 API를 사용하여 도커 이미지를 확인하는 데 사용되는 도커 레지스트리를 정의해야 합니다.
  + `docker.trusted.registries`
  + `docker.privileged-containers.registries`
+ 도커 컨테이너에서 Spark 애플리케이션을 실행하려면 다음 구성 옵션이 필요합니다.
  + `YARN_CONTAINER_RUNTIME_TYPE=docker`
  + `YARN_CONTAINER_RUNTIME_DOCKER_IMAGE={DOCKER_IMAGE_NAME}`
+ Amazon ECR을 사용하여 도커 이미지를 검색하는 경우 클러스터를 자체적으로 인증하도록 구성해야 합니다. 이렇게 하려면 다음 구성 옵션을 사용해야 합니다.
  + YARN\$1CONTAINER\$1RUNTIME\$1DOCKER\$1CLIENT\$1CONFIG=\$1DOCKER\$1CLIENT\$1CONFIG\$1PATH\$1ON\$1HDFS\$1
+ Amazon EMR 6.1.0 이상에서는 ECR 자동 인증 기능이 활성화된 경우 나열된 명령 `YARN_CONTAINER_RUNTIME_DOCKER_CLIENT_CONFIG={DOCKER_CLIENT_CONFIG_PATH_ON_HDFS}`를 사용할 필요가 없습니다.
+ Spark와 함께 사용되는 모든 도커 이미지에는 Java가 설치되어 있어야 합니다.

필수 조건에 대한 자세한 내용은 [Docker 통합 구성](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-plan-docker.html)을 참조하세요.

## 도커 이미지 생성
<a name="emr-spark-docker-image"></a>

도커 이미지는 이미지에 포함할 패키지와 구성을 정의하는 Dockerfile을 사용하여 생성됩니다. 다음 두 가지 예제 Dockerfile은 PySpark와 SparkR을 사용합니다.

**PySpark Dockerfile**

이 Dockerfile에서 생성된 도커 이미지에는 Python 3 및 NumPy Python 패키지가 포함되어 있습니다. 이 Dockerfile은 Amazon Linux 2와 Amazon Corretto JDK 8을 사용합니다.

```
FROM amazoncorretto:8

RUN yum -y update
RUN yum -y install yum-utils
RUN yum -y groupinstall development

RUN yum list python3*
RUN yum -y install python3 python3-dev python3-pip python3-virtualenv

RUN python -V
RUN python3 -V

ENV PYSPARK_DRIVER_PYTHON python3
ENV PYSPARK_PYTHON python3

RUN pip3 install --upgrade pip
RUN pip3 install numpy pandas

RUN python3 -c "import numpy as np"
```

**SparkR Dockerfile**

이 Dockerfile에서 생성된 도커 이미지에는 R 및 randomForest CRAN 패키지가 포함되어 있습니다. 이 Dockerfile은 Amazon Linux 2와 Amazon Corretto JDK 8을 사용합니다.

```
FROM amazoncorretto:8

RUN java -version

RUN yum -y update
RUN amazon-linux-extras install R4

RUN yum -y install curl hostname

#setup R configs
RUN echo "r <- getOption('repos'); r['CRAN'] <- 'http://cran.us.r-project.org'; options(repos = r);" > ~/.Rprofile

RUN Rscript -e "install.packages('randomForest')"
```

Dockerfile 구문에 대한 자세한 내용은 [Dockerfile 참조 설명서](https://docs.docker.com/engine/reference/builder/)를 참조하세요.

## Amazon ECR에서 도커 이미지 사용
<a name="emr-spark-docker-ECR"></a>

Amazon Elastic Container Registry(Amazon ECR)는 개발자가 Docker 컨테이너 이미지를 간편하게 저장, 관리 및 배포할 수 있게 해주는 완전관리형 Docker 컨테이너 레지스트리입니다. Amazon ECR을 사용하는 경우 ECR 인스턴스를 신뢰하도록 클러스터를 구성해야 하며 클러스터가 Amazon ECR의 도커 이미지를 사용할 수 있도록 인증을 구성해야 합니다. 자세한 내용은 [Amazon ECR에 액세스하도록 YARN 구성](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-plan-docker.html#emr-docker-ECR)을 참조하세요.

Amazon EMR 호스트가 Amazon ECR에 저장된 이미지에 액세스할 수 있도록 하려면 클러스터에 인스턴스 프로파일과 연결된 `AmazonEC2ContainerRegistryReadOnly` 정책의 권한이 있어야 합니다. 자세한 내용은 [`AmazonEC2ContainerRegistryReadOnly` 정책](https://docs.aws.amazon.com/AmazonECR/latest/userguide/ecr_managed_policies.html#AmazonEC2ContainerRegistryReadOnly)을 참조하세요.

이 예제에서는 Amazon ECR 레지스트리를 신뢰할 수 있도록 다음 추가 구성으로 클러스터를 생성해야 합니다. *123456789123.dkr.ecr.us-east-1.amazonaws.com* 엔드포인트를 Amazon ECR 엔드포인트로 바꿉니다.

```
[
  {
    "Classification": "container-executor",
    "Configurations": [
      {
        "Classification": "docker",
        "Properties": {
          "docker.privileged-containers.registries": "local,centos,123456789123.dkr.ecr.us-east-1.amazonaws.com",
          "docker.trusted.registries": "local,centos,123456789123.dkr.ecr.us-east-1.amazonaws.com"
        }
      }
    ],
    "Properties": {}
  }
]
```

**Amazon ECR과 함께 PySpark 사용**

다음 예제에서는 PySpark Dockerfile을 사용하며, 이 Dockerfile을 태그 지정하여 Amazon ECR에 업로드합니다. Dockerfile을 업로드한 후 PySpark 작업을 실행하고 Amazon ECR의 도커 이미지를 참조할 수 있습니다.

클러스터를 시작한 후 SSH를 사용하여 코어 노드에 연결하고 다음 명령을 실행하여 PySpark Dockerfile 예제의 로컬 도커 이미지를 빌드합니다.

먼저 디렉터리와 Dockerfile을 만듭니다.

```
mkdir pyspark
vi pyspark/Dockerfile
```

PySpark Dockerfile의 내용을 붙여 넣고 다음 명령을 실행하여 도커 이미지를 빌드합니다.

```
sudo docker build -t local/pyspark-example pyspark/
```

예제용 `emr-docker-examples` ECR 리포지토리를 생성합니다.

```
aws ecr create-repository --repository-name emr-docker-examples
```

로컬로 빌드한 이미지를 태그 지정하고 ECR에 업로드합니다. 이때 *123456789123.dkr.ecr.us-east-1.amazonaws.com*을 해당 ECR 엔드포인트로 대체합니다.

```
sudo docker tag local/pyspark-example 123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:pyspark-example
sudo docker push 123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:pyspark-example
```

SSH를 사용하여 프라이머리 노드에 연결하고 `main.py`라는 파일 이름으로 Python 스크립트를 준비합니다. 다음 내용을 `main.py` 파일에 붙여 넣고 저장합니다.

```
from pyspark.sql import SparkSession
spark = SparkSession.builder.appName("docker-numpy").getOrCreate()
sc = spark.sparkContext

import numpy as np
a = np.arange(15).reshape(3, 5)
print(a)
```

Amazon EMR 6.0.0에서 작업을 제출하려면 도커 이미지의 이름을 참조합니다. 추가 구성 파라미터를 정의하여 작업 실행에 Docker가 런타임으로 사용되도록 합니다. Amazon ECR을 사용하는 경우 `YARN_CONTAINER_RUNTIME_DOCKER_CLIENT_CONFIG`에서 Amazon ECR에 대한 인증에 사용되는 보안 인증이 포함된 `config.json` 파일을 참조해야 합니다.

```
DOCKER_IMAGE_NAME=123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:pyspark-example
DOCKER_CLIENT_CONFIG=hdfs:///user/hadoop/config.json
spark-submit --master yarn \
--deploy-mode cluster \
--conf spark.executorEnv.YARN_CONTAINER_RUNTIME_TYPE=docker \
--conf spark.executorEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=$DOCKER_IMAGE_NAME \
--conf spark.executorEnv.YARN_CONTAINER_RUNTIME_DOCKER_CLIENT_CONFIG=$DOCKER_CLIENT_CONFIG \
--conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_TYPE=docker \
--conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=$DOCKER_IMAGE_NAME \
--conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_DOCKER_CLIENT_CONFIG=$DOCKER_CLIENT_CONFIG \
--num-executors 2 \
main.py -v
```

Amazon EMR 6.1.0 이상에서 작업을 제출하려면 도커 이미지의 이름을 참조합니다. ECR 자동 인증이 활성화된 경우 다음 명령을 실행합니다.

```
DOCKER_IMAGE_NAME=123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:pyspark-example
spark-submit --master yarn \
--deploy-mode cluster \
--conf spark.executorEnv.YARN_CONTAINER_RUNTIME_TYPE=docker \
--conf spark.executorEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=$DOCKER_IMAGE_NAME \
--conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_TYPE=docker \
--conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=$DOCKER_IMAGE_NAME \
--num-executors 2 \
main.py -v
```

작업이 완료되면 YARN 애플리케이션 ID를 기록하고 다음 명령을 사용하여 PySpark 작업의 출력을 얻습니다.

```
yarn logs --applicationId application_id | grep -C2 '\[\['
LogLength:55
LogContents:
[[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]]
```

**Amazon ECR과 함께 SparkR 사용**

다음 예제에서는 SparkR Dockerfile을 사용하며, 이 Dockerfile을 태그 지정하여 ECR에 업로드합니다. Dockerfile이 업로드된 후 SparkR 작업을 실행하고 Amazon ECR의 도커 이미지를 참조할 수 있습니다.

클러스터를 시작한 후 SSH를 사용하여 코어 노드에 연결하고 다음 명령을 실행하여 SparkR Dockerfile 예제의 로컬 Docker 이미지를 빌드합니다.

먼저 디렉터리와 Dockerfile을 만듭니다.

```
mkdir sparkr
vi sparkr/Dockerfile
```

SparkR Dockerfile의 내용을 붙여 넣고 다음 명령을 실행하여 도커 이미지를 빌드합니다.

```
sudo docker build -t local/sparkr-example sparkr/
```

로컬로 빌드한 이미지를 태그 지정하고 Amazon ECR에 업로드합니다. 이때 *123456789123.dkr.ecr.us-east-1.amazonaws.com*을 해당 Amazon ECR 엔드포인트로 대체합니다.

```
sudo docker tag local/sparkr-example 123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:sparkr-example
sudo docker push 123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:sparkr-example
```

SSH를 사용하여 프라이머리 노드에 연결하고 `sparkR.R`이라는 이름으로 R 스크립트를 준비합니다. 다음 내용을 `sparkR.R` 파일에 붙여 넣습니다.

```
library(SparkR)
sparkR.session(appName = "R with Spark example", sparkConfig = list(spark.some.config.option = "some-value"))

sqlContext <- sparkRSQL.init(spark.sparkContext)
library(randomForest)
# check release notes of randomForest
rfNews()

sparkR.session.stop()
```

Amazon EMR 6.0.0에서 작업을 제출하려면 도커 이미지의 이름을 참조합니다. 추가 구성 파라미터를 정의하여 작업 실행에 Docker가 런타임으로 사용되도록 합니다. Amazon ECR을 사용하는 경우 `YARN_CONTAINER_RUNTIME_DOCKER_CLIENT_CONFIG`에서 ECR에 대한 인증에 사용되는 보안 인증이 포함된 `config.json` 파일을 참조해야 합니다.

```
DOCKER_IMAGE_NAME=123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:sparkr-example
DOCKER_CLIENT_CONFIG=hdfs:///user/hadoop/config.json
spark-submit --master yarn \
--deploy-mode cluster \
--conf spark.executorEnv.YARN_CONTAINER_RUNTIME_TYPE=docker \
--conf spark.executorEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=$DOCKER_IMAGE_NAME \
--conf spark.executorEnv.YARN_CONTAINER_RUNTIME_DOCKER_CLIENT_CONFIG=$DOCKER_CLIENT_CONFIG \
--conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_TYPE=docker \
--conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=$DOCKER_IMAGE_NAME \
--conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_DOCKER_CLIENT_CONFIG=$DOCKER_CLIENT_CONFIG \
sparkR.R
```

Amazon EMR 6.1.0 이상에서 작업을 제출하려면 도커 이미지의 이름을 참조합니다. ECR 자동 인증이 활성화된 경우 다음 명령을 실행합니다.

```
DOCKER_IMAGE_NAME=123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:sparkr-example
spark-submit --master yarn \
--deploy-mode cluster \
--conf spark.executorEnv.YARN_CONTAINER_RUNTIME_TYPE=docker \
--conf spark.executorEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=$DOCKER_IMAGE_NAME \
--conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_TYPE=docker \
--conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=$DOCKER_IMAGE_NAME \
sparkR.R
```

작업이 완료되면 YARN 애플리케이션 ID를 기록하고 다음 명령을 사용하여 SparkR 작업의 출력을 얻습니다. 이 예제에는 RandomForest 라이브러리, 설치된 버전 및 릴리스 정보를 사용할 수 있는지 확인하는 테스트가 포함되어 있습니다.

```
yarn logs --applicationId application_id | grep -B4 -A10 "Type rfNews"
randomForest 4.6-14
Type rfNews() to see new features/changes/bug fixes.
Wishlist (formerly TODO):

* Implement the new scheme of handling classwt in classification.

* Use more compact storage of proximity matrix.

* Allow case weights by using the weights in sampling?

========================================================================
Changes in 4.6-14:
```

# Amazon EMR에서 Spark와 함께 AWS Glue 데이터 카탈로그 사용
<a name="emr-spark-glue"></a>

Amazon EMR 릴리스 5.8.0 이상을 사용하면 Glue 데이터 카탈로그를 Apache Hive AWS 메타스토어로 사용하도록 Spark를 구성할 수 있습니다. 영구 Hive 메타스토어 또는 다른 클러스터, 서비스, 애플리케이션 또는 AWS 계정에서 공유하는 Hive 메타스토어가 필요한 경우이 구성을 사용하는 것이 좋습니다.

Amazon EMR 릴리스 6.5.0 이상을 사용하면 Apache Iceberg와 함께 AWS Glue 데이터 카탈로그를 사용하도록 Spark를 구성할 수 있습니다.

Amazon EMR 릴리스 7.5.0 이상을 사용하면 AWS Glue 데이터 카탈로그를 Iceberg REST 카탈로그로 사용하도록 Spark를 구성할 수 있습니다.

AWS Glue는 완전 관리형 ETL(추출, 변환 및 로드) 서비스로, 데이터를 분류하고 정리하고 보강하고 다양한 데이터 스토어 간에 안정적으로 이동할 수 있는 간단하고 비용 효율적입니다. Glue 데이터 카탈로그는 Amazon EMR뿐만 아니라 Amazon RDS, Amazon Redshift, Redshift Spectrum, Athena 및 Apache Hive AWS 메타스토어와 호환되는 모든 애플리케이션과 통합하여 다양한 데이터 소스 및 데이터 형식에 걸쳐 통합된 메타데이터 리포지토리를 제공합니다. AWS Glue 크롤러는 Amazon S3의 소스 데이터에서 스키마를 자동으로 추론하고 데이터 카탈로그에 연결된 메타데이터를 저장할 수 있습니다. 데이터 카탈로그에 대한 자세한 내용은 [AWS Glue 개발자 안내서의 Glue 데이터 카탈로그 채우기를](https://docs.aws.amazon.com/glue/latest/dg/populate-data-catalog.html) 참조하세요. *AWS * 

 AWS Glue에는 별도의 요금이 적용됩니다. 데이터 카탈로그의 메타데이터 저장 및 액세스에 대한 월별 요금, Glue ETL 작업 및 AWS 크롤러 런타임에 대해 분당 청구되는 시간당 요금, 프로비저닝된 각 개발 엔드포인트에 대해 분당 청구되는 시간당 요금이 있습니다. 데이터 카탈로그에는 최대 100만 개의 객체를 무료로 저장할 수 있습니다. 100만 개 이상의 객체를 저장하는 경우, 100만 이상의 객체 100,000개마다 1USD가 부과됩니다. 데이터 카탈로그의 객체로는 테이블, 파티션 또는 데이터베이스가 있습니다. 자세한 내용은 [Glue 요금](https://aws.amazon.com/glue/pricing)을 참조하세요.

**중요**  
2017년 8월 14일 이전에 Amazon Athena 또는 Amazon Redshift Spectrum을 사용하여 테이블을 생성한 경우 데이터베이스 및 테이블은 AWS Glue 데이터 카탈로그와 별도의 Athena 관리형 카탈로그에 저장됩니다. Amazon EMR을 이러한 테이블과 통합하려면 AWS Glue 데이터 카탈로그로 업그레이드해야 합니다. 자세한 내용은 *Amazon Athena 사용 설명서*[의 AWS Glue 데이터 카탈로그로 업그레이드를](https://docs.aws.amazon.com/athena/latest/ug/glue-upgrade.html) 참조하세요.

## Glue 데이터 카탈로그를 Apache Hive AWS 메타스토어로 지정
<a name="emr-spark-glue-configure"></a>

 AWS Management Console AWS CLI또는 Amazon EMR API를 사용하여 AWS Glue 데이터 카탈로그를 메타스토어로 지정할 수 있습니다. CLI 또는 API를 사용할 때 Spark에 대한 구성 분류를 사용하여 데이터 카탈로그를 지정합니다. 또한 Amazon EMR 5.16.0 이상에서는 구성 분류를 사용하여 다른에서 데이터 카탈로그를 지정할 수 있습니다 AWS 계정. 콘솔을 사용할 때 **고급 옵션** 또는 **빠른 옵션**을 사용하여 데이터 카탈로그를 지정할 수 있습니다.

**참고**  
Zeppelin은 Spark 구성 요소와 함께 설치되므로 AWS Glue 데이터 카탈로그를 사용하는 옵션도 Zeppelin에서 사용할 수 있습니다.

------
#### [ Console ]

**새 콘솔을 사용하여 AWS Glue 데이터 카탈로그를 Apache Hive 메타스토어로 지정하려면**

1. 에 로그인 AWS Management Console하고 [https://console.aws.amazon.com/emr](https://console.aws.amazon.com/emr) Amazon EMR 콘솔을 엽니다.

1. 왼쪽 탐색 창의 **Amazon EMR on EC2**에서 **클러스터**를 선택하고 **클러스터 생성**을 선택합니다.

1. **애플리케이션 번들**에서 **Spark** 또는 **사용자 지정**을 선택합니다. 클러스터를 사용자 지정하는 경우 Zeppelin 또는 Spark를 애플리케이션 중 하나로 선택해야 합니다.

1. **AWS Glue Data Catalog 설정**에서 **Spark 테이블 메타데이터에 사용** 확인란을 선택합니다.

1. 클러스터에 적용할 다른 옵션을 선택합니다.

1. 클러스터를 시작하려면 **클러스터 생성**을 선택합니다.

------
#### [ AWS CLI ]

**를 사용하여 AWS Glue 데이터 카탈로그를 Apache Hive 메타스토어로 지정하려면 AWS CLI**

 AWS CLI 및 Amazon EMR API를 사용하여 구성 분류를 지정하는 방법에 대한 자세한 내용은 섹션을 참조하세요[애플리케이션 구성](emr-configure-apps.md).
+ 다음 예에서 나온 것처럼 `spark-hive-site` 분류를 사용하여 `hive.metastore.client.factory.class`에 대한 값을 지정합니다.

  ```
  [
    {
      "Classification": "spark-hive-site",
      "Properties": {
        "hive.metastore.client.factory.class": "com.amazonaws.glue.catalog.metastore.AWSGlueDataCatalogHiveClientFactory"
      }
    }
  ]
  ```

  다른 AWS 계정에서 데이터 카탈로그를 지정하려면 다음 예제와 같이 `hive.metastore.glue.catalogid` 속성을 추가합니다. `acct-id`를 데이터 카탈로그의 AWS 계정으로 바꿉니다.

  ```
  [
    {
      "Classification": "spark-hive-site",
      "Properties": {
        "hive.metastore.client.factory.class": "com.amazonaws.glue.catalog.metastore.AWSGlueDataCatalogHiveClientFactory",
        "hive.metastore.glue.catalogid": "acct-id"
      }
    }
  ]
  ```

------

## AWS Glue 데이터 카탈로그를 Apache Iceberg 카탈로그로 지정
<a name="emr-spark-glue-configure-iceberg"></a>

 AWS 또는 AWS Management Console AWS CLI Amazon EMR API를 사용하거나 Spark 세션 런타임 구성에서 Glue 데이터 카탈로그를 Apache Iceberg 카탈로그 구현 또는 Apache Iceberg REST 카탈로그 엔드포인트로 지정할 수 있습니다. CLI 또는 API를 사용할 때 Spark에 대한 구성 분류를 사용하여 데이터 카탈로그를 지정합니다. 자세한 내용은 [AWS Glue 데이터 카탈로그를 Apache Iceberg 카탈로그로 지정을](https://docs.aws.amazon.com/emr/latest/ReleaseGuide/emr-spark-glue.html#emr-spark-glue-configure-iceberg) 참조하세요.

## IAM 권한
<a name="emr-hive-glue-permissions"></a>

클러스터의 EC2 인스턴스 프로파일에는 AWS Glue 작업에 대한 IAM 권한이 있어야 합니다. 또한 AWS Glue Data Catalog 객체에 대한 암호화를 활성화하는 경우 역할은 암호화에 AWS KMS key 사용되는를 암호화, 복호화 및 생성할 수 있어야 합니다.

### AWS Glue 작업에 대한 권한
<a name="emr-hive-glue-permissions-actions"></a>

Amazon EMR에 대한 기본 EC2 인스턴스 프로파일을 사용할 경우 어떤 작업도 필요하지 않습니다. 에 연결된 `AmazonElasticMapReduceforEC2Role` 관리형 정책은 필요한 모든 AWS Glue 작업을 `EMR_EC2_DefaultRole` 허용합니다. 그러나 사용자 지정 EC2 인스턴스 프로파일 및 권한을 지정하는 경우 적절한 AWS Glue 작업을 구성해야 합니다. `AmazonElasticMapReduceforEC2Role` 관리형 정책을 시작점으로 사용합니다. 자세한 내용은 *Amazon EMR 관리 안내서*에서 [클러스터 EC2 인스턴스의 서비스 역할(EC2 인스턴스 프로파일)](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-iam-role-for-ec2.html)을 참조하세요.

### AWS Glue 데이터 카탈로그 암호화 및 복호화 권한
<a name="emr-hive-glue-permissions-encrypt"></a>

인스턴스 프로파일에 키를 사용하여 데이터를 암호화하고 복호화할 수 있는 권한이 필요합니다. 다음 두 설명이 모두 적용되는 경우에는 이러한 권한을 구성할 필요가 *없습니다*.
+  AWS Glue용 관리형 키를 사용하여 AWS Glue Data Catalog 객체에 대한 암호화를 활성화합니다.
+ Glue 데이터 카탈로그 AWS 계정 와 동일한 AWS 에 있는 클러스터를 사용합니다.

그렇지 않으면 EC2 인스턴스 프로파일에 연결된 권한 정책에 다음 명령을 추가해야 합니다.

Glue 데이터 카탈로그 암호화에 대한 자세한 내용은 AWS *AWS Glue 개발자 안내서*의 [데이터 카탈로그 암호화를 참조하세요](https://docs.aws.amazon.com/glue/latest/dg/encrypt-glue-data-catalog.html).

### 리소스 기반 권한
<a name="emr-hive-glue-permissions-resource"></a>

Amazon EMR에서 AWS Glue를 Hive, Spark 또는 Presto와 함께 사용하는 경우 AWS Glue는 리소스 기반 정책을 지원하여 데이터 카탈로그 리소스에 대한 액세스를 제어합니다. 이러한 리소스에는 데이터베이스, 테이블, 연결 및 사용자 정의 기능이 포함됩니다. 자세한 내용은 *AWS Glue 개발자 안내서*에서 [AWS Glue 리소스 정책](https://docs.aws.amazon.com/glue/latest/dg/glue-resource-policies.html)을 참조하세요.

리소스 기반 정책을 사용하여 Amazon EMR 내에서 AWS Glue에 대한 액세스를 제한하는 경우 권한 정책에서 지정하는 보안 주체는 클러스터 생성 시 지정된 EC2 인스턴스 프로파일과 연결된 역할 ARN이어야 합니다. 예를 들어, 카탈로그에 연결된 리소스 기반 정책의 경우 다음 예에 표시된 형식을 사용하여 클러스터 EC2 인스턴스에 대한 기본 서비스 역할의 ARN(*EMR\$1EC2\$1DefaultRole*)을 `Principal`로 지정할 수 있습니다.

```
arn:aws:iam::acct-id:role/EMR_EC2_DefaultRole
```

*acct-id*는 AWS Glue 계정 ID와 다를 수 있습니다. 그러면 다른 계정의 EMR 클러스터에서 액세스할 수 있습니다. 각각 다른 계정에서 여러 보안 주체를 지정할 수 있습니다.

## AWS Glue 데이터 카탈로그 사용 시 고려 사항
<a name="emr-hive-glue-considerations-hive"></a>

Glue Data Catalog를 Spark에서 Apache Hive AWS 메타스토어로 사용할 때는 다음 항목을 고려하세요.
+ 테이블을 생성할 때 위치 URI 없이 기본 데이터베이스를 지정하면 오류가 발생합니다. 차선책으로 `LOCATION`을 사용할 때 `s3://amzn-s3-demo-bucket1` 절을 사용하여 버킷 위치를 지정합니다(예: `CREATE TABLE`). 또는 기본 데이터베이스가 아닌 데이터베이스에서 테이블을 생성합니다.
+  AWS Glue 내에서 테이블 이름을 바꾸는 것은 지원되지 않습니다.
+ `LOCATION`을 지정하지 않고 Hive 테이블을 생성하면 테이블 데이터가 `hive.metastore.warehouse.dir` 속성을 통해 지정된 위치에 저장됩니다. 기본적으로 HDFS에 있는 위치입니다. 다른 클러스터가 테이블에 액세스해야 하는 경우, 테이블을 생성한 클러스터에 대한 적절한 권한이 없으면 실패합니다. 또한 HDFS 스토리지는 일시적이기 때문에, 클러스터가 종료되는 경우 테이블 데이터가 손실되고 테이블을 다시 생성해야 합니다. Glue를 사용하여 Hive 테이블을 생성할 때 Amazon S3`LOCATION`에서 AWS 를 지정하는 것이 좋습니다. 또는 `hive-site` 구성 분류를 사용하여 모든 Hive 테이블에 적용되는 Amazon S3에서 `hive.metastore.warehouse.dir`에 대한 위치를 지정할 수도 있습니다. HDFS 위치에 테이블이 생성되고 테이블을 생성한 클러스터가 여전히 실행 중인 경우 AWS Glue 내에서 테이블 위치를 Amazon S3로 업데이트할 수 있습니다. 자세한 내용은 [Glue 개발자 안내서의 AWS Glue 콘솔에서 테이블 작업을 참조하세요](https://docs.aws.amazon.com/glue/latest/dg/console-tables.html). *AWS * 
+ 따옴표와 아포스트로피가 포함된 파티션 값은 지원되지 않습니다(예: `PARTITION (owner="Doe's").`).
+ [열 통계](https://cwiki.apache.org/confluence/display/Hive/StatsDev#StatsDev-ColumnStatistics)는 emr-5.31.0 이상에서 지원됩니다.
+ [Hive 권한 부여](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Authorization) 사용은 지원되지 않습니다. 대안으로 [AWS Glue 리소스 기반 정책](https://docs.aws.amazon.com/glue/latest/dg/glue-resource-policies.html) 사용을 고려합니다. 자세한 내용은 [AWS Glue 데이터 카탈로그에 대한 Amazon EMR 액세스를 위한 리소스 기반 정책 사용을 참조하세요](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-iam-roles-glue.html).

Spark에서 AWS Glue 데이터 카탈로그를 Apache Iceberg REST 카탈로그로 사용할 때는 다음 사항을 고려하세요.
+ 에 설명된 Iceberg와 함께 Spark 세션 카탈로그를 사용하는 경우 [Iceberg SparkCatalog를 사용할 때와 SparkSessionCatalog를 사용할 때의 구성 차이](emr-iceberg-use-spark-cluster.md#emr-iceberg-spark-catalog) AWS Glue Data Catalog를 Apache Iceberg REST 카탈로그로 구성하는 것 외에도 Glue Data Catalog를 Apache Hive AWS 메타스토어로 구성합니다.
+  AWS Glue Data Catalog IRC 엔드포인트는 Amazon SigV4 인증 체계만 지원합니다. OAuth는 지원되지 않습니다. OAuth 사용자의 경우 IAM Identity Center를 사용하여 액세스를 구성하세요. [Lake Formation과 IAM Identity Center 연결](https://docs.aws.amazon.com/lake-formation/latest/dg/connect-lf-identity-center.html)을 참조하세요.
+  AWS Glue Iceberg REST 카탈로그는 오픈 소스의 모든 작업을 지원하지 않습니다.

# Amazon EMR에서 Spark를 사용하여 AWS Glue Data Catalog의 다중 카탈로그 계층 구조 작업
<a name="emr-multi-catalog"></a>

Amazon EMR 클러스터를 등록하여 AWS Glue Data Catalog에 액세스할 수 있습니다. 그러면 테이블 및 기타 카탈로그 리소스를 다양한 소비자가 사용할 수 있습니다. AWS Glue Data Catalog는 Amazon S3 데이터 레이크에서 데이터를 통합하는 다중 카탈로그 계층 구조를 지원합니다. 또한 데이터에 액세스하기 위한 Hive 메타스토어 API와 오픈 소스 Apache Iceberg REST API를 모두 제공합니다. 이러한 기능은 Amazon EMR 및 기타 서비스(예: Amazon Athena , Amazon Redshift)에서 사용할 수 있습니다.

## 카탈로그 리소스 구성 방법
<a name="emr-lakehouse-org"></a>

Glue 데이터 카탈로그에서 리소스를 생성할 때 Apache Iceberg REST API 또는 Hive AWS 메타스토어를 지원하는 모든 SQL 엔진에서 리소스에 액세스할 수 있습니다. AWS Lake Formation은 권한을 관리합니다.

 AWS Glue Data Catalog에서 데이터는 카탈로그, 데이터베이스 및 테이블의 논리적 계층 구조로 구성됩니다.
+ **카탈로그** - 스키마 또는 테이블과 같은 데이터 스토어의 객체를 유지하는 논리적 컨테이너입니다.
+ **RMS(Redshift Managed Storage) 테이블을 저장하는 카탈로그 **- 카탈로그를 관리하여 RMS 테이블을 저장하는 경우 Iceberg를 사용하여 이러한 테이블에 액세스할 수 있습니다.
+ **데이터베이스** - 카탈로그의 테이블 및 뷰와 같은 데이터 객체를 구성합니다.
+ **테이블 및 뷰** - 이해하기 쉬운 스키마를 사용하여 추상화 계층을 제공하는 데이터베이스의 데이터 객체입니다. 다양한 형식과 다양한 위치에 있을 수 있는 기본 데이터에 액세스할 수 있는 계층을 제공합니다.



## Amazon EMR과 함께 사용할 Data Catalog 구성
<a name="emr-lakehouse-configuration"></a>

시작하려면 Amazon EMR 도구를 지원하도록 카탈로그를 구성합니다. AWS Glue 데이터 카탈로그는 Hive 메타스토어 호환성과 Iceberg REST 호환 APIs 제공합니다.

**Hive 메타스토어를 사용하여 Amazon EMR 구성**

 이를 설정하는 방법에 대한 자세한 내용은 [AWS Glue 사용 설명서의 Spark 작업에 대한 Glue 데이터 카탈로그 지원을](https://docs.aws.amazon.com/glue/latest/dg/aws-glue-programming-etl-glue-data-catalog-hive.html) 참조하세요. AWS 이 주제에서는 AWS Glue 데이터 카탈로그를 Hive 메타스토어로 구성하고 엔드포인트로 사용할 수 있도록 하는 방법을 설명합니다. 또한 Glue 데이터 카탈로그를 Spark AWS 용 [Apache Hive 메타스토어로 사용에서 Glue 데이터 카탈로그를 Spark AWS 메타스토어로](https://docs.aws.amazon.com/emr/latest/ReleaseGuide/emr-spark-glue.html) 지정하는 방법을 보여주는 Amazon EMR 설명서가 제공됩니다.

## AWS Glue 데이터 카탈로그의 리소스에 액세스하기 위한 권한
<a name="emr-lakehouse-using-irc-prereqs"></a>

이 섹션에서는 카탈로그 데이터와 함께 Amazon EMR 도구를 사용하기 위한 IAM 정책 요구 사항을 설명합니다. 클러스터를 AWS Glue 데이터 카탈로그에 등록한 후 이후에 생성된 데이터 카탈로그의 생성 및 변경 사항을 검색하려면 다음 권한이 필요합니다.
+ **glue:GetCatalog**
+ **glue:GetCatalogs**
+ **sts:AssumeRole**
+ **sts:TagSession**
+ **sts:SetContext**
+ **sts:SetSourceIdentity**

대부분의 경우 권한을 할당할 때 IAM 역할을 생성하고 해당 역할에 권한을 할당하는 것이 좋습니다.

카탈로그를 쿼리하려면 먼저 AWS Lake Formation을 사용하여 카탈로그에 대한 권한을 설정합니다. AWS Lake Formation에서 데이터 카탈로그에 대한 권한을 설정하는 방법에 대한 자세한 내용은 [데이터 카탈로그 리소스에 대한 권한 부여 및 취소](https://docs.aws.amazon.com/lake-formation/latest/dg/granting-catalog-permissions.html)를 참조하세요.

클러스터를 생성 및 구성하고 카탈로그 객체에 대한 권한을 설정한 후 작업을 제출하여 데이터를 쿼리하고 처리할 수 있습니다.

## AWS Glue 데이터 카탈로그의 다중 카탈로그 계층 구조에 액세스하도록 Spark 구성
<a name="emr-lakehouse-using-spark-access"></a>

EMR 7.5를 사용하면 AWS Glue의 다중 카탈로그 계층 구조를 사용하도록 Spark를 구성할 수 있습니다. 다중 카탈로그 계층 구조를 사용하면 다음을 수행할 수 있습니다.
+ 기존 Amazon Redshift 데이터 웨어하우스의 테이블, 뷰 및 구체화된 뷰와 같은 Redshift Managed Storage(RMS) 데이터를 AWS Glue Data Catalog로 가져옵니다. EMR on EC2 및 EMR Serverless를 사용하여 이러한 객체를 쿼리할 수 있습니다.
+ RMS 카탈로그, AWS Glue 데이터 카탈로그를 생성하고 ZeroETL을 사용하여 RMS에 데이터를 저장하고 Iceberg 호환 쿼리 엔진을 사용하여 데이터를 쿼리합니다.
+ 압축, 스냅샷 및 보존을 포함하는 모든 기능을 갖춘 스토리지 관리를 사용하여 AWS Glue Data Catalog에서 관리형 Iceberg 테이블을 생성합니다.

### Spark 세션을 초기화할 때 다중 카탈로그에 연결
<a name="emr-iceberg-initialize-spark-session-spark"></a>

다음 예제에서는 대화형 Spark 셸, Spark 제출 또는 Amazon EMR 노트북을 사용하여 AWS Glue의 다중 카탈로그 계층 구조로 작업하는 방법을 보여줍니다.

------
#### [ spark-shell ]

1. SSH를 사용하여 마스터 노드에 연결합니다. 자세한 내용은 *Amazon EMR 관리 안내서*에서 [SSH를 사용하여 프라이머리 노드에 연결](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-connect-master-node-ssh.html)을 참조하세요.

1. Spark 셸을 시작하려면 다음 명령을 입력합니다. PySpark 쉘을 사용하려면 `spark-shell`을 `pyspark`로 바꿉니다.

   ```
   spark-shell \
       --conf spark.sql.catalog.my_catalog=org.apache.iceberg.spark.SparkCatalog \
       --conf spark.sql.catalog.my_catalog.warehouse=s3://amzn-s3-demo-bucket/prefix/
       --conf spark.sql.catalog.my_catalog.type=glue \
       --conf spark.sql.catalog.my_catalog.glue.id=Glue RMS catalog ID \
       --conf spark.sql.defaultCatalog=my_catalog \
       --conf spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions
   ```

------
#### [ spark-submit ]

1. SSH를 사용하여 마스터 노드에 연결합니다. 자세한 내용은 *Amazon EMR 관리 안내서*에서 [SSH를 사용하여 프라이머리 노드에 연결](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-connect-master-node-ssh.html)을 참조하세요.

1. Spark용 Spark 세션을 시작하려면 다음 명령을 입력합니다.

   ```
   spark-submit \
   --conf spark.sql.catalog.my_catalog=org.apache.iceberg.spark.SparkCatalog \
   --conf spark.sql.catalog.my_catalog.warehouse=s3://amzn-s3-demo-bucket1/prefix \
   --conf spark.sql.catalog.my_catalog.type=glue \
   --conf spark.sql.catalog.my_catalog.glue.id=Glue RMS catalog ID \
   --conf spark.sql.defaultCatalog=my_catalog \
   --conf spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions
   ```

------
#### [ EMR Studio notebooks ]

EMR Studio 노트북을 사용하여 Spark 세션을 초기화하려면 다음 예제와 같이 Amazon EMR Notebooks에서 `%%configure` 매직 명령을 사용하여 Spark 세션을 구성합니다. 자세한 내용은 *Amazon EMR 관리 안내서*에서 [EMR Notebooks 매직 사용](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-studio-magics.html#emr-magics)을 참조하세요.

```
%%configure -f{
"conf":{
    "spark.sql.catalog.my_catalog":"org.apache.iceberg.spark.SparkCatalog",
    "spark.sql.catalog.my_catalog.type":"glue",
    "spark.sql.catalog.my_catalog.glue.id":"Glue RMS catalog ID",
    "spark.sql.catalog.my_catalog.warehouse":"s3://amzn-s3-demo-bucket1/prefix/",
    "spark.sql.defaultCatalog", "my_catalog",
    "spark.sql.extensions":"org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions"
    }
}
```

------
#### [ CLI ]

CLI를 사용하여 Spark 세션을 초기화하려면 다음 샘플을 실행합니다. AWS CLI 및 Amazon EMR API를 사용하여 구성 분류를 지정하는 방법에 대한 자세한 내용은 [애플리케이션 구성을](https://docs.aws.amazon.com/emr/latest/ReleaseGuide/emr-configure-apps.html) 참조하세요.

```
[
  {
    "Classification": "spark-defaults",
    "Properties": {
      "spark.sql.catalog.my_catalog":"org.apache.iceberg.spark.SparkCatalog",
      "spark.sql.catalog.my_catalog.type":"glue",
      "spark.sql.catalog.my_catalog.glue.id":"Glue RMS catalog ID",
      "spark.sql.catalog.my_catalog.warehouse":"s3://amzn-s3-demo-bucket1/prefix/",
      "spark.sql.defaultCatalog", "my_catalog",
      "spark.sql.extensions":"org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions"
    }
  }
]
```

------

#### AWS Glue 데이터 카탈로그를 사용하여 Redshift 관리형 스토리지로 Spark 세션 초기화
<a name="considerations-multi-catalog-glue-connect"></a>

다음 샘플 명령은 AWS Glue Data Catalog를 사용하여 Spark 세션을 초기화합니다.

```
spark-sql \
  --conf spark.sql.catalog.rms=org.apache.iceberg.spark.SparkCatalog \
  --conf spark.sql.catalog.rms.type=glue \
  --conf spark.sql.catalog.rms.glue.id=Glue RMS catalog ID \
  --conf spark.sql.defaultCatalog=rms
  --conf spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions
```

다음 샘플은 Iceberg REST API 및 Redshift Managed Storage with AWS Glue Data Catalog를 사용하여 Spark 세션을 초기화합니다.

```
spark-sql \
  --conf spark.sql.catalog.rms=org.apache.iceberg.spark.SparkCatalog \
  --conf spark.sql.catalog.rms.type=rest \
  --conf spark.sql.catalog.rms.warehouse=glue RMS catalog ID \
  --conf spark.sql.catalog.rms.uri=Glue endpoint URI/iceberg \
  --conf spark.sql.catalog.rms.rest.sigv4-enabled=true \
  --conf spark.sql.catalog.rms.rest.signing-name=glue \
  --conf spark.sql.defaultCatalog=rms \
  --conf spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions
```

Spark Iceberg에서 AWS Glue 다중 카탈로그 계층 구조를 사용하는 방법에 대한 자세한 내용은 [Spark에서 Iceberg 클러스터 사용을 참조하세요](https://docs.aws.amazon.com/emr/latest/ReleaseGuide/emr-iceberg-use-spark-cluster.html).

## 다중 카탈로그 구성에 대한 고려 사항 및 제한 사항
<a name="considerations-multi-catalog"></a>
+ Apache Hive 메타스토어와 함께 다중 카탈로그 계층 구조를 사용하는 것은 지원되지 않습니다.
+ Apache Iceberg와 함께 다중 카탈로그 계층 구조를 사용하면 `SparkSessionCatalog`를 사용할 때 Apache Hive 메타스토어로의 대체를 지원할 수 없습니다.
+ 런타임 역할이 있는 EMR on EC2 클러스터는 다중 카탈로그 계층 구조를 지원하지 않습니다.
+ 에서 활성화된 EMR on EC2 클러스터는 다중 카탈로그 계층 구조를 지원하지 AWS Lake Formation 않습니다.

# Spark 구성
<a name="emr-spark-configure"></a>

구성 분류를 사용하여 [Spark on Amazon EMR](https://aws.amazon.com/elasticmapreduce/details/spark/)을 구성할 수 있습니다. 구성 분류에 대한 자세한 내용은 [애플리케이션 구성](emr-configure-apps.md) 섹션을 참조하세요.

Amazon EMR에서 Spark에 대한 구성 분류에는 다음이 포함됩니다.
+ **`spark`** - `maximizeResourceAllocation` 속성을 true 또는 false로 설정합니다. true로 설정하면, Amazon EMR에서 클러스터 하드웨어 구성을 기반으로 `spark-defaults` 속성을 자동으로 구성합니다. 자세한 내용은 [`maximizeResourceAllocation` 사용하기](#emr-spark-maximizeresourceallocation) 단원을 참조하십시오.
+ **`spark-defaults`** - `spark-defaults.conf` 파일에서 값을 설정합니다. 자세한 내용은 Spark 설명서에서 [Spark configuration](https://spark.apache.org/docs/latest/configuration.html)을 참조하세요.
+ **`spark-env`** - `spark-env.sh` 파일에서 값을 설정합니다. 자세한 내용은 Spark 설명서에서 [Environment variables](https://spark.apache.org/docs/latest/configuration.html#environment-variables)를 참조하세요.
+ **`spark-hive-site`** - `hive-site.xml`에 Spark에 대한 값을 설정합니다.
+ **`spark-log4j`** - (Amazon EMR 릴리스 6.7.x 이하) `log4j.properties` 파일에서 값을 설정합니다. 자세한 내용은 Github에서 [log4j.properties.template](https://github.com/apache/spark/blob/branch-3.2/conf/log4j.properties.template) 파일을 참조하세요.
+ **`spark-log4j2`** - (Amazon EMR 릴리스 6.8.0 이상) `log4j2.properties` 파일에서 값을 설정합니다. 자세한 내용은 Github에서 [log4j2.properties.template](https://github.com/apache/spark/blob/v3.3.0/conf/log4j2.properties.template) 파일을 참조하세요.
+ **`spark-metrics`** - `metrics.properties` 파일에서 값을 설정합니다. 설정 및 자세한 내용은 Github의 [metrics.properties.template](https://github.com/apache/spark/blob/master/conf/metrics.properties.template) 파일 및 Spark 설명서의 [Metrics](https://spark.apache.org/docs/latest/monitoring.html#metrics)(지표)를 참조하세요.

**참고**  
다른 플랫폼에서 Spark 워크로드를 Amazon EMR로 마이그레이션하는 경우 사용자 지정 구성을 추가하기 전에 [Amazon EMR에서 설정한 Spark 기본값](#spark-defaults)을 사용하여 워크로드를 테스트하는 것이 좋습니다. 대부분의 고객은 기본 설정을 통해 성능을 개선할 수 있습니다.

**Topics**
+ [Amazon EMR에서 설정한 Spark 기본값](#spark-defaults)
+ [Amazon EMR 6.1.0에서 Spark 가비지 수집 구성](#spark-gc-config)
+ [`maximizeResourceAllocation` 사용하기](#emr-spark-maximizeresourceallocation)
+ [노드 서비스 해제 동작 구성](#spark-decommissioning)
+ [Spark ThriftServer 환경 변수](#spark-thriftserver)
+ [Spark 기본 설정 변경](#spark-change-defaults)
+ [Apache Log4j 1.x에서 Log4j 2.x로 마이그레이션](#spark-migrate-logj42)

## Amazon EMR에서 설정한 Spark 기본값
<a name="spark-defaults"></a>

다음 테이블에서는 Amazon EMR이 애플리케이션에 영향을 미치는 `spark-defaults`의 기본값을 설정하는 방법을 보여줍니다.


**Amazon EMR에서 설정한 Spark 기본값**  

| 설정 | 설명 | 기본값  | 
| --- | --- | --- | 
| spark.executor.memory | 실행기 프로세스당 사용할 메모리 양. 예시: `1g`, `2g`. |  이 설정은 클러스터의 코어 및 태스크 인스턴스 유형에 따라 결정됩니다.  | 
| spark.executor.cores | 각 실행기에서 사용할 코어 수입니다. | 이 설정은 클러스터의 코어 및 태스크 인스턴스 유형에 따라 결정됩니다. | 
| spark.dynamicAllocation.enabled | true인 경우 동적 리소스 할당을 사용하여 워크로드를 기반으로 애플리케이션에 등록된 실행기 수를 늘리거나 줄입니다. |  `true`(Amazon EMR 4.4.0 이상)  Amazon EMR에서 Spark Shuffle Service를 자동으로 구성합니다.   | 
| spark.sql.hive.advancedPartitionPredicatePushdown.enabled | true인 경우 Hive 메타스토어로의 고급 파티션 조건부 푸시다운이 활성화됩니다. | true | 
| spark.sql.hive.stringLikePartitionPredicatePushdown.enabled | `startsWith`, `contains`, `endsWith` 필터를 Hive 메타스토어로 푸시다운합니다.  Glue는 `startsWith`, `contains` 또는 `endsWith`에 대한 조건부 푸시다운을 지원하지 않습니다. Glue 메타스토어를 사용하는 중에 이러한 함수의 조건부 푸시다운으로 인해 오류가 발생하는 경우 이 구성을 `false`로 설정합니다.   | true | 

## Amazon EMR 6.1.0에서 Spark 가비지 수집 구성
<a name="spark-gc-config"></a>

`spark.driver.extraJavaOptions` 및 `spark.executor.extraJavaOptions`에서 사용자 지정 가비지 수집 구성을 설정하면 Amazon EMR 6.1에서 드라이버 또는 실행기가 시작되지 않습니다. Amazon EMR 6.1.0과 가비지 수집 구성이 충돌하기 때문입니다. Amazon EMR 6.1.0의 경우 기본 가비지 수집 구성은 `spark.driver.defaultJavaOptions` 및 `spark.executor.defaultJavaOptions`를 통해 설정됩니다. 이 구성은 Amazon EMR 6.1.0에만 적용됩니다. 로깅 구성과 같이 가비지 수집과 관련이 없는 JVM 옵션(`-verbose:class`)은 계속 `extraJavaOptions`를 통해 설정할 수 있습니다. 자세한 내용은 [Spark application properties](https://spark.apache.org/docs/latest/configuration.html#application-properties)를 참조하세요.

## `maximizeResourceAllocation` 사용하기
<a name="emr-spark-maximizeresourceallocation"></a>

클러스터의 각 노드에서 가능한 최대 리소스를 사용하도록 실행기를 구성하려면 `spark` 구성 분류에서 `maximizeResourceAllocation`을 `true`로 설정합니다. `maximizeResourceAllocation`은 Amazon EMR에만 해당됩니다. `maximizeResourceAllocation`을 활성화하는 경우 Amazon EMR은 코어 인스턴스 그룹의 인스턴스에 있는 실행기에 대해 사용할 수 있는 최대 컴퓨팅 및 메모리 리소스를 계산합니다. 그런 다음 계산된 최대값을 기반으로 해당 `spark-defaults` 설정을 설정합니다.

Amazon EMR은 코어 인스턴스 플릿의 인스턴스 유형에 기반하여 실행기에 대해 사용할 수 있는 최대 컴퓨팅 및 메모리 리소스를 계산합니다. 각 인스턴스 플릿은 플릿 내에서 서로 다른 인스턴스 유형과 크기를 가질 수 있으므로 Amazon EMR이 사용하는 실행기 구성이 클러스터에 적합하지 않을 수 있습니다. 따라서 최대 리소스 할당을 사용할 때 기본 설정을 사용하지 않는 것이 좋습니다. 인스턴스 플릿 클러스터에 대한 사용자 지정 설정을 구성합니다.

**참고**  
HBase와 같은 다른 분산 애플리케이션이 있는 클러스터에서는 `maximizeResourceAllocation` 옵션을 사용하지 않아야 합니다. Amazon EMR은 분산 애플리케이션에 사용자 지정 YARN 구성을 사용하므로 `maximizeResourceAllocation`과 충돌하여 Spark 애플리케이션이 실패할 수 있습니다.

다음은 `maximizeResourceAllocation`을 `true`로 설정한 Spark 구성 분류 예제입니다.

```
[
  {
    "Classification": "spark",
    "Properties": {
      "maximizeResourceAllocation": "true"
    }
  }
]
```


**`spark-defaults`활성화 시 `maximizeResourceAllocation`에서 구성되는 설정**  

| 설정 | 설명 | 값 | 
| --- | --- | --- | 
| spark.default.parallelism | 사용자가 설정하지 않은 경우 조인, reduceByKey 및 병렬 처리 같은 변환에서 반환한 RDD의 기본 파티션 수입니다. |  YARN 컨테이너에서 사용할 수 있는 CPU 코어의 2배수입니다.  | 
| spark.driver.memory | SparkContext가 초기화된 경우와 같이 드라이버 프로세스에 사용할 메모리 양(예: 1g, 2g)입니다. |  클러스터의 인스턴스 유형을 기반으로 설정이 구성됩니다. 하지만 Spark 드라이버 애플리케이션을 프라이머리 또는 코어 인스턴스 중 하나에서(예를 들면 각각 YARN 클라이언트 및 클러스터 모드에서) 실행할 수 있으므로 설정이 이러한 두 인스턴스 그룹에서 더 작은 인스턴스 유형에 따라 설정됩니다.  | 
| spark.executor.memory | 실행기 프로세스당 사용하는 메모리 양(예: 1g, 2g)입니다. |  클러스터의 코어 및 작업 인스턴스 유형을 기반으로 설정이 구성됩니다.  | 
| spark.executor.cores | 각 실행기에서 사용할 코어 수입니다. | 클러스터의 코어 및 작업 인스턴스 유형을 기반으로 설정이 구성됩니다. | 
| spark.executor.instances |  실행기의 수입니다. |  클러스터의 코어 및 작업 인스턴스 유형을 기반으로 설정이 구성됩니다. `spark.dynamicAllocation.enabled`가 동시에 명시적으로 true로 설정되지 않은 경우 설정합니다.  | 

## 노드 서비스 해제 동작 구성
<a name="spark-decommissioning"></a>

Amazon EMR 릴리스 5.9.0 이상에서는 Amazon EMR의 Spark에는 수동 크기 조정 또는 자동 조정 정책 요청으로 인해 Spark가 노드 종료를 원활하게 처리하도록 돕는 일련의 기능이 포함되어 있습니다. Amazon EMR은 YARN의 폐기 메커니즘을 기반으로 하여 구축된 Spark에서 블랙리스팅 메커니즘을 구현합니다. 이 메커니즘은 폐기 중인 노드에서 새 작업을 예약하지 않는 동시에 이미 실행 중인 작업을 완료하는 데 도움이 됩니다. 또한 노드가 종료될 때 셔플 블록이 손실되는 경우, Spark 작업을 보다 빠르게 복구하는 데 도움이 되는 기능들도 있습니다. 재계산 프로세스는 더 빨리 트리거되고 단계 재시도 횟수를 줄이면서 더 빨리 재계산하도록 최적화되며, 셔플 블록 누락으로 인한 가져오기 실패로 인해 작업이 실패하는 것을 방지할 수 있습니다.

**중요**  
스팟 인스턴스를 사용할 때 Spark 복원력을 높일 수 있도록 Amazon EMR 릴리스 버전 5.11.0에 `spark.decommissioning.timeout.threshold` 설정이 추가되었습니다. 이전 릴리스에서는 노드가 스팟 인스턴스를 사용하고 입찰 가격으로 인해 인스턴스가 종료될 때 Spark가 정상적으로 종료를 처리하지 못할 수 있습니다. 작업은 실패할 수 있으며 셔플 재계산 시 상당한 시간이 걸릴 수 있습니다. 이러한 이유로 스팟 인스턴스를 사용하는 경우, 5.11.0 이상의 릴리스를 사용하는 것이 좋습니다.


**Spark 노드 서비스 해제 설정**  

| 설정 | 설명 | 기본값  | 
| --- | --- | --- | 
|  `spark.blacklist.decommissioning.enabled`  |  `true`로 설정한 경우 Spark는 YARN에서 `decommissioning` 상태의 노드를 거부 목록에 등록합니다. Spark은 해당 노드에서 실행 중인 executor에 대해 새 작업을 예약하지 않습니다. 이미 실행 중인 작업은 완료 할 수 있습니다.  |  `true`  | 
|  `spark.blacklist.decommissioning.timeout`  |  `decommissioning` 상태의 노드가 거부 목록에 등록된 동안의 시간입니다. 기본적으로 이 값은 1시간으로 설정되는데, 이는 `yarn.resourcemanager.decommissioning.timeout`에 대한 기본값이기도 합니다. 전체 서비스 해제 기간에 노드를 거부 목록에 등록하려면 이 값을 `yarn.resourcemanager.decommissioning.timeout` 이상으로 설정합니다. 서비스 해제 제한 시간이 만료되면 노드는 `decommissioned` 상태로 전환되며 Amazon EMR은 노드의 EC2 인스턴스를 종료할 수 있습니다. 제한 시간이 만료된 후에도 작업이 계속 실행 중이면 다른 노드에서 실행 중인 executor에서 손실되거나 종료되며 일정이 조정됩니다.  |  `1h`  | 
|  `spark.decommissioning.timeout.threshold`  |  Amazon EMR 릴리스 5.11.0 이상에서 사용할 수 있습니다. 초 단위로 지정됩니다. 노드가 서비스 해제 상태로 전환될 때 호스트가 이 값보다 작거나 같은 시간 안에 서비스 해제되는 경우, Amazon EMR은 노드가 서비스 해제 상태로 전환되기를 기다리지 않고 노드를 거부 목록에 등록할 뿐 아니라 호스트 상태를 정리합니다(`spark.resourceManager.cleanupExpiredHost`에서 지정한 대로). 이를 통해 Spark가 스팟 인스턴스 종료를 더 잘 처리할 수 있습니다. 다른 노드가 셔플 파일을 읽기에는 시간이 부족할 수 있는 `yarn.resourcemager.decommissioning.timeout` 값에 상관없이 20초 제한 시간 이내에 스팟 인스턴스가 폐기되기 때문입니다.  |  `20s`  | 
|  `spark.resourceManager.cleanupExpiredHost`  |  `true`로 설정된 Spark는 `decommissioned` 상태에 있는 노드의 executor에 저장된 모든 캐시된 데이터와 셔플 블록의 등록을 취소합니다. 이렇게 하면 복구 프로세스가 빨라집니다.  |  `true`  | 
|  `spark.stage.attempt.ignoreOnDecommissionFetchFailure`  |  `true`로 설정되면 폐기된 노드에서 가져오기 실패 건수가 너무 많은 이유로 Spark에서 단계 및 작업이 실패하는 문제를 방지하는 데 도움이 됩니다. `decommissioned` 상태의 노드에서 셔플 블록 가져오기 실패는 연속 가져오기의 최대 실패 횟수에 포함되지 않습니다.  | true | 

## Spark ThriftServer 환경 변수
<a name="spark-thriftserver"></a>

Spark에서 Hive Thrift Server Port 환경 변수 `HIVE_SERVER2_THRIFT_PORT`를 10001로 설정합니다.

## Spark 기본 설정 변경
<a name="spark-change-defaults"></a>

`spark-defaults` 구성 분류 또는 `spark` 구성 분류의 `maximizeResourceAllocation` 설정을 사용하여 `spark-defaults.conf`에서 기본값을 변경합니다.

다음 절차에는 CLI 또는 콘솔을 사용하여 설정을 수정하는 방법이 나와 있습니다.

**CLI를 사용하여 spark.executor.memory가 2g로 설정된 클러스터를 생성하는 방법**
+ Amazon S3에 저장된 `myConfig.json` 파일을 참조하는 다음 명령을 사용하여 Spark가 설치되고 `spark.executor.memory`가 2g로 설정된 클러스터를 생성합니다.

  ```
  aws emr create-cluster --release-label emr-7.12.0 --applications Name=Spark \
  --instance-type m5.xlarge --instance-count 2 --service-role EMR_DefaultRole_V2 --ec2-attributes InstanceProfile=EMR_EC2_DefaultRole --configurations https://s3.amazonaws.com/amzn-s3-demo-bucket/myfolder/myConfig.json
  ```
**참고**  
가독성을 위해 Linux 줄 연속 문자(\$1)가 포함됩니다. Linux 명령에 사용하거나 제외할 수 있습니다. Windows에서는 제외시키거나 캐럿(^)으로 바꿉니다.

  `myConfig.json`:

  ```
  [
      {
        "Classification": "spark-defaults",
        "Properties": {
          "spark.executor.memory": "2G"
        }
      }
    ]
  ```

**콘솔을 사용하여 spark.executor.memory가 2ㅎ로 설정된 클러스터를 생성하는 방법**

1. 새 Amazon EMR 콘솔로 이동하고 측면 탐색에서 **이전 콘솔로 전환**을 선택합니다. 이전 콘솔로 전환할 때 예상되는 사항에 대한 자세한 내용은 [이전 콘솔 사용](https://docs.aws.amazon.com/emr/latest/ManagementGuide/whats-new-in-console.html#console-opt-in)을 참조하세요.

1. **클러스터 생성** 및 **고급 옵션으로 이동**을 선택합니다.

1. **Spark**를 선택합니다.

1. **소프트웨어 설정 편집**에서 **구성 입력**을 선택한 채로 다음 구성을 입력합니다.

   ```
   classification=spark-defaults,properties=[spark.executor.memory=2G]
   ```

1. 다른 옵션을 선택하고, ****을 선택한 다음 **클러스터 생성**을 선택합니다.

**maximizeResourceAllocation을 설정하려면**
+ Spark가 설치된 클러스터를 생성하고 Amazon S3에 `myConfig.json`저장된 파일 AWS CLI를 참조하여를 사용하여 true로 `maximizeResourceAllocation` 설정합니다.

  ```
  aws emr create-cluster --release-label emr-7.12.0 --applications Name=Spark \
  --instance-type m5.xlarge --instance-count 2 --service-role EMR_DefaultRole_V2 --ec2-attributes InstanceProfile=EMR_EC2_DefaultRole --configurations https://s3.amazonaws.com/amzn-s3-demo-bucket/myfolder/myConfig.json
  ```
**참고**  
가독성을 위해 Linux 줄 연속 문자(\$1)가 포함됩니다. Linux 명령에 사용하거나 제외할 수 있습니다. Windows에서는 제외시키거나 캐럿(^)으로 바꿉니다.

  `myConfig.json`:

  ```
  [
    {
      "Classification": "spark",
      "Properties": {
        "maximizeResourceAllocation": "true"
      }
    }
  ]
  ```

**참고**  
Amazon EMR 버전 5.21.0 이상에서는 클러스터 구성을 재정의할 수 있으며, 실행 중인 클러스터의 각 인스턴스 그룹에 대해 추가 구성 분류를 지정할 수 있습니다. Amazon EMR 콘솔, AWS Command Line Interface (AWS CLI) 또는 AWS SDK를 사용하여이 작업을 수행할 수 있습니다. 자세한 내용은 [실행 중 클러스터의 인스턴스 그룹에 대해 구성 제공](https://docs.aws.amazon.com/emr/latest/ReleaseGuide/emr-configure-apps-running-cluster.html)을 참조하세요.

## Apache Log4j 1.x에서 Log4j 2.x로 마이그레이션
<a name="spark-migrate-logj42"></a>

[Apache Spark](https://aws.amazon.com/emr/features/spark/) 릴리스 3.2.x 이하에서는 레거시 Apache Log4j 1.x 및 `log4j.properties` 파일을 사용하여 Spark 프로세스에서 Log4j를 구성합니다. Apache Spark 릴리스 3.3.0 이상에서는 Apache Log4j 2.x 및 `log4j2.properties` 파일을 사용하여 Spark 프로세스에서 Log4j를 구성합니다.

6.8.0 미만의 Amazon EMR 릴리스를 사용하여 Apache Spark Log4j를 구성한 경우 Amazon EMR 6.8.0 이상으로 업그레이드하기 전에 먼저 레거시 `spark-log4j` 구성 분류를 제거하고 `spark-log4j2` 구성 분류 및 키 형식으로 마이그레이션해야 합니다. 기존 `spark-log4j` 분류로 인해 Amazon EMR 릴리스 6.8.0 이상에서 `ValidationException` 오류로 클러스터 생성이 실패합니다. Log4j 비호환성과 관련된 오류에 대해서는 요금이 부과되지 않지만 계속하려면 더 이상 사용되지 않는 `spark-log4j` 구성 분류를 제거해야 합니다.

Apache Log4j 1.x에서 Log4j 2.x로 마이그레이션하는 방법에 대한 자세한 내용은 Github에서 [Apache Log4j Migration Guide](https://logging.apache.org/log4j/2.x/manual/migration.html) 및 [Spark Log4j 2 Template](https://github.com/apache/spark/blob/master/conf/log4j2.properties.template)을 참조하세요.

**참고**  
Amazon EMR에서 Apache Spark는 [Apache Log4j Migration Guide](https://logging.apache.org/log4j/2.x/manual/migration.html)에 설명된 .xml 파일 대신 `log4j2.properties` 파일을 사용합니다. 또한 Log4j 1.x 브리지 메서드를 사용하여 Log4j 2.x로 변환하는 방법도 권장하지 않습니다.

# Amazon EMR용 Apache Spark 문제 해결 에이전트란?
<a name="spark-troubleshoot"></a>

## 소개
<a name="spark-troubleshooting-agent-intro"></a>

Amazon EMR용 Apache Spark 문제 해결 에이전트는 Amazon EMR, AWS Glue 및 Amazon SageMaker 노트북에서 Apache Spark 애플리케이션의 문제 해결을 간소화하는 대화형 AI 기능입니다. 기존 Spark 문제 해결에서는 로그, 성능 지표 및 오류 패턴을 광범위하게 수동으로 분석하여 근본 원인과 코드 수정을 식별해야 합니다. 에이전트는 자연어 프롬프트, 자동화된 워크로드 분석 및 지능형 코드 권장 사항을 통해이 프로세스를 간소화합니다.

에이전트를 사용하여 PySpark 및 Scala 애플리케이션 실패 문제를 해결할 수 있습니다. 에이전트는 실패한 작업을 분석하고, 성능 병목 현상을 식별하고, 실행 가능한 권장 사항 및 코드 수정을 제공하는 동시에 구현 결정을 완벽하게 제어할 수 있습니다.

**참고**  
Apache Spark 문제 해결 에이전트는 Amazon EMR의 일부로 추가 비용 없이 사용할 수 있습니다. 에이전트는 분석 및 권장 사항만 제공합니다. 권장 수정 사항을 검증하기 위해 애플리케이션을 실행할 때 사용하는 Amazon EMR 리소스에 대해서만 비용을 지불합니다.

## 아키텍처 개요
<a name="spark-troubleshooting-agent-architecture"></a>

문제 해결 에이전트에는 상호 작용을 위한 개발 환경의 MCP 호환 AI 도우미, 클라이언트와 AWS 서비스 간의 보안 통신 및 인증을 처리하는 [용 MCP 프록시 AWS](https://github.com/aws/mcp-proxy-for-aws), Amazon EMR, Glue 및 Amazon SageMaker 노트북을 위한 특수 Spark 문제 해결 도구를 `(preview)` 제공하는 Amazon SageMaker Unified Studio 원격 MCP 서버의 세 가지 주요 구성 요소가 있습니다. AWS 이 다이어그램은 AI 도우미를 통해 Amazon SageMaker Unified Studio 원격 MCP 서버와 상호 작용하는 방법을 보여줍니다.

![\[Spark 에이전트 아키텍처 문제 해결.\]](http://docs.aws.amazon.com/ko_kr/emr/latest/ReleaseGuide/images/spark-troubleshooting-agent-architecture.png)


AI 어시스턴트는 다음 단계에 따라 MCP 서버에서 제공하는 특수 도구를 사용하여 문제 해결을 오케스트레이션합니다.
+ **특성 추출 및 컨텍스트 구축:** 에이전트는 Spark 기록 서버 로그, 구성 설정 및 오류 추적을 포함하여 Spark 애플리케이션에서 원격 측정 데이터를 자동으로 수집하고 분석합니다. 주요 성능 지표, 리소스 사용률 패턴 및 장애 서명을 추출하여 지능형 문제 해결을 위한 포괄적인 컨텍스트 프로파일을 구축합니다.
+ **GenAI 근본 원인 분석기 및 권장 엔진:** 에이전트는 AI 모델과 Spark 지식 기반을 활용하여 추출된 기능을 상호 연관시키고 성능 문제 또는 장애의 근본 원인을 식별합니다. Spark 애플리케이션 실행에서 무엇이 잘못되었는지에 대한 진단 인사이트와 분석을 제공합니다.
+ **GenAI Spark 코드 권장 사항:** 이전 단계의 근본 원인 분석을 기반으로 에이전트는 기존 코드 패턴을 분석하고 애플리케이션 장애에 대한 코드 수정이 필요한 비효율적인 작업을 식별합니다. 구체적인 예제를 통해 특정 코드 수정, 구성 조정 및 아키텍처 개선 등 실행 가능한 권장 사항을 제공합니다.

**Topics**
+ [소개](#spark-troubleshooting-agent-intro)
+ [아키텍처 개요](#spark-troubleshooting-agent-architecture)
+ [에이전트 문제 해결을 위한 설정](spark-troubleshooting-agent-setup.md)
+ [문제 해결 에이전트 사용](spark-troubleshooting-using-troubleshooting-agent.md)
+ [기능 및 기능](spark-troubleshooting-features.md)
+ [문제 해결 및 Q&A](spark-troubleshooting-agent-troubleshooting.md)
+ [세부 정보의 Spark 에이전트 워크플로 문제 해결](spark-troubleshooting-agent-workflow.md)
+ [프롬프트 예제](spark-troubleshooting-agent-prompt-examples.md)
+ [IAM 역할 설정](spark-troubleshooting-agent-iam-setup.md)
+ [Spark 문제 해결 도구 사용](spark-troubleshooting-agent-using-tools.md)
+ [Amazon SageMaker Unified Studio MCP에 대한 인터페이스 VPC 엔드포인트 구성](spark-troubleshooting-agent-vpc-endpoints.md)
+ [Apache Spark 문제 해결 에이전트의 리전 간 처리](spark-troubleshooting-cross-region-processing.md)
+ [를 사용하여 Amazon SageMaker Unified Studio MCP 호출 로깅 AWS CloudTrail](spark-troubleshooting-cloudtrail-integration.md)
+ [Apache Spark 에이전트의 서비스 개선 사항](spark-agents-service-improvements.md)

# 에이전트 문제 해결을 위한 설정
<a name="spark-troubleshooting-agent-setup"></a>

**참고**  
Apache Spark 문제 해결 에이전트는 리전 간 추론을 사용하여 자연어 요청을 처리하고 응답을 생성합니다. 자세한 내용은 단원을 참조하십시오[Apache Spark 문제 해결 에이전트의 리전 간 처리](spark-troubleshooting-cross-region-processing.md). Amazon SageMaker Unified Studio MCP 서버는 미리 보기 중이며 변경될 수 있습니다.

## 사전 조건
<a name="spark-troubleshooting-agent-prerequisites"></a>

Kiro CLI와의 통합을 위한 설정 프로세스를 시작하기 전에 워크스테이션에 다음이 설치되어 있는지 확인합니다.
+  [AWS CLI 설치 ](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) 
+  [ Python 3.10 이상 설치 ](https://www.python.org/downloads/release/python-3100/) 
+  [ 용 MCP 프록시용 `uv` 패키지 관리자 설치 ](https://docs.astral.sh/uv/getting-started/installation/) [AWS](https://github.com/aws/mcp-proxy-for-aws?tab=readme-ov-file) 
+  [ Kiro CLI 설치 ](https://kiro.dev/docs/cli/) 
+ AWS 구성된 로컬 자격 증명([AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html), 환경 변수 또는 IAM 역할을 통해) - EMR 검증 작업 실행을 위해 업그레이드된 작업 아티팩트 업로드와 같은 로컬 작업에 사용됩니다.

## 리소스 설정
<a name="spark-troubleshooting-agent-setup-resources"></a>

 AWS CloudFormation 템플릿을 사용하여 MCP 서버의 리소스를 설정할 수 있습니다. 이 템플릿은 요구 사항에 맞게 수정해야 하는 샘플입니다. 템플릿은 문제 해결 프로세스를 위해 다음 리소스를 생성합니다.

1. MCP Server를 호출할 수 있는 권한과 선택한 플랫폼의 문제 해결 프로세스에 필요한 권한이 있는 IAM 역할입니다.

다음 표에서 **스택 시작** 버튼 중 하나를 선택하십시오. 그러면 해당 리전의 AWS CloudFormation 콘솔에서 스택이 시작됩니다.


| 리전 | 시작 | 
| --- | --- | 
| 미국 동부(오하이오) |  [https://console.aws.amazon.com/cloudformation/home?region=us-east-2#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-us-east-2.s3.us-east-2.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup](https://console.aws.amazon.com/cloudformation/home?region=us-east-2#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-us-east-2.s3.us-east-2.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup)  | 
| 미국 동부(버지니아 북부) |  [https://console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-us-east-1.s3.us-east-1.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup](https://console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-us-east-1.s3.us-east-1.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup)  | 
| 미국 서부(오레곤) |  [https://console.aws.amazon.com/cloudformation/home?region=us-west-2#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-us-west-2.s3.us-west-2.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup](https://console.aws.amazon.com/cloudformation/home?region=us-west-2#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-us-west-2.s3.us-west-2.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup)  | 
| 아시아 태평양(도쿄) |  [https://console.aws.amazon.com/cloudformation/home?region=ap-northeast-1#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-ap-northeast-1.s3.ap-northeast-1.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup](https://console.aws.amazon.com/cloudformation/home?region=ap-northeast-1#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-ap-northeast-1.s3.ap-northeast-1.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup)  | 
| 유럽(아일랜드) |  [https://console.aws.amazon.com/cloudformation/home?region=eu-west-1#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-eu-west-1.s3.eu-west-1.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup](https://console.aws.amazon.com/cloudformation/home?region=eu-west-1#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-eu-west-1.s3.eu-west-1.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup)  | 
| 아시아 태평양(싱가포르) |  [https://console.aws.amazon.com/cloudformation/home?region=ap-southeast-1#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-ap-southeast-1.s3.ap-southeast-1.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup](https://console.aws.amazon.com/cloudformation/home?region=ap-southeast-1#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-ap-southeast-1.s3.ap-southeast-1.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup)  | 
| 아시아 태평양(시드니) |  [https://console.aws.amazon.com/cloudformation/home?region=ap-southeast-2#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-ap-southeast-2.s3.ap-southeast-2.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup](https://console.aws.amazon.com/cloudformation/home?region=ap-southeast-2#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-ap-southeast-2.s3.ap-southeast-2.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup)  | 
| 캐나다(중부) |  [https://console.aws.amazon.com/cloudformation/home?region=ca-central-1#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-ca-central-1.s3.ca-central-1.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup](https://console.aws.amazon.com/cloudformation/home?region=ca-central-1#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-ca-central-1.s3.ca-central-1.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup)  | 
| 남아메리카(상파울루) |  [https://console.aws.amazon.com/cloudformation/home?region=sa-east-1#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-sa-east-1.s3.sa-east-1.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup](https://console.aws.amazon.com/cloudformation/home?region=sa-east-1#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-sa-east-1.s3.sa-east-1.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup)  | 
| 유럽(프랑크푸르트) |  [https://console.aws.amazon.com/cloudformation/home?region=eu-central-1#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-eu-central-1.s3.eu-central-1.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup](https://console.aws.amazon.com/cloudformation/home?region=eu-central-1#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-eu-central-1.s3.eu-central-1.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup)  | 
| 유럽(스톡홀름) |  [https://console.aws.amazon.com/cloudformation/home?region=eu-north-1#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-eu-north-1.s3.eu-north-1.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup](https://console.aws.amazon.com/cloudformation/home?region=eu-north-1#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-eu-north-1.s3.eu-north-1.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup)  | 
| 유럽(런던) |  [https://console.aws.amazon.com/cloudformation/home?region=eu-west-2#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-eu-west-2.s3.eu-west-2.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup](https://console.aws.amazon.com/cloudformation/home?region=eu-west-2#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-eu-west-2.s3.eu-west-2.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup)  | 
| 유럽(파리) |  [https://console.aws.amazon.com/cloudformation/home?region=eu-west-3#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-eu-west-3.s3.eu-west-3.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup](https://console.aws.amazon.com/cloudformation/home?region=eu-west-3#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-eu-west-3.s3.eu-west-3.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup)  | 
| 아시아 태평양(서울) |  [https://console.aws.amazon.com/cloudformation/home?region=ap-northeast-2#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-ap-northeast-2.s3.ap-northeast-2.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup](https://console.aws.amazon.com/cloudformation/home?region=ap-northeast-2#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-ap-northeast-2.s3.ap-northeast-2.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup)  | 
| 아시아 태평양(뭄바이) |  [https://console.aws.amazon.com/cloudformation/home?region=ap-south-1#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-ap-south-1.s3.ap-south-1.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup](https://console.aws.amazon.com/cloudformation/home?region=ap-south-1#/stacks/new?templateURL=https%3A%2F%2Fsmus-mcp-cfn-template-prod-ap-south-1.s3.ap-south-1.amazonaws.com%2Fcloudformation%2Fspark-troubleshooting-mcp-setup.yaml&stackName=spark-troubleshooting-mcp-setup)  | 

**스택 세부 정보 지정** 페이지로 이동하여 **스택 이름을** 입력합니다. **파라미터(Parameters)** 아래에 추가 정보를 입력합니다. 다음 정보를 제공하고 스택 생성을 진행합니다.
+ **TroubleshootingRoleName** - 문제 해결 작업을 위해 생성할 IAM 역할의 이름입니다.
+ **EnableEMREC2** - EMR-EC2 문제 해결 권한 활성화(기본값: true)
+ **EnableEMRServerless** - EMR-Serverless 문제 해결 권한 활성화(기본값: true)
+ **EnableGlue** - Glue 문제 해결 권한 활성화(기본값: true)
+ **CloudWatchKmsKeyArn** - (선택 사항) CloudWatch Logs 암호화를 위한 기존 KMS 키의 ARN(EMR Serverless만 해당, 기본 암호화를 위해 비워둠)

[CloudFormation 템플릿을](https://github.com/aws-samples/aws-emr-utilities/blob/03c20fece616de23ec0ea5389f0113a5bc65fc3a/utilities/apache-spark-agents/spark-troubleshooting-agent-cloudformation/spark-troubleshooting-mcp-setup.yaml) 다운로드 및 검토하고, 위의 옵션을 지정하고, CloudFormation CLI 명령을 사용하여 템플릿을 직접 시작할 수도 있습니다. 아래 예제를 참조하세요.

```
# deploy the stack with CloudFormation CLI commands
aws cloudformation deploy \
  --template-file spark-troubleshooting-mcp-setup.yaml \
  --stack-name spark-troubleshooting-mcp-setup \
  --region <your Spark MCP server launch region> \
  --capabilities CAPABILITY_NAMED_IAM \
  --parameter-overrides \
    TroubleshootingRoleName=spark-troubleshooting-role


# retrieve the 1-line instruction to set the local environment variables, which will be used for the following MCP server configuration
aws cloudformation describe-stacks \
  --stack-name spark-troubleshooting-mcp-setup \
  --region <your Spark MCP server launch region> \
  --query "Stacks[0].Outputs[?OutputKey=='ExportCommand'].OutputValue" \
  --output text
```

출력 탭을 열고(또는 위의 CloudFormation describe-stacks CLI 명령에서 검색) CloudFormation 출력에서 1줄 명령을 복사하여 환경 변수를 설정한 다음 로컬 환경에서 실행합니다. 1줄 지침의 예:

```
export SMUS_MCP_REGION=<your mcp server launch region> && export IAM_ROLE=arn:aws:iam::111122223333:role/spark-troubleshooting-role-xxxxxx
```

그런 다음 로컬에서 다음 명령을 실행하여 IAM 프로파일 및 MCP 서버 구성을 설정합니다.

```
# Step 1: Configure AWS CLI Profile
aws configure set profile.smus-mcp-profile.role_arn ${IAM_ROLE}
aws configure set profile.smus-mcp-profile.source_profile <AWS CLI Profile to assume the IAM role - ex: default>
aws configure set profile.smus-mcp-profile.region ${SMUS_MCP_REGION}

# Step 2: if you are using kiro CLI, use the following command to add the MCP configuration
# Add Spark Troubleshooting MCP Server
kiro-cli-chat mcp add \
    --name "sagemaker-unified-studio-mcp-troubleshooting" \
    --command "uvx" \
    --args "[\"mcp-proxy-for-aws@latest\",\"https://sagemaker-unified-studio-mcp.${SMUS_MCP_REGION}.api.aws/spark-troubleshooting/mcp\", \"--service\", \"sagemaker-unified-studio-mcp\", \"--profile\", \"smus-mcp-profile\", \"--region\", \"${SMUS_MCP_REGION}\", \"--read-timeout\", \"180\"]" \
    --timeout 180000 \
    --scope global
    
# Add Spark Code Recommendation MCP Server
kiro-cli-chat mcp add \
    --name "sagemaker-unified-studio-mcp-code-rec" \
    --command "uvx" \
    --args "[\"mcp-proxy-for-aws@latest\",\"https://sagemaker-unified-studio-mcp.${SMUS_MCP_REGION}.api.aws/spark-code-recommendation/mcp\", \"--service\", \"sagemaker-unified-studio-mcp\", \"--profile\", \"smus-mcp-profile\", \"--region\", \"${SMUS_MCP_REGION}\", \"--read-timeout\", \"180\"]" \
    --timeout 180000 \
    --scope global
```

MCP 서버 구성을 `~/.kiro/settings/mcp.json` 포함하도록 아래와 같이 업데이트해야 합니다.

```
{
  "mcpServers": {
    "sagemaker-unified-studio-mcp-troubleshooting": {
      "type": "stdio",
      "command": "uvx",
      "args": [
        "mcp-proxy-for-aws@latest",
        "https://sagemaker-unified-studio-mcp.us-east-1.api.aws/spark-troubleshooting/mcp",
        "--service",
        "sagemaker-unified-studio-mcp",
        "--profile",
        "smus-mcp-profile",
        "--region",
        "us-east-1",
        "--read-timeout",
        "180"
      ],
      "timeout": 180000,
      "disabled": false
    },
    "sagemaker-unified-studio-mcp-code-rec": {
      "type": "stdio",
      "command": "uvx",
      "args": [
        "mcp-proxy-for-aws@latest",
        "https://sagemaker-unified-studio-mcp.us-east-1.api.aws/spark-code-recommendation/mcp",
        "--service",
        "sagemaker-unified-studio-mcp",
        "--profile",
        "smus-mcp-profile",
        "--region",
        "us-east-1",
        "--read-timeout",
        "180"
      ],
      "timeout": 180000,
      "disabled": false
    }
  }
}
```

Kiro, Cline 및 GitHub CoPilot과 같은 다양한 MCP 클라이언트에 대한 구성 지침은 섹션을 참조[지원되는 인터페이스](spark-troubleshooting-using-troubleshooting-agent.md#supported-interfaces)하세요.

# 문제 해결 에이전트 사용
<a name="spark-troubleshooting-using-troubleshooting-agent"></a>

## 지원되는 배포 모드
<a name="supported-deployment-modes"></a>

Amazon EMR용 Apache Spark 문제 해결 에이전트는 자동화된 오류 진단, 성능 병목 현상 식별, 코드 권장 사항 및 다음 Spark 배포 모드의 향상된 애플리케이션 성능을 위한 실행 가능한 제안 등 장애가 발생한 Spark 워크로드에 대한 포괄적인 분석 기능을 지원합니다.
+ EMR on EC2
+ EMR Serverless
+ AWS Glue

자세한 기능, 용량 및 제한 사항을 알아보려면 [기능 및 기능](spark-troubleshooting-features.md) 섹션을 참조하세요.

## 지원되는 인터페이스
<a name="supported-interfaces"></a>

### Amazon SageMaker 노트북 내 셀 문제 해결
<a name="troubleshooting-sagemaker-notebooks"></a>

Amazon SageMaker Notebooks의 문제 해결 경험에 대한 데모입니다. 노트북 셀 장애의 경우 `Fix with AI` 버튼을 클릭하여 Amazon SageMaker Notebook Agent에 분석 요청 실패 문제를 해결하고 코드에서 오류가 발생한 경우 가능한 코드 수정을 요청할 수 있습니다.

[![AWS Videos](http://img.youtube.com/vi/https://www.youtube.com/embed/btW8hwio0tE/0.jpg)](http://www.youtube.com/watch?v=https://www.youtube.com/embed/btW8hwio0tE)


### Kiro CLI를 사용한 Glue 및 EMR Spark 애플리케이션 문제 해결
<a name="troubleshooting-glue-emr-applications"></a>

Kiro CLI 또는 AI Assistant를 시작하고 문제 해결 프로세스를 위해 로드된 도구를 확인합니다.

```
...
 sagemaker-unified-studio-mcp-code-rec (MCP)
 - spark_code_recommendation    not trusted
 
 sagemaker-unified-studio-mcp-troubleshooting (MCP)
 - analyze_spark_workload       not trusted
...
```

이제 Spark 문제 해결 에이전트 워크플로를 시작할 준비가 되었습니다.

Kiro CLI의 문제 해결 경험에 대한 데모입니다. 다음 프롬프트를 사용하여 문제 해결 프로세스를 시작할 수 있습니다.

```
Analyze my Glue job. The job name is "xxx" and the job run id is "xxx"
```

[![AWS Videos](http://img.youtube.com/vi/https://www.youtube.com/embed/YLwV_EenJXY/0.jpg)](http://www.youtube.com/watch?v=https://www.youtube.com/embed/YLwV_EenJXY)


### 다른 MCP 클라이언트와 통합
<a name="integration-other-mcp-clients"></a>

에 설명된 구성은 다른 MCP 클라이언트 및 IDEs 데 사용할 [에이전트 문제 해결을 위한 설정](spark-troubleshooting-agent-setup.md) 수 있습니다.
+ **Cline과 통합** - MCP 서버를 Cline과 함께 사용하려면를 수정`cline_mcp_settings.json`하고 위의 구성을 추가합니다. MCP 구성을 관리하는 방법에 대한 자세한 내용은 [Cline의 설명서를](https://docs.cline.bot/mcp/configuring-mcp-servers) 참조하세요.
+ **Claude 코드와 통합** Claude 코드와 함께 MCP 서버를 사용하려면 MCP 구성을 포함하도록 구성 파일을 수정합니다. 파일 경로는 운영 체제에 따라 다릅니다. 자세한 설정은 [ https://code.claude.com/docs/en/mcp](https://code.claude.com/docs/en/mcp) 참조하십시오.
+ **GitHub Copilot과의 통합** - GitHub Copilot과 함께 MCP 서버를 사용하려면 [ https://docs.github.com/en/copilot/how-tos/provide-context/use-mcp/extend-copilot-chat-with-mcp](https://docs.github.com/en/copilot/how-tos/provide-context/use-mcp/extend-copilot-chat-with-mcp) 지침에 따라 해당 구성 파일을 수정하고 각 IDE의 지침에 따라 설정을 활성화합니다.

# 기능 및 기능
<a name="spark-troubleshooting-features"></a>

## 지원되는 플랫폼
<a name="supported-platforms"></a>
+ **언어**: Python 및 Scala Spark 애플리케이션
+ **대상 플랫폼**: Amazon EMR, EMR Serverless 및 AWS Glue

## 작동 방식
<a name="how-it-works"></a>

Spark 애플리케이션에 장애가 발생하면 문제 해결 에이전트를 사용하여 무엇이 잘못되었는지 자동으로 조사할 수 있습니다. Spark 이벤트 로그, 오류 메시지 및 리소스 사용량을 분석하여 메모리 부족, 구성 오류 또는 코드 버그와 같은 정확한 문제를 정확히 찾아냅니다.

자연어 프롬프트에 Spark 워크로드를 분석하도록 요청하면 에이전트는 플랫폼의 리소스에 연결하고 기능(Spark 이벤트 로그, 쿼리 계획, 실행기 타임라인, 로그 추적, 구성 및 지표 포함)을 추출합니다.
+ EMR-EC2: 클러스터의 [EMR 영구 UI](https://docs.aws.amazon.com/emr/latest/ManagementGuide/app-history-spark-UI.html)에 연결
+ Glue: 작업에 대한 Glue Studio의 [Spark UI](https://docs.aws.amazon.com/glue/latest/dg/monitor-spark-ui-jobs.html)에서 컨텍스트를 빌드합니다.
+ EMR-Serverless: 작업을 위해 EMR-Serverless [Spark 기록 서버에](https://docs.aws.amazon.com/emr-serverless/latest/APIReference/API_GetDashboardForJobRun.html) 연결
+ 또한 에이전트는 오류 스택 추적 및 구성 세부 정보를 분석하여 실행 가능한 인사이트를 제공합니다.

실패한 워크로드의 경우 명확한 근본 원인 설명과 이를 해결하기 위한 특정 단계를 얻을 수 있습니다. 에이전트가 코드 관련 문제를 감지하면 코드에서 변경해야 할 사항을 정확히 보여주는 코드 권장 사항을 자동으로 제공합니다. 전체 분석 없이 언제든지 코드 수준 제안을 직접 요청할 수도 있습니다.

## 사용 가능한 리전
<a name="available-regions"></a>

Spark 문제 해결 에이전트는 다음 리전에서 사용할 수 있습니다.
+ **아시아 태평양**: 도쿄(ap-northeast-1), 서울(ap-northeast-2), 싱가포르(ap-southeast-1), 시드니(ap-southeast-2), 뭄바이(ap-south-1)
+ **북미**: 캐나다(ca-central-1)
+ **유럽**: 스톡홀름(eu-north-1), 아일랜드(eu-west-1), 런던(eu-west-2), 파리(eu-west-3), 프랑크푸르트(eu-central-1)
+ **남아메리카**: 상파울루(sa-east-1)
+ **미국**: 버지니아 북부(us-east-1), 오하이오(us-east-2), 오리건(us-west-2)

## Spark 문제 해결 범위 및 사용자 요구 사항
<a name="scope-requirements"></a>
+ **지원되는 Spark 워크로드 상태**: 도구는 실패한 Spark 워크로드에 대한 응답만 지원합니다.
+ **EMR 영구 UI:** Amazon EMR-EC2 워크로드를 분석할 때 분석 도구는 EMR 영구 UI에 연결하여 주요 Spark 정보를 검색하려고 시도합니다. EMR 영구 UI 고려 사항은 [ 여기에](https://docs.aws.amazon.com/emr/latest/ManagementGuide/app-history-spark-UI.html#app-history-spark-UI-limitations) 설명되어 있습니다.
+ **Glue Studio Spark UI**: Glue 워크로드를 분석할 AWS 때 분석 도구는 Amazon S3에서 사용자의 Spark 이벤트 로그를 구문 분석하여 주요 Spark 정보를 검색하려고 시도합니다. 허용되는 최대 Spark 이벤트 로그 크기는 여기에 설명되어 [ 있습니다](https://docs.aws.amazon.com/glue/latest/dg/monitor-spark-ui-jobs.html). 롤링 로그의 경우 512MB 및 2GB입니다.
+ **코드 권장 사항:** PySpark 워크로드용 Amazon EMR-EC2 및 AWS Glue 워크로드에만 지원됨
+ **리전 리소스:** Spark 문제 해결 에이전트는 리전별이며 문제 해결 프로세스에 해당 리전의 기본 EMR 리소스를 사용합니다. 리전 간 문제 해결은 지원되지 않습니다.

# 문제 해결 및 Q&A
<a name="spark-troubleshooting-agent-troubleshooting"></a>

## 문제 해결
<a name="spark-troubleshooting-common-issues"></a>

Spark 문제 해결 에이전트의 오류 메시지는 다양한 MCP 클라이언트에서 다양한 방식으로 사용할 수 있습니다. 이 페이지에서는 Amazon EMR용 Apache Spark 문제 해결 에이전트를 사용하여 발생할 수 있는 일반적인 문제에 대한 몇 가지 일반적인 지침을 나열합니다.

주제
+ [오류: MCP 서버 로드 실패](#mcp-server-failed-to-load)
+ [관찰: 느린 도구 로드](#slow-tool-loading)
+ [오류: 제한 오류와 함께 도구 호출 실패](#throttling-error)
+ [오류: 도구가 사용자 오류로 응답](#user-error)
+ [오류: 도구가 내부 오류로 응답](#internal-error)

### 오류: MCP 서버 로드 실패
<a name="mcp-server-failed-to-load"></a>
+ MCP 구성이 올바르게 구성되었는지 확인합니다.
+ **JSON 구문 검증**:
  + 구문 오류 없이 JSON이 유효한지 확인
  + 누락된 쉼표, 따옴표 또는 대괄호 확인
+ 로컬 AWS 자격 증명을 확인하고 MCP IAM 역할에 대한 정책이 올바르게 구성되었는지 확인합니다.
+ /mcp를 실행하여 `Kiro-CLI` 사례에 대한 MCP 서버 가용성 확인

### 관찰: 느린 도구 로드
<a name="slow-tool-loading"></a>
+ 서버를 처음 시작할 때 도구를 로드하는 데 몇 초 정도 걸릴 수 있습니다.
+ 도구가 표시되지 않으면 채팅을 다시 시작해 보세요.
+ `/tools` 명령을 실행하여 도구 가용성을 확인합니다.
+ 서버가 오류 없이 시작`/mcp`되면를 실행합니다.

### 오류: 제한 오류와 함께 도구 호출 실패
<a name="throttling-error"></a>
+ 서비스 한도에 도달한 경우 제한 예외가 표시되면 몇 초 정도 기다렸다가 도구 호출을 실행하십시오.

### 오류: 도구가 사용자 오류로 응답
<a name="user-error"></a>
+ AccessDeniedException - 오류 메시지를 확인하고 권한 문제를 수정합니다.
+ InvalidInputException - 오류 메시지를 확인하고 도구 입력 파라미터를 수정합니다.
+ ResourceNotFoundException - 오류 메시지를 확인하고 리소스 참조를 위해 입력 파라미터를 수정합니다.

### 오류: 도구가 내부 오류로 응답
<a name="internal-error"></a>
+ 표시되는 경우 몇 초 후에 도구 호출을 다시 시도`The service is handling high-volume requests`하세요.
+ 분석 ID, 도구 이름, mcp 로그 또는 도구 응답에서 사용할 수 있는 오류 메시지, 선택적으로 삭제된 대화 기록을 문서화하고 AWS 지원 팀에 문의`INTERNAL SERVICE EXCEPTION`하세요.

## Q&A
<a name="spark-troubleshooting-qa"></a>

### 1. 도구에 대해 기본적으로 "신뢰" 설정을 활성화해야 합니까?
<a name="qa-trust-setting"></a>

처음에는 모든 도구 호출에 대해 기본적으로 "신뢰" 설정을 켜지 말고 코드 권장 사항을 수락할 때 git 버전 빌드 환경에서 작동하세요. 각 도구 실행을 검토하여 변경 사항을 이해합니다.

### 2. 문제 해결 도구를 활용하기 위한 일반적인 예제 프롬프트는 무엇입니까?
<a name="qa-example-prompts"></a>

문제 해결 도구 활용에 대한 프롬프트 예제[프롬프트 예제](spark-troubleshooting-agent-prompt-examples.md)는 섹션을 참조하세요.

### 3. LLM으로 전송되는 데이터는 무엇이며 어떻게 처리됩니까?
<a name="qa-data-transmitted-to-llm"></a>

고객 데이터 및 파일은 선택한 AWS 리전 내에 유지되며 리전 간에 전송되지 않습니다. 에이전트가 Amazon Bedrock의 글로벌 리전 간 추론을 사용하는 리전에서 작동하는 경우 서비스는 수요에 따라 사용 가능한 용량이 있는 가장 가까운 리전으로 요청을 라우팅할 수 있습니다. 이러한 경우 고객 로그에서 추출한 메타데이터와 처리된 추론 결과만 전송되며 기본 고객 데이터나 파일은 전송되지 않습니다. 추론이 동일한 리전 내에서 발생하든 다른 리전으로 라우팅하든 모든 데이터는 처리를 위해 LLM으로 전송되기 전에 PII 마스킹 처리됩니다. 교차 리전 추론의 작동 방식과 영향을 받는 리전에 대한 자세한 내용은 섹션을 참조하세요[Apache Spark 문제 해결 에이전트의 리전 간 처리](spark-troubleshooting-cross-region-processing.md).

# 세부 정보의 Spark 에이전트 워크플로 문제 해결
<a name="spark-troubleshooting-agent-workflow"></a>

문제 해결 프로세스를 시작하려면 지원되는 플랫폼(EMR-EC2, EMR Serverless, AWS Glue 또는 Amazon SageMaker Data Notebooks)에서 실행 중인 실패한 Spark 애플리케이션 식별자에 액세스해야 합니다. 애플리케이션에는 액세스 가능한 로그, Spark 기록 서버 및 구성 세부 정보가 있어야 합니다. 플랫폼 리소스 및 애플리케이션 메타데이터에 액세스하는 데 필요한 권한이 있는지 확인합니다. 이러한 요구 사항이 설정되면 다음과 같은 프롬프트를 제출하여 문제 해결 워크플로를 시작할 수 있습니다.

```
Analyze my EMR step execution failure, EMR id <step-id> with cluster id <cluster-id>
```

이 시점에서 에이전트는 특수 도구를 사용하여 문제 해결을 오케스트레이션합니다. 워크플로는 다음 단계를 따릅니다.

1. **특성 추출 및 컨텍스트 구축**: 에이전트는 기록 서버 로그, 구성 설정 및 오류 추적을 포함하여 Spark 애플리케이션에서 원격 측정 데이터를 자동으로 수집하고 분석합니다. 성능 지표, 리소스 사용률 패턴 및 장애 서명에 대한 정보를 수집하는 도구가 표시됩니다.

1. **분석 및 근본 원인 식별**: 에이전트는 AI 모델과 Spark 지식 기반을 활용하여 추출된 기능을 상호 연관시키고 성능 문제 또는 장애의 근본 원인을 식별합니다. 다음을 받게 됩니다.
   + **분석 인사이트**: 에이전트가 검색하고 분석한 내용에 대한 기술 세부 정보입니다.
   + **근본 원인**: 무엇이 왜 잘못되었는지에 대한 명확한 설명입니다.
   + **초기 평가**: 문제가 코드 관련이든 구성 관련이든 리소스 관련이든 완화를 위한 몇 가지 일반 지침 및 분석이 제공됩니다.

1. **코드 권장 사항**(해당하는 경우): 분석에서 오류 분류를 기반으로 코드 관련 문제를 식별하는 경우 에이전트는 코드 권장 도구를 활용하여 제안된 대체와 함께 정확한 전/후 코드로 권장 코드 수정을 구현하기 위한 특정 권장 사항을 제공하도록 제안할 수 있습니다.

문제 해결 프로세스는 반복적입니다. 대화를 계속 진행하여 특정 문제를 자세히 살펴볼 수 있습니다. 로컬 Spark 코드 개발에서 대화형으로 도구를 사용하여 코드 버그를 해결하거나 코드를 지속적으로 개선할 수도 있습니다.

# 프롬프트 예제
<a name="spark-troubleshooting-agent-prompt-examples"></a>

다음은 문제 해결 경험에 사용할 수 있는 프롬프트 예제 목록입니다.

## 1. Spark 작업 실행 실패 문제 해결
<a name="troubleshoot-job-failure"></a>

EC2의 EMR 문제 해결:

```
Troubleshoot my EMR-EC2 step with id s-xxxxxxxxxxxx on cluster j-xxxxxxxxxxxxx
```

Glue 작업 문제 해결:

```
Troubleshoot my Glue job with job run id jr_xxxxxxxxxxxxxxxxxxxxxxxxxxxx and job name test_job
```

EMR Serverless 문제 해결:

```
Troubleshoot my EMR-Serverless job run with application id 00xxxxxxxx and job run id 00xxxxxxxx
```

## 2. 코드 수정 권장 사항 요청
<a name="request-code-fix"></a>

EC2 작업의 EMR에 대한 코드 수정 권장 사항 요청:

```
Recommend code fix for my EMR-EC2 step with id s-STEP_ID on cluster j-CLUSTER_ID
```

Glue 작업에 대한 코드 수정 권장 사항 요청:

```
Recommend code fix for my Glue job with job run id jr_JOB_RUN_ID and job name test_job
```

# IAM 역할 설정
<a name="spark-troubleshooting-agent-iam-setup"></a>

설정 지침의 CloudFormation 스택은 IAM 역할 설정을 자동화합니다. 수동으로 실행하려면 아래 지침을 따르세요.

## MCP 서버에 대한 IAM 역할 설정
<a name="iam-role-mcp-server"></a>

SMUS 관리형 MCP 서버에 액세스하려면 다음 인라인 정책에 따라 IAM 역할이 필요합니다.

```
{
    "Version": "2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "AllowUseSagemakerUnifiedStudioMcpServer",
            "Effect": "Allow",
            "Action": [
                "sagemaker-unified-studio-mcp:InvokeMcp",
                "sagemaker-unified-studio-mcp:CallReadOnlyTool",
                "sagemaker-unified-studio-mcp:CallPrivilegedTool"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}
```

다음 단계에서는이 역할에 대한 프로필을 생성합니다. 자격 증명을 얻기 위해이 역할을 수임하는 계정은 수임 역할 정책에 추가해야 합니다.

```
{
  "Version": "2012-10-17",		 	 	 
  "Statement": [
    {
      "Sid": "AllowAccountToAssumeRole",
      "Effect": "Allow",
      "Principal": { "AWS": "arn:aws:iam::<accountId>:root" },
      "Action": "sts:AssumeRole"
    }
  ]
}
```

## 배포 모드별 추가 권한(EMR-EC2/EMR-S/Glue)
<a name="additional-permissions"></a>

### EMR-EC2 애플리케이션
<a name="emr-ec2-permissions"></a>

```
{
    "Version": "2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "EMREC2ReadAccess",
            "Effect": "Allow",
            "Action": [
                "elasticmapreduce:DescribeCluster",
                "elasticmapreduce:DescribeStep",
                "elasticmapreduce:ListSteps",
                "elasticmapreduce:ListClusters",
                "elasticmapreduce:DescribeJobFlows"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Sid": "EMRS3LogAccess",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:ListBucket"
            ],
            "Resource": "*"
        },
        {
            "Sid": "EMRPersistentApp",
            "Effect": "Allow",
            "Action": [
                "elasticmapreduce:CreatePersistentAppUI",
                "elasticmapreduce:DescribePersistentAppUI",
                "elasticmapreduce:GetPersistentAppUIPresignedURL"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}
```

### Glue 작업
<a name="glue-permissions"></a>

```
{
    "Version": "2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "GlueReadAccess",
            "Effect": "Allow",
            "Action": [
                "glue:GetJob",
                "glue:GetJobRun",
                "glue:GetJobRuns",
                "glue:GetJobs",
                "glue:BatchGetJobs"
            ],
            "Resource": [
                "arn:aws:glue:*:<account id>:job/*"
            ]
        },
        {
            "Sid": "GlueCloudWatchLogsAccess",
            "Effect": "Allow",
            "Action": [
                "logs:GetLogEvents",
                "logs:FilterLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:*:<account id>:log-group:/aws/glue/*"
            ]
        },
        {
            "Sid": "GlueSparkWebUI",
            "Effect": "Allow",
            "Action": [
                "glue:RequestLogParsing",
                "glue:GetLogParsingStatus",
                "glue:GetEnvironment",
                "glue:GetStage",
                "glue:GetStages",
                "glue:GetStageFiles",
                "glue:BatchGetStageFiles",
                "glue:GetStageAttempt",
                "glue:GetStageAttemptTaskList",
                "glue:GetStageAttemptTaskSummary",
                "glue:GetExecutors",
                "glue:GetExecutorsThreads",
                "glue:GetStorage",
                "glue:GetStorageUnit",
                "glue:GetQueries",
                "glue:GetQuery",
                "glue:GetDashboardUrl"
            ],
            "Resource": [
                "arn:aws:glue:*:<account id>:job/*"
            ]
        },
        {
            "Sid": "GluePassRoleAccess",
            "Effect": "Allow",
            "Action": "iam:PassRole",
            "Resource": "*",
            "Condition": {
                "StringLike": {
                    "iam:PassedToService": "glue.amazonaws.com"
                }
            }
        }
    ]
}
```

### EMR Serverless 애플리케이션
<a name="emr-serverless-permissions"></a>

```
{
    "Version": "2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "EMRServerlessReadAccess",
            "Effect": "Allow",
            "Action": [
                "emr-serverless:GetJobRun",
                "emr-serverless:GetApplication",
                "emr-serverless:ListApplications",
                "emr-serverless:ListJobRuns",
                "emr-serverless:ListJobRunAttempts",
                "emr-serverless:GetDashboardForJobRun",
                "emr-serverless:ListTagsForResource"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Sid": "EMRServerlessCloudWatchLogsAccess",
            "Effect": "Allow",
            "Action": [
                "logs:GetLogEvents",
                "logs:FilterLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:*:<account id>:log-group:/aws/emr-serverless/*"
            ]
        },
        {
            "Sid": "EMRServerlessS3LogsAccess",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:ListBucket"
            ],
            "Resource": "*"
        }
    ]
}
```

### KMS 권한 - CloudWatch Logs
<a name="kms-permissions"></a>

CloudWatch Logs가 CMK로 암호화된 경우 서비스가 EMR-Serverless 애플리케이션 로그를 읽을 수 있도록 다음 정책을 추가합니다.

```
{
    "Effect": "Allow",
    "Action": [
        "kms:Decrypt",
        "kms:DescribeKey"
    ],
    "Resource": "arn:aws:kms:<region>:<account-id>:key/<cw-logs-cmk-id>"
}
```

# Spark 문제 해결 도구 사용
<a name="spark-troubleshooting-agent-using-tools"></a>

## 사용 가능한 문제 해결 도구
<a name="available-tools"></a>

MCP 서비스는 Spark 문제 해결 에이전트를 위한 다양한 도구를 제공합니다. 주요 도구는 다음과 같습니다.


| 도구 이름 | 도구 범주 | 설명 | 
| --- | --- | --- | 
| analyze\$1spark\$1워크로드 | 근본 원인 분석 | 실패한 Apache Spark 워크로드에 대한 자세한 문제 해결 제공 | 
| spark\$1code\$1recommendation | 코드 수정 권장 사항 | 실패한 작업에 대한 Apache Spark 코드 권장 사항을 제공합니다. | 

# Amazon SageMaker Unified Studio MCP에 대한 인터페이스 VPC 엔드포인트 구성
<a name="spark-troubleshooting-agent-vpc-endpoints"></a>

*인터페이스 VPC 엔드포인트*를 생성하여 VPC와 Amazon SageMaker Unified Studio MCP 서비스 간에 프라이빗 연결을 설정할 수 있습니다. 인터페이스 엔드포인트는 [Amazon VPC](https://aws.amazon.com/vpc/)로 구동되므로 인터넷 게이트웨이, NAT 디바이스, VPN 연결 또는 연결 없이 VPC의 MCP 서버에 비공개로 액세스할 수 있습니다. VPC의 인스턴스는 MCP 서비스와 통신하는 데 퍼블릭 IP 주소가 필요하지 않으며 VPC와 MCP 서비스 간의 트래픽은 Amazon 네트워크를 벗어나지 않습니다.

각 인터페이스 엔드포인트는 VPC 서브넷에서 하나 이상의 [탄력적 네트워크 인터페이스](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-eni.html)로 표시됩니다. 자세한 내용은 *Amazon* [VPC 사용 설명서의 인터페이스 VPC 엔드포인트](https://docs.aws.amazon.com/vpc/latest/userguide/vpce-interface.html)를 참조하세요.

## 1단계: Amazon SageMaker Unified Studio MCP용 인터페이스 VPC 엔드포인트 생성
<a name="create-vpc-endpoint"></a>

Amazon VPC 콘솔 또는를 사용하여 Amazon SageMaker Unified Studio MCP 서비스에 대한 VPC 엔드포인트를 생성할 수 있습니다 AWS CLI. 자세한 내용은 *Amazon VPC 사용 설명서*의 [인터페이스 엔드포인트 생성](https://docs.aws.amazon.com/vpc/latest/userguide/vpce-interface.html#create-interface-endpoint)을 참조하세요.

다음 서비스 이름을 사용하여 Amazon SageMaker Unified Studio MCP용 VPC 엔드포인트를 생성합니다.
+ com.amazonaws.*<aws-region>*.sagemaker-unified-studio-mcp

엔드포인트에 대해 프라이빗 DNS를 활성화하는 경우 리전의 기본 DNS 이름을 사용하여 Amazon SageMaker Unified Studio MCP에 API 요청을 할 수 있습니다. 예를 들면 다음과 같습니다. `sagemaker-unified-studio-mcp.us-east-1.api.aws` 

자세한 내용은 *Amazon VPC 사용 설명서*의 [인터페이스 엔드포인트를 통해 서비스 액세스](https://docs.aws.amazon.com/vpc/latest/userguide/vpce-interface.html#access-service-though-endpoint)를 참조하세요.

## 2단계: Amazon SageMaker Unified Studio MCP에 대한 VPC 엔드포인트 정책 생성
<a name="create-vpc-endpoint-policy"></a>

Amazon SageMaker Unified Studio MCP에 대한 액세스를 제어하는 엔드포인트 정책을 VPC 엔드포인트에 연결할 수 있습니다. 이 정책은 다음 정보를 지정합니다.
+ 작업을 수행할 수 있는 위탁자.
+ 수행할 수 있는 작업.
+ 작업을 수행할 수 있는 리소스.

자세한 내용은 *Amazon VPC 사용 설명서*의 [VPC 엔드포인트를 통해 서비스에 대한 액세스 제어](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-endpoints-access.html)를 참조하세요.

### 예: 특정 IAM 역할에 대한 MCP 액세스를 허용하는 VPC 엔드포인트 정책
<a name="vpc-endpoint-policy-example"></a>

다음은 Amazon SageMaker Unified Studio MCP 액세스를 위한 엔드포인트 정책의 예입니다. 엔드포인트에 연결되면이 정책은 모든 리소스의 특정 IAM 역할 보안 주체에 대해 나열된 Amazon SageMaker Unified Studio MCP 작업에 대한 액세스 권한을 부여합니다.

```
{
  "Version": "2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::ACCOUNT-ID:role/YourRoleName"
      },
      "Action": [
        "sagemaker-unified-studio-mcp:InvokeMcp",
        "sagemaker-unified-studio-mcp:CallReadOnlyTool",
        "sagemaker-unified-studio-mcp:CallPrivilegedTool"
      ],
      "Resource": "*"
    }
  ]
}
```

## 3단계: VPC 테스트
<a name="test-vpc-endpoint"></a>

이 `curl` 명령은 HTTP/HTTPS 요청을 통해 VPC 네트워크(EC2)에서 VPC 엔드포인트로의 end-to-end 네트워크 연결을 검증합니다. MCP 서버에서 메시지를 다시 수신하는 curl 응답은 전체 네트워크 경로가 작동하는지 확인합니다.

### 방법 1: 프라이빗 DNS가 활성화된 경우(권장)
<a name="test-private-dns-enabled"></a>

```
curl https://sagemaker-unified-studio-mcp.us-east-1.api.aws/spark-troubleshooting/mcp
```

### 방법 2: 프라이빗 DNS가 활성화되지 않은 경우
<a name="test-private-dns-disabled"></a>

```
curl -k https://vpce-0069xxxx-ejwhxxx.sagemaker-unified-studio-mcp.us-east-1.vpce.amazonaws.com/spark-troubleshooting/mcp
```

**참고**  
`-k` 플래그는 VPC 엔드포인트 DNS 이름과 인증서의 일반 이름(CN) 간의 호스트 이름 불일치로 인해 SSL 인증서 확인을 우회합니다.

두 경우 모두 curl 명령은 응답을 반환합니다`{"Message":"...."}`. 메시지와 함께를 반환하면 MCP 서비스의 VPC 엔드포인트에 대한 네트워크 경로 연결이 성공했는지 확인합니다.

## 4단계: MCP VPC 엔드포인트 사용 시작
<a name="use-vpc-endpoint"></a>

연결을 확인한 후에는 단계에 따라에서 MCP를 구성할 수 있습니다[에이전트 문제 해결을 위한 설정](spark-troubleshooting-agent-setup.md). MCP 구성에서 프라이빗 VPC 엔드포인트를 사용하기만 하면 됩니다.

# Apache Spark 문제 해결 에이전트의 리전 간 처리
<a name="spark-troubleshooting-cross-region-processing"></a>

Apache Spark 문제 해결 에이전트는 리전 간 추론을 사용하여 자연어 요청을 처리하고 응답을 생성합니다. 교차 리전 추론을 통해 에이전트는 추론 요청을 자동으로 라우팅하여 성능을 최적화하고 사용 가능한 컴퓨팅 리소스와 모델 가용성을 극대화하며 최상의 고객 경험을 제공합니다. 사용되는 교차 리전 추론 유형은 Apache Spark 문제 해결 에이전트를 실행하는 리전에 따라 다릅니다. 대부분의 리전에서 에이전트는 추론 요청을 처리할 리전 내에서 최적의 리전을 선택합니다. 그러나 일부 리전에서는 에이전트가 수행한 추론 요청이 모든 글로벌 상용 AWS 리전에서 사용 가능한 모든 컴퓨팅 리소스로 안전하게 라우팅됩니다.

## 교차 리전 추론
<a name="cross-region-inference-overview"></a>

Apache Spark 문제 해결 에이전트는 Amazon Bedrock으로 구동되며 교차 리전 추론을 사용하여 여러 AWS 리전에 트래픽을 분산하여 대규모 언어 모델(LLM) 추론 성능과 신뢰성을 개선합니다.

Spark 애플리케이션 또는 문제 해결 환경이 호스팅되거나 데이터가 저장되는 리전 간 추론은 변경되지 않지만, 추론 처리를 위해 입력 프롬프트와 출력 결과가 다른 리전으로 전송될 수 있습니다. 모든 데이터는 Amazon의 보안 네트워크를 통해 암호화되어 전송됩니다.

교차 리전 추론을 사용하는 데 드는 추가 비용은 없습니다.

## 교차 리전 추론에 지원되는 리전
<a name="supported-regions-cross-region"></a>

 **지리적 리전 간 추론을 사용하는 리전** 

대부분의 리전에서 교차 리전 추론 요청은 Apache Spark 문제 해결 에이전트를 실행하는 동일한 리전의 일부인 AWS 리전 내에 보관됩니다. 예를 들어 미국 동부(버지니아 북부) 리전의 에이전트로부터 이루어진 요청은 미국 리전 내의 AWS 리전으로만 라우팅됩니다. 다음 표에서는 요청이 시작된 리전에 따라 요청이 라우팅될 수 있는 리전을 설명합니다.


| 지원되는 지역 | 추론 리전 | 
| --- | --- | 
|  미국  |  미국 동부(버지니아 북부)(us-east-1), 미국 서부(오레곤)(us-west-2), 미국 동부(오하이오)(us-east-2), 미국 서부(캘리포니아 북부)(us-west-1)  | 
|  유럽  |  유럽(프랑크푸르트)(eu-central-1), 유럽(아일랜드)(eu-west-1), 유럽(파리)(eu-west-3), 유럽(스톡홀름)(eu-north-1), 유럽(런던)(eu-west-2)  | 
|  아시아 태평양  |  아시아 태평양(도쿄)(ap-northeast-1), 아시아 태평양(서울)(ap-northeast-2), 아시아 태평양(뭄바이)(ap-south-1)  | 

### 글로벌 리전 간 추론을 사용하는 리전
<a name="global-cross-region-inference"></a>

**중요**  
다음 AWS 리전은 글로벌 리전 간 추론을 사용합니다. 이러한 리전에서 Apache Spark 문제 해결 에이전트를 사용하는 경우 성능 및 가용성을 최적화하기 위해 추론 처리를 위해 요청이 다른 AWS 리전으로 전역적으로 전송될 수 있습니다.  
남아메리카(상파울루) (sa-east-1)
아시아 태평양(싱가포르)(ap-southeast-1)
아시아 태평양(시드니)(ap-southeast-2)
캐나다(중부)(ca-central-1)

# 를 사용하여 Amazon SageMaker Unified Studio MCP 호출 로깅 AWS CloudTrail
<a name="spark-troubleshooting-cloudtrail-integration"></a>

Amazon SageMaker Unified Studio MCP Server는 Amazon SageMaker Unified Studio MCP Server에서 사용자, 역할 또는 서비스가 수행한 작업에 대한 레코드를 AWS CloudTrail제공하는 AWS 서비스와 통합됩니다. CloudTrail은 Amazon SageMaker Unified Studio MCP Server에 대한 모든 API 호출을 이벤트로 캡처합니다. 캡처되는 호출에는 Amazon SageMaker Unified Studio MCP Server에 대한 호출과 SageMaker Unified Studio MCP Server에서 도구를 실행하는 동안 다른 AWS 작업에 대한 코드 호출이 포함됩니다. 추적을 생성하면 Amazon SageMaker Unified Studio MCP Server에 대한 이벤트를 포함하여 CloudTrail 이벤트를 지속적으로 Amazon S3 버킷에 배포할 수 있습니다. Amazon S3 Amazon SageMaker 추적을 구성하지 않은 경우에도 **이벤트 기록**에서 CloudTrail 콘솔의 최신 이벤트를 볼 수 있습니다. CloudTrail에서 수집한 정보를 사용하여 Amazon SageMaker Unified Studio MCP 서버에 수행된 요청, 요청이 수행된 IP 주소, 요청을 수행한 사람, 요청이 수행된 시간 및 추가 세부 정보를 확인할 수 있습니다.

CloudTrail에 대한 자세한 내용은 [AWS CloudTrail 사용 설명서](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/)를 참조하세요.

## CloudTrail의 Amazon SageMaker Unified Studio MCP Server 정보
<a name="sagemaker-mcp-info-in-cloudtrail"></a>

 AWS 계정을 생성할 때 계정에서 CloudTrail이 활성화됩니다. Amazon SageMaker Unified Studio MCP 서버에서 활동이 발생하면 해당 활동은 **이벤트 기록**의 다른 AWS 서비스 이벤트와 함께 CloudTrail 이벤트에 기록됩니다. AWS 계정에서 최근 이벤트를 보고 검색하고 다운로드할 수 있습니다. 자세한 내용은 [CloudTrail 이벤트 기록을 사용하여 이벤트 보기](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/view-cloudtrail-events.html)를 참조하세요.

SageMaker Unified Studio MCP Server에 대한 이벤트를 포함하여 AWS 계정에 이벤트를 지속적으로 기록하려면 추적을 생성합니다. CloudTrail은 추적을 사용하여 Amazon S3 버킷으로 로그 파일을 전송할 수 있습니다. 기본적으로 콘솔에서 추적을 생성하면 추적이 모든 AWS 리전에 적용됩니다. 추적은 AWS 파티션의 모든 리전에서 이벤트를 로깅하고 지정한 Amazon S3 버킷으로 로그 파일을 전송합니다. 또한 CloudTrail 로그에서 수집된 이벤트 데이터를 추가로 분석하고 조치를 취하도록 다른 AWS 서비스를 구성할 수 있습니다. 자세한 내용은 다음 자료를 참조하세요.
+ [추적 생성 개요](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-create-and-update-a-trail.html)
+ [CloudTrail 지원 서비스 및 통합](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-aws-service-specific-topics.html)
+ [CloudTrail에 대한 Amazon SNS 알림 구성](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/configure-sns-notifications-for-cloudtrail.html)
+ [여러 리전에서 CloudTrail 로그 파일 받기](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/receive-cloudtrail-log-files-from-multiple-regions.html) 및 [여러 계정에서 CloudTrail 로그 파일 받기](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-receive-logs-from-multiple-accounts.html)

도구 실행 중에 AWS 서비스에 대한 모든 SageMaker Unified Studio MCP Server 도구 호출 및 API 호출은 CloudTrail에서 로깅됩니다. 예를 들어 다양한 도구에 대한 호출과 도구에서 수행된 AWS 서비스 호출은 CloudTrail 로그 파일에 항목을 생성합니다.

모든 이벤트 또는 로그 항목에는 요청을 생성했던 사용자에 관한 정보가 포함됩니다. ID 정보를 이용하면 다음을 쉽게 판단할 수 있습니다.
+ 요청을 루트로 했는지 아니면 IAM 사용자 자격 증명 정보로 했는지 여부.
+ 역할 또는 페더레이션 사용자의 임시 자격 증명을 사용하여 요청이 생성되었는지 여부.
+ 요청이 다른 AWS 서비스에 의해 이루어졌는지 여부입니다.

자세한 내용은 [CloudTrail userIdentity 요소](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-event-reference-user-identity.html)를 참조하세요.

## Amazon SageMaker Unified Studio MCP Server 로그 파일 항목 이해
<a name="understanding-mcp-log-entries"></a>

트레일이란 지정한 S3 버킷에 이벤트를 로그 파일로 입력할 수 있게 하는 구성입니다. CloudTrail 로그 파일에는 하나 이상의 로그 항목이 포함될 수 있습니다. 이벤트는 모든 소스로부터의 단일 요청을 나타내며 요청 작업, 작업 날짜와 시간, 요청 파라미터 등에 대한 정보가 들어 있습니다. CloudTrail 로그 파일은 퍼블릭 API 직접 호출의 주문 스택 트레이스가 아니므로 특정 순서로 표시되지 않습니다.

다음 예제는 `CallTool` 작업을 보여주는 CloudTrail 로그 항목이 나타냅니다.

```
{
    "eventVersion": "1.09",
    "userIdentity": {
        ...
    },
    "eventTime": "...",
    "eventSource": "sagemaker-unified-studio-mcp.amazonaws.com",
    "eventName": "CallPrivilegedTool",
    "awsRegion": "us-east-1",
    "sourceIPAddress": "...",
    "userAgent": "...",
    "requestParameters": {
        "id": 1,
        "method": "tools/call",
        "params": {
            "name": "generate_spark_upgrade_plan",
            "arguments": "***",
            "_meta": {
                "progressToken": 1
            }
        },
        "jsonrpc": "2.0"
    },
    "responseElements": {
        "result": {
            "content": "***",
            "structuredContent": "***",
            "isError": false
        },
        "id": 1,
        "jsonrpc": "2.0"
    },
    "requestID": "12345678-1234-1234-1234-123456789012",
    "eventID": "87654321-4321-4321-4321-210987654321",
    "readOnly": false,
    "eventType": "AwsMcpEvent",
    "managementEvent": true,
    "recipientAccountId": "123456789012",
    "eventCategory": "Management"
}
```

다음 예제는 업그레이드 도구 호출 중에 Amazon SageMaker Unified Studio MCP의 `AddJobFlowSteps` 작업을 보여주는 CloudTrail 로그 항목을 보여줍니다.

```
{
    "eventVersion": "1.11",
    "userIdentity": {
        "type": "AssumedRole",
        "principalId": "...",
        "arn": "...",
        "accountId": "123456789012",
        "accessKeyId": "...",
        "sessionContext": {
            ...
        },
        "invokedBy": "sagemaker-unified-studio-mcp.amazonaws.com"
    },
    "eventTime": "...",
    "eventSource": "elasticmapreduce.amazonaws.com",
    "eventName": "AddJobFlowSteps",
    "awsRegion": "us-east-1",
    "sourceIPAddress": "sagemaker-unified-studio-mcp.amazonaws.com",
    "userAgent": "sagemaker-unified-studio-mcp.amazonaws.com",
    "requestParameters": {
        "jobFlowId": "j-2PY4KXXXXXX63",
        "steps": [
            ...
        ]
    },
    "responseElements": {
        "stepIds": [
            ...
        ]
    },
    "requestID": "12345678-1234-1234-1234-123456789013",
    "eventID": "87654321-4321-4321-4321-210987654322",
    "readOnly": false,
    "eventType": "AwsApiCall",
    "managementEvent": true,
    "recipientAccountId": "123456789012",
    "sharedEventID": "12345678-1234-1234-1234-123456789012",
    "vpcEndpointId": "sagemaker-unified-studio-mcp.amazonaws.com",
    "vpcEndpointAccountId": "sagemaker-unified-studio-mcp.amazonaws.com",
    "eventCategory": "Management"
}
```

# Apache Spark 에이전트의 서비스 개선 사항
<a name="spark-agents-service-improvements"></a>

Amazon EMR용 Apache Spark 에이전트는 예를 들어 에이전트가 일반적인 질문에 더 나은 응답을 제공하거나 운영 문제를 해결하거나 디버깅하는 데 도움이 되는 콘텐츠를 사용할 수 있습니다.

## 가 서비스 개선에 사용할 AWS 수 있는 콘텐츠
<a name="content-used-for-improvement"></a>
+ Amazon EMR, AWS Glue 및 Amazon SageMaker Notebooks에 대한 Apache Spark 에이전트의 자연어 프롬프트 및 생성된 응답

## 서비스 개선에를 사용하지 AWS 않는 콘텐츠
<a name="content-not-used-for-improvement"></a>
+ Spark 애플리케이션을 위해 직접 작성하는 코드
+ SageMaker 노트북 컨텍스트 및 메타데이터
+  AWS Glue 데이터 카탈로그 또는 기타 데이터 소스의 데이터

Amazon 직원만 데이터에 액세스할 수 있습니다. 사용자의 신뢰, 프라이버시 및 고객 콘텐츠 보안을 최우선으로 생각하며, 약속한 대로 데이터를 사용하도록 할 것입니다. 자세한 내용은 데이터 프라이버시 FAQ를 참조하세요.

## 옵트아웃 방법
<a name="how-to-opt-out"></a>

Apache Spark 에이전트의 데이터 수집을 옵트아웃하려면 AWS Organizations for Amazon SageMaker Unified Studio MCP Service에서 AI 서비스 옵트아웃 정책을 구성합니다. 자세한 내용은 *AWS 조직 사용 설명서*의 [AI 서비스 옵트아웃 정책](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_ai-opt-out.html)을 참조하세요.

AI 서비스 옵트아웃 정책을 구성하면 다음과 같은 효과가 있습니다.
+ AWS 는 옵트아웃 전에 서비스 개선을 위해 수집 및 저장된 데이터를 삭제합니다(있는 경우).
+ 옵트아웃한 후에는 AWS 가 더 이상이 데이터를 수집하거나 저장하지 않습니다.
+ AWS 는 더 이상 서비스 개선에 콘텐츠를 사용하지 않습니다.

# Spark 성능 최적화
<a name="emr-spark-performance"></a>

Amazon EMR은 Spark를 위한 여러 성능 최적화 성능을 제공합니다. 이 주제에서는 각 최적화 기능에 대해 자세히 설명합니다.

Spark 구성을 설정하는 방법에 대한 자세한 내용은 [Spark 구성](emr-spark-configure.md) 섹션을 참조하세요.

## 적응형 쿼리 실행
<a name="emr-spark-performance-aqe"></a>

적응형 쿼리 실행은 런타임 통계를 기반으로 쿼리 계획을 재최적화하기 위한 프레임워크입니다. Amazon EMR 5.30.0부터 Spark 2용 Apache Amazon EMR 런타임에서 Apache Spark 3의 다음과 같은 적응형 쿼리 실행 최적화를 사용할 수 있습니다.
+ 적응형 조인 변환
+ 셔플 파티션의 적응형 병합

**적응형 조인 변환**

적응형 조인 변환은 쿼리 스테이지의 런타임 크기에 따라 정렬-병합-조인 작업을 브로드캐스트-해시-조인 작업으로 변환하여 쿼리 성능을 개선합니다. 브로드캐스트-해시-조인은 조인의 한쪽이 출력을 모든 실행기에게 효율적으로 브로드캐스트할 수 있을 만큼 작은 경우 교환을 셔플하고 조인 양쪽을 모두 정렬할 필요가 없으므로 더 나은 성능을 지원합니다. 적응형 조인 변환은 Spark가 브로드캐스트-해시 조인을 자동으로 수행하는 경우 더 다양한 사례를 지원합니다.

이 기능은 기본적으로 활성화되어 있습니다. `spark.sql.adaptive.enabled`를 `false`로 설정하여 비활성화할 수 있으며, 이렇게 하면 적응형 쿼리 실행 프레임워크도 비활성화됩니다. Spark는 조인 측 중 하나의 런타임 크기 통계가 `spark.sql.autoBroadcastJoinThreshold`(기본값: 10,485,760바이트(10MiB))를 초과하지 않을 때 정렬-병합-조인을 브로드캐스트-해시-조인으로 변환하기로 결정합니다.

**셔플 파티션의 적응형 병합**

셔플 파티션의 적응형 병합은 작은 연속 셔플 파티션을 통합하여 작은 작업이 너무 많아서 발생하는 오버헤드를 방지함으로써 쿼리 성능을 개선합니다. 이렇게 하면 더 많은 수의 초기 셔플 파티션을 미리 구성한 다음, 런타임 시 목표 크기로 줄일 수 있으므로 셔플 파티션을 더 균등하게 분산할 가능성이 커집니다.

이 기능은 명시적으로 `spark.sql.shuffle.partitions`를 설정하지 않는 한 기본적으로 활성화되어 있습니다. `spark.sql.adaptive.coalescePartitions.enabled`를 `true`로 설정하여 활성화할 수 있습니다. 셔플 파티션의 초기 수와 목표 파티션 크기는 각각 `spark.sql.adaptive.coalescePartitions.minPartitionNum` 및 `spark.sql.adaptive.advisoryPartitionSizeInBytes` 속성을 사용하여 조정할 수 있습니다. 이 기능의 관련 Spark 속성에 대한 자세한 내용은 다음 테이블을 참조하세요.


**Spark 적응형 통합 파티션 속성**  

| 속성 | 기본값  | 설명 | 
| --- | --- | --- | 
|  `spark.sql.adaptive.coalescePartitions.enabled`  |  true(명시적으로 `spark.sql.shuffle.partitions`를 설정하지 않은 경우)  |  이 속성이 true이고 spark.sql.adaptive.enabled가 true인 경우 Spark는 목표 크기(`spark.sql.adaptive.advisoryPartitionSizeInBytes`에서 지정함)에 따라 작은 작업이 너무 많이 발생하지 않도록 연속 셔플 파티션을 병합합니다.  | 
|  `spark.sql.adaptive.advisoryPartitionSizeInBytes`  | 64MB |  병합 시 셔플 파티션의 권장 크기(바이트). 이 구성은 `spark.sql.adaptive.enabled` 및 `spark.sql.adaptive.coalescePartitions.enabled` 모두 `true`인 경우에만 유효합니다.  | 
|  `spark.sql.adaptive.coalescePartitions.minPartitionNum`  | 25 |  병합 후 셔플 파티션의 최소 수. 이 구성은 `spark.sql.adaptive.enabled` 및 `spark.sql.adaptive.coalescePartitions.enabled` 모두 `true`인 경우에만 유효합니다.  | 
|  `spark.sql.adaptive.coalescePartitions.initialPartitionNum`  | 1000 |  병합 전 셔플 파티션의 초기 수. 이 구성은 `spark.sql.adaptive.enabled` 및 `spark.sql.adaptive.coalescePartitions.enabled` 모두 `true`인 경우에만 유효합니다.  | 

## 동적 파티션 잘라내기
<a name="emr-spark-performance-dynamic"></a>

동적 파티션 잘라내기는 특정 쿼리를 위해 읽고 처리해야 하는 테이블 내 특정 파티션을 더 정확하게 선택하여 작업 성능을 향상시킵니다. 읽고 처리한 데이터의 양을 줄임으로써 작업 실행 시 상당한 시간이 절약됩니다. Amazon EMR 5.26.0의 경우 이 기능은 기본적으로 활성화되어 있습니다. Amazon EMR 5.24.0 및 5.25.0의 경우 Spark 내에서 또는 클러스터 생성 시 Spark 속성인 `spark.sql.dynamicPartitionPruning.enabled`를 설정하여 이 기능을 활성화할 수 있습니다.


**Spark 동적 파티션 정리 파티션 속성**  

| 속성 | 기본 값 | 설명 | 
| --- | --- | --- | 
|  `spark.sql.dynamicPartitionPruning.enabled`  |  `true`  |  true인 경우 동적 파티션 정리를 활성화합니다.  | 
|  `spark.sql.optimizer.dynamicPartitionPruning.enforceBroadcastReuse`  |  `true`  |  `true`인 경우 Spark는 쿼리 실행 전에 방어 검사를 수행하여 동적 정리 필터에서의 브로드캐스트 교환 재사용이 사용자 정의 열 기반 규칙과 같은 이후 준비 규칙에 의해 중단되지 않도록 합니다. 재사용이 중단되고 이 구성이 `true`인 경우 Spark는 영향을 받는 동적 정리 필터를 제거하여 성능을 보호하고 정확성 문제를 방지합니다. 동적 정리 필터의 브로드캐스트 교환 시 해당 조인 작업의 브로드캐스트 교환과 다른, 일관되지 않은 결과가 생성되는 경우 정확성 문제가 발생할 수 있습니다. 이 구성을 `false`로 설정할 때는 주의해야 합니다. 이렇게 하면 사용자 정의 열 기반 규칙에 의해 재사용이 중단되는 경우와 같은 시나리오를 해결할 수 있습니다. 적응형 쿼리 실행이 활성화되면 브로드캐스트 재사용이 항상 적용됩니다.  | 

이러한 최적화를 통해 계획 시간에 해결할 수 있는 정적 조건자를 푸시다운하는 것만 지원하는 Spark 2.4.2의 기존 기능보다 나은 결과를 얻을 수 있습니다.

다음은 Spark 2.4.2이 실행하는 정적 조건자 푸시다운의 예입니다.

```
partition_col = 5

partition_col IN (1,3,5)

partition_col between 1 and 3

partition_col = 1 + 3
```

동적 파티션 잘라내기를 통해 Spark 엔진은 읽어야 할 파티션과 안전하게 제거할 수 있는 파티션을 실행 시간에 동적으로 추론할 수 있습니다. 예를 들어, 다음 쿼리에는 두 가지 테이블이 수반됩니다. 즉 모든 스토어에 대해 총 매출 전체를 포함하고 리전에 따라 분할된 `store_sales` 테이블과 각 국가에 대해 리전 매핑을 포함하는 `store_regions` 테이블입니다. 테이블에는 전 세계에 분산된 스토어에 대한 데이터가 포함되어 있지만, 여기서는 북미에 대한 데이터만 쿼리합니다.

```
select ss.quarter, ss.region, ss.store, ss.total_sales 
from store_sales ss, store_regions sr
where ss.region = sr.region and sr.country = 'North America'
```

동적 파티션 잘라내기가 없으면 이 쿼리는 하위 쿼리의 결과와 일치하는 리전의 하위 집합을 필터링하기 전에 모든 리전을 읽습니다. 동적 파티션 잘라내기가 있는 경우 이 쿼리는 하위 쿼리에서 반환되는 리전에 대한 파티션만 읽고 처리합니다. 이를 통해 스토리지에서 더 적은 데이터를 읽고 더 적은 레코드를 처리함으로써 시간과 리소스를 절약합니다.

## 스칼라 하위 쿼리 평면화
<a name="emr-spark-performance-flatten"></a>

이 최적화를 통해 동일한 테이블에 대한 스칼라 하위 쿼리가 있는 쿼리의 성능이 향상됩니다. Amazon EMR 5.26.0의 경우 이 기능은 기본적으로 활성화되어 있습니다. Amazon EMR 5.24.0 및 5.25.0의 경우 Spark 내에서 또는 클러스터 생성 시 Spark 속성인 `spark.sql.optimizer.flattenScalarSubqueriesWithAggregates.enabled`를 설정하여 이 기능을 활성화할 수 있습니다. 이 속성을 true로 설정하면 이 쿼리 최적화 프로그램은 가능한 경우 동일한 관계를 사용하는 총 스칼라 하위 쿼리를 평면화합니다. 스칼라 하위 쿼리는 집계 함수에 대한 하위 쿼리에 있는 모든 조건자를 푸시한 후 관계당 모든 집계 함수로 한 가지 집계를 수행하는 방식으로 평면화됩니다.

다음은 이러한 최적화를 통해 이익을 얻을 쿼리의 샘플입니다.

```
select (select avg(age) from students                    /* Subquery 1 */
                 where age between 5 and 10) as group1,
       (select avg(age) from students                    /* Subquery 2 */
                 where age between 10 and 15) as group2,
       (select avg(age) from students                    /* Subquery 3 */
                 where age between 15 and 20) as group3
```

최적화를 통해 이전 쿼리는 다음과 같이 재작성됩니다.

```
select c1 as group1, c2 as group2, c3 as group3
from (select avg (if(age between 5 and 10, age, null)) as c1,
             avg (if(age between 10 and 15, age, null)) as c2,
             avg (if(age between 15 and 20, age, null)) as c3 from students);
```

재작성된 쿼리는 학생 테이블을 한 번만 읽고 세 가지 하위 쿼리의 조건자는 `avg` 함수로 푸시된다는 점에 유의하세요.

## INTERSECT에 앞선 DISTINCT
<a name="emr-spark-performance-distinct"></a>

이 최적화에서는 INTERSECT 사용 시 조인을 최적화합니다. Amazon EMR 5.26.0의 경우 이 기능은 기본적으로 활성화되어 있습니다. Amazon EMR 5.24.0 및 5.25.0의 경우 Spark 내에서 또는 클러스터 생성 시 Spark 속성인 `spark.sql.optimizer.distinctBeforeIntersect.enabled`를 설정하여 이 기능을 활성화할 수 있습니다. INTERSECT를 사용하는 쿼리는 자동으로 좌측 세미 조인을 사용하도록 자동 변환됩니다. 이 속성이 true로 설정된 경우 DISTINCT 연산자가 좌측 세미 조인을 SortMergeJoin이 아닌 BroadcastHashJoin으로 만들 수 있음을 감지한 쿼리 최적화 프로그램은 DISTINCT 연산자를 INTERSECT의 하위 항목으로 푸시합니다.

다음은 이러한 최적화를 통해 이익을 얻을 쿼리의 샘플입니다.

```
(select item.brand brand from store_sales, item
     where store_sales.item_id = item.item_id)
intersect
(select item.brand cs_brand from catalog_sales, item 
     where catalog_sales.item_id = item.item_id)
```

이 `spark.sql.optimizer.distinctBeforeIntersect.enabled` 속성을 활성화하지 않으면 쿼리는 다음과 같이 재작성됩니다.

```
select distinct brand from
  (select item.brand brand from store_sales, item
     where store_sales.item_id = item.item_id)
left semi join
   (select item.brand cs_brand from catalog_sales, item 
     where catalog_sales.item_id = item.item_id)
 on brand <=> cs_brand
```

이 `spark.sql.optimizer.distinctBeforeIntersect.enabled` 속성을 활성화하면 쿼리는 다음과 같이 재작성됩니다.

```
select brand from
  (select distinct item.brand brand from store_sales, item
     where store_sales.item_id = item.item_id)
left semi join
   (select distinct item.brand cs_brand from catalog_sales, item 
     where catalog_sales.item_id = item.item_id)
 on brand <=> cs_brand
```

## 블룸 필터 조인
<a name="emr-spark-performance-bloom"></a>

이러한 최적화는 조인의 다른 측면 값에서 생성된 [블룸 필터](https://en.wikipedia.org/wiki/Bloom_filter)를 사용해 조인의 한 측면을 사전 필터링하여 일부 조인의 성능을 향상시킬 수 있습니다. Amazon EMR 5.26.0의 경우 이 기능은 기본적으로 활성화되어 있습니다. Amazon EMR 5.25.0의 경우 Spark 내에서 또는 클러스터 생성 시 Spark 속성 `spark.sql.bloomFilterJoin.enabled`를 `true`로 설정하여 이 기능을 활성화할 수 있습니다.

다음은 블룸 필터를 활용할 수 있는 예제 쿼리입니다.

```
select count(*)
from sales, item
where sales.item_id = item.id
and item.category in (1, 10, 16)
```

이 기능을 사용할 때, 블룸 필터는 카테고리가 쿼리 처리되는 카테고리 세트에 있는 모든 항목 id들로 구축됩니다. 매출 테이블을 스캔하는 동안 블룸 필터를 사용해 어떤 매출이 블룸 필터에서 지정한 세트에서 분명 제외된 항목에 있는지 파악합니다. 따라서 이렇게 확인된 매출은 가능한 한 조기에 필터링될 수 있습니다.

## 최적화된 조인 재정렬
<a name="emr-spark-performance-join-reorder"></a>

이 최적화로 필터와 함께 테이블에 관여하는 조인들을 재정렬하여 쿼리 성능을 향상시킬 수 있습니다. Amazon EMR 5.26.0의 경우 이 기능은 기본적으로 활성화되어 있습니다. Amazon EMR 5.25.0의 경우 Spark 구성 파라미터 `spark.sql.optimizer.sizeBasedJoinReorder.enabled`를 true로 설정하여 이 기능을 활성화할 수 있습니다. Spark의 기본 동작은 쿼리에 기재된 대로 테이블을 왼쪽에서 오른쪽으로 조인하는 것입니다. 이러한 전략은 많이 사용하는 조인을 나중에 활용하기 위해 필터가 있는 소규모 조인을 우선 실행할 수 있는 기회를 놓칠 수 있습니다.

아래의 예시 쿼리는 한 국가의 모든 매장에 있는 모든 반환품을 보고합니다. 조인 재정렬을 최적화하지 않으면, Spark는 두 개의 대형 테이블인 `store_sales`와 `store_returns`를 우선 조인한 다음, 두 대형 테이블을 `store` 그리고 마지막으로 `item`과 조인합니다.

```
select ss.item_value, sr.return_date, s.name, i.desc, 
from store_sales ss, store_returns sr, store s, item i
where ss.id = sr.id and ss.store_id = s.id and ss.item_id = i.id
and s.country = 'USA'
```

최적화된 조인 재정렬을 활용해 Spark는 `store_sales`와 `store`를 우선 조인하는 데, 이는 `store`에 필터가 있으며 `store_returns` 및 `broadcastable`보다 소규모이기 때문입니다. 그런 다음 Spark는 `store_returns`와 조인한 뒤 마지막으로 `item`와 조인합니다. `item` 에 필터가 있고 브로드캐스팅할 수 있다면, 재정렬에 적격하며 `store_sales`를 `store`와, 그리고 `item`, 또 결국 `store_returns`와 조인하게 됩니다.

# Spark 결과 조각 캐싱
<a name="emr-spark-fragment-result-caching"></a>

Amazon EMR 6.6.0 이상에는 결과 조각을 자동으로 캐싱하는 선택적 Spark 결과 조각 캐싱 기능이 포함되어 있습니다. 이러한 결과 조각은 선택한 Amazon S3 버킷에 저장된 쿼리 하위 트리에서 얻은 결과의 일부입니다. 저장된 쿼리 결과 조각은 후속 쿼리 실행 시 재사용되므로 쿼리 속도가 빨라집니다.

결과 조각 캐싱은 Spark 쿼리를 분석하고 지정된 S3 위치에 적합한 결과 조각을 캐싱합니다. 후속 쿼리 실행 시 사용 가능한 쿼리 결과 조각을 자동으로 감지하여 S3에서 가져옵니다. 결과 조각 캐싱은 후속 쿼리가 원래 쿼리와 정확히 일치해야 캐시에서 결과를 반환하는 결과 세트 캐싱과 다릅니다. 데이터의 정적 하위 세트를 반복적으로 대상으로 하는 쿼리에 사용할 경우 결과 조각 캐싱은 성능을 크게 개선합니다.

2022년까지 주문을 집계하는 다음 쿼리를 고려합니다.

```
select
    l_returnflag,
    l_linestatus,
    count(*) as count_order
from
    lineitem
where
    l_shipdate <= current_date
    and year(l_shipdate) == '2022'
group by
    l_returnflag,
    l_linestatus
```

시간이 지남에 따라 이 쿼리를 매일 실행하여 해당 연도의 총 판매를 보고해야 합니다. 결과 조각 캐싱을 사용하지 않으면 해당 연도의 모든 날짜에 대한 결과를 매일 다시 계산해야 합니다. 쿼리 속도는 시간이 지날수록 느려지고 365일 분량의 결과를 모두 다시 계산해야 하는 연말에는 속도가 가장 느려집니다.

 결과 조각 캐싱을 활성화하면 캐시에 있는 해당 연도의 모든 이전 날짜에 대한 결과를 사용합니다. 이 기능은 매일 하루의 결과만 다시 계산하면 됩니다. 기능이 결과 조각을 계산한 후 해당 조각을 캐싱합니다. 따라서 캐시를 사용하는 쿼리 시간이 빨라지고 후속 쿼리마다 일정한 시간이 유지됩니다.

## Spark 결과 조각 캐싱 활성화
<a name="enable-fragment-caching"></a>

Spark 결과 조각 캐싱을 활성화하려면 다음 단계를 수행합니다.

1. Amazon S3에 캐시 버킷을 생성하고 EMRFS에 대한 읽기 및 쓰기 액세스를 승인합니다. 자세한 내용은 [Amazon S3에서 EMRFS 데이터에 대한 액세스 권한 부여](emr-plan-credentialsprovider.md) 단원을 참조하십시오.

1. 기능을 활성화하려면 Amazon EMR Spark 구성을 설정합니다.

   ```
   spark.subResultCache.enabled = true
   spark.subResultCache.fs.root.path = s3://&example-s3-bucket;/cache_dir/
   ```

1. 버킷의 S3 수명 주기 관리를 활성화하여 캐시 파일을 자동으로 정리합니다.

1. 선택적으로 reductionRationThreshold 및 maxBufferSize 속성을 구성하여 기능을 추가로 조정합니다.

   ```
   spark.sql.subResultCache.reductionRatioThreshold
   spark.sql.subResultCache.maxBufferSize
   ```

## 결과 조각 캐싱 사용 시 고려 사항
<a name="frag-caching-considerations"></a>

다시 계산하는 대신 Amazon S3에 이미 캐시된 결과를 사용할 경우 동일한 캐시된 결과를 사용할 수 있는 횟수만큼 비용 절감 효과가 커집니다. 대형 테이블을 스캔한 후 결과 크기를 8배 이상 줄이는 필터 또는 해시 집계(즉, 입력 크기 대 결과의 비율이 8:1 이상인 경우)를 사용하는 쿼리에서는 이 기능을 최대한 활용할 수 있습니다. 입력과 결과 간의 감소 비율이 클수록 비용상의 이점도 커집니다. 감소 비율은 작지만 테이블 스캔과 필터 또는 집계 사이에 비용이 많이 드는 계산 단계가 포함된 쿼리도 결과를 생성하는 데 드는 비용이 Amazon S3에서 결과를 가져오는 데 드는 비용보다 큰 경우 비용이 절감됩니다. 기본적으로 결과 조각 캐싱은 감소 비율이 8:1 이상일 것으로 감지되는 경우에만 유효합니다.

쿼리가 캐시된 결과를 반복적으로 재사용하는 경우 이 기능의 이점이 가장 큽니다. 롤링 및 증분 기간 쿼리가 좋은 예입니다. 예를 들어, 이미 29일 동안 실행된 30일의 롤링 기간 쿼리는 원래 입력 소스에서 대상 데이터의 1/30만 가져오면 되고 이전 29일 동안 캐시된 결과 조각을 사용합니다. 증분 기간 쿼리는 기간의 시작 위치가 고정되어 있기 때문에 훨씬 더 유용합니다. 쿼리를 간접 호출할 때마다 입력 소스에서 읽어야 하는 처리 비율이 줄어듭니다.

결과 조각 캐싱을 사용할 때 고려해야 할 추가 사항은 다음과 같습니다.
+ 동일한 쿼리 조각을 포함하는 동일한 데이터를 대상으로 하지 않는 쿼리는 캐시 적중률이 낮으므로 이 기능을 활용할 수 없습니다.
+ 비용이 많이 드는 계산 단계를 포함하지 않고 감소 비율이 낮은 쿼리에서는 캐시된 결과에서는 처음에 처리할 때와 읽기 비용이 거의 같습니다.
+ 캐시에 쓰는 데 드는 비용 때문에 첫 번째 쿼리에서는 항상 약간의 회귀가 나타납니다.
+ 결과 조각 캐싱 기능은 Parquet 파일에서만 작동합니다. 다른 파일 형식은 지원되지 않습니다.
+ 결과 조각 캐싱 기능 버퍼는 파일 분할 크기가 128MB 이상인 스캔만 캐시하려고 시도합니다. 기본 Spark 구성에서 스캔 크기(스캔 중인 모든 파일의 총 크기)를 실행기 코어 수로 나눈 값이 128MB 미만이면 결과 조각 캐싱이 비활성화됩니다. 아래 나열된 Spark 구성 중 하나를 설정하는 경우 파일 분할 크기는 다음과 같습니다.

  ```
  min(maxPartitionBytes, max(openCostInBytes, scan size / minPartitionNum))
  ```
  + spark.sql.leafNodeDefaultParallelism(기본값: spark.default.parallelism)
  + spark.sql.files.minPartitionNum(기본값: spark.sql.leafNodeDefaultParallelism)
  + spark.sql.files.openCostInBytes
  + spark.sql.files.maxPartitionBytes
+ 결과 조각 캐싱 기능은 RDD 파티션 단위로 캐싱합니다. 앞에서 설명한 감소 비율(기본값 8:1)이 RDD 파티션별로 평가됩니다. RDD당 감소 비율이 8:1보다 크거나 작은 워크로드는 RDD당 감소 비율이 지속적으로 8:1 미만인 워크로드보다 성능상의 이점이 적을 수 있습니다.
+ 결과 조각 캐싱 기능은 캐시되는 각 RDD 파티션에 대해 기본적으로 16MB 쓰기 버퍼를 사용합니다. RDD 파티션당 16MB가 넘게 캐시될 경우 쓰기 불가능 여부를 판단하는 데 드는 비용으로 인해 성능이 저하될 수 있습니다.
+ 기본적으로 결과 조각 캐싱은 감소 비율이 8:1 미만인 RDD 파티션 결과를 캐시하려고 시도하지 않으며, 쓰기 버퍼를 16MB로 제한하지만 다음 구성을 통해 이 두 값을 모두 조정할 수 있습니다.

  ```
  spark.sql.subResultCache.reductionRatioThreshold (default: 8.0)
  spark.sql.subResultCache.maxBufferSize (default: 16MB, max: 64MB)
  ```
+ 동일한 Amazon EMR 릴리스를 사용하는 여러 클러스터는 동일한 캐시 위치를 공유할 수 있습니다. 결과의 정확성을 보장하기 위해 결과 조각 캐싱은 여러 Amazon EMR 릴리스에서 작성된 캐시 결과를 사용하지 않습니다.
+ 결과 조각 캐싱은 Spark 스트리밍 사용 사례 또는 RecordServer, Apache Ranger 또는가 사용되는 경우 자동으로 비활성화 AWS Lake Formation 됩니다.
+ 결과 조각 캐시 읽기 및 쓰기는 EMRFS / S3A 및 Amazon S3 버킷을 사용합니다. CSE(EMRFS와 함께만 사용 가능), SSE S3, SSE KMS 암호화가 지원됩니다. 맥락을 설명하자면, S3A는 클러스터가 Amazon S3에서 데이터를 읽고 쓸 수 있도록 Hadoop 구현을 제공합니다. S3A에 대한 지원은 EMR-7.4.0 이상에서 사용할 수 있습니다.

# Apache Spark용 Nvidia RAPIDS 액셀러레이터 사용
<a name="emr-spark-rapids"></a>

Amazon EMR 릴리스 6.2.0 이상에서는 Nvidia의 [Apache Spark용 RAPIDS 액셀러레이터](https://docs.nvidia.com/spark-rapids/user-guide/latest/overview.html) 플러그인을 통해 EC2 그래픽 처리 장치(GPU) 인스턴스 유형을 사용하여 Spark를 가속화할 수 있습니다. RAPIDS Accelerator는 코드 변경 없이 Apache Spark 3.0 데이터 과학 파이프라인에서 GPU를 가속화하고, 데이터 처리 및 모델 교육 속도를 높이는 동시에 인프라 비용을 크게 절감합니다.

다음 섹션에서는 Spark용 Spark RAPIDS 플러그인을 사용하도록 EMR 클러스터를 구성하는 방법을 안내합니다.

## 인스턴스 유형 선택
<a name="emr-spark-rapids-instancetypes"></a>

Spark용 Nvidia Spark RAPIDS 플러그인을 사용하려면 코어 및 태스크 인스턴스 그룹에서 Spark-RAPIDS의 [하드웨어 요구 사항](https://nvidia.github.io/spark-rapids/)을 충족하는 EC2 GPU 인스턴스 유형을 사용해야 합니다. Amazon EMR에서 지원되는 GPU 인스턴스 유형의 전체 목록을 보려면 *Amazon EMR 관리 안내서*에서 [지원되는 인스턴스 유형](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-supported-instance-types.html)을 참조하세요. 기본 인스턴스 그룹의 인스턴스 유형은 GPU 또는 비GPU 유형일 수 있지만 ARM 인스턴스 유형은 지원되지 않습니다.

## 클러스터의 애플리케이션 구성 설정
<a name="emr-spark-rapids-appconfig"></a>

**1: Amazon EMR을 활성화하여 새 클러스터에 플러그인 설치**

플러그인을 설치하려면 클러스터를 생성할 때 다음 구성을 제공합니다.

```
{
	"Classification":"spark",
	"Properties":{
		"enableSparkRapids":"true"
	}
}
```

**2. GPU를 사용하도록 YARN 구성**

YARN 기반 GPU를 사용하는 방법에 대한 자세한 내용은 Apache Hadoop 설명서에서 [YARN에서 GPU 사용](https://hadoop.apache.org/docs/r3.2.1/hadoop-yarn/hadoop-yarn-site/UsingGpus.html)을 참조하세요. 다음 예에서는 Amazon EMR 6.x 및 7.x 릴리스를 위한 샘플 YARN 구성을 보여줍니다.

------
#### [ Amazon EMR 7.x ]

**Amazon EMR 7.x용 YARN 구성 예제**

```
{
    "Classification":"yarn-site",
    "Properties":{
        "yarn.nodemanager.resource-plugins":"yarn.io/gpu",
        "yarn.resource-types":"yarn.io/gpu",
        "yarn.nodemanager.resource-plugins.gpu.allowed-gpu-devices":"auto",
        "yarn.nodemanager.resource-plugins.gpu.path-to-discovery-executables":"/usr/bin",
        "yarn.nodemanager.linux-container-executor.cgroups.mount":"true",
        "yarn.nodemanager.linux-container-executor.cgroups.mount-path":"/spark-rapids-cgroup",
        "yarn.nodemanager.linux-container-executor.cgroups.hierarchy":"yarn",
        "yarn.nodemanager.container-executor.class":"org.apache.hadoop.yarn.server.nodemanager.LinuxContainerExecutor"
    }
},{
    "Classification":"container-executor",
    "Properties":{
        
    },
    "Configurations":[
        {
            "Classification":"gpu",
            "Properties":{
                "module.enabled":"true"
            }
        },
        {
            "Classification":"cgroups",
            "Properties":{
                "root":"/spark-rapids-cgroup",
                "yarn-hierarchy":"yarn"
            }
        }
    ]
}
```

------
#### [ Amazon EMR 6.x ]

**Amazon EMR 6.x용 YARN 구성 예제**

```
{
    "Classification":"yarn-site",
    "Properties":{
        "yarn.nodemanager.resource-plugins":"yarn.io/gpu",
        "yarn.resource-types":"yarn.io/gpu",
        "yarn.nodemanager.resource-plugins.gpu.allowed-gpu-devices":"auto",
        "yarn.nodemanager.resource-plugins.gpu.path-to-discovery-executables":"/usr/bin",
        "yarn.nodemanager.linux-container-executor.cgroups.mount":"true",
        "yarn.nodemanager.linux-container-executor.cgroups.mount-path":"/sys/fs/cgroup",
        "yarn.nodemanager.linux-container-executor.cgroups.hierarchy":"yarn",
        "yarn.nodemanager.container-executor.class":"org.apache.hadoop.yarn.server.nodemanager.LinuxContainerExecutor"
    }
},{
    "Classification":"container-executor",
    "Properties":{
        
    },
    "Configurations":[
        {
            "Classification":"gpu",
            "Properties":{
                "module.enabled":"true"
            }
        },
        {
            "Classification":"cgroups",
            "Properties":{
                "root":"/sys/fs/cgroup",
                "yarn-hierarchy":"yarn"
            }
        }
    ]
}
```

------

**3. RAPIDS를 사용하도록 Spark 구성**

Spark에서 RAPIDS 플러그인을 사용하려면 다음 구성이 필요합니다.

```
{
	"Classification":"spark-defaults",
	"Properties":{
		"spark.plugins":"com.nvidia.spark.SQLPlugin",
		"spark.executor.resource.gpu.discoveryScript":"/usr/lib/spark/scripts/gpu/getGpusResources.sh",
		"spark.executor.extraLibraryPath":"/usr/local/cuda/targets/x86_64-linux/lib:/usr/local/cuda/extras/CUPTI/lib64:/usr/local/cuda/compat/lib:/usr/local/cuda/lib:/usr/local/cuda/lib64:/usr/lib/hadoop/lib/native:/usr/lib/hadoop-lzo/lib/native:/docker/usr/lib/hadoop/lib/native:/docker/usr/lib/hadoop-lzo/lib/native"
	}
}
```

XGBoost 설명서의 [XGBoost4J-Spark 라이브러리](https://xgboost.readthedocs.io/en/latest/jvm/xgboost4j_spark_tutorial.html)는 클러스터에서 Spark RAPIDS 플러그인이 활성화된 경우에도 사용할 수 있습니다. 다음 구성을 사용하여 XGBoost를 Spark 작업과 통합할 수 있습니다.

```
{
	"Classification":"spark-defaults",
	"Properties":{
		"spark.submit.pyFiles":"/usr/lib/spark/jars/xgboost4j-spark_3.0-1.4.2-0.3.0.jar"
	}
}
```

GPU 가속 EMR 클러스터를 튜닝하는 데 사용할 수 있는 추가 Spark 구성은 Nvidia.github.io 설명서에서 [Rapids Accelerator for Apache Spark 튜닝 안내서](https://docs.nvidia.com/spark-rapids/user-guide/latest/tuning-guide.html)를 참조하세요.

**4. YARN 용량 스케줄러 구성**

GPU 예약 및 격리를 활성화하도록 `DominantResourceCalculator`를 구성해야 합니다. 자세한 내용은 Apache Hadoop 설명서에서 [Using GPU on YARN](https://hadoop.apache.org/docs/r3.2.1/hadoop-yarn/hadoop-yarn-site/UsingGpus.html)을 참조하세요.

```
{
	"Classification":"capacity-scheduler",
	"Properties":{
		"yarn.scheduler.capacity.resource-calculator":"org.apache.hadoop.yarn.util.resource.DominantResourceCalculator"
	}
}
```

**5. 구성을 포함하도록 JSON 파일 생성**

Spark 클러스터용 RAPIDS 플러그인을 사용하기 위한 구성이 포함된 JSON 파일을 생성할 수 있습니다. 나중에 클러스터를 시작할 때 파일을 제공합니다.

파일을 로컬 또는 S3에 저장할 수 있습니다. 클러스터에 애플리케이션 구성을 제공하는 방법에 대한 자세한 내용은 [애플리케이션 구성](emr-configure-apps.md) 섹션을 참조하세요.

다음 샘플 파일을 템플릿으로 사용하고 고유한 구성을 만드세요.

------
#### [ Amazon EMR 7.x ]

**Amazon EMR 7.x용 예제 `my-configurations.json` 파일**

```
[
    {
        "Classification":"spark",
        "Properties":{
            "enableSparkRapids":"true"
        }
    },
    {
        "Classification":"yarn-site",
        "Properties":{
            "yarn.nodemanager.resource-plugins":"yarn.io/gpu",
            "yarn.resource-types":"yarn.io/gpu",
            "yarn.nodemanager.resource-plugins.gpu.allowed-gpu-devices":"auto",
            "yarn.nodemanager.resource-plugins.gpu.path-to-discovery-executables":"/usr/bin",
            "yarn.nodemanager.linux-container-executor.cgroups.mount":"true",
            "yarn.nodemanager.linux-container-executor.cgroups.mount-path":"/spark-rapids-cgroup",
            "yarn.nodemanager.linux-container-executor.cgroups.hierarchy":"yarn",
            "yarn.nodemanager.container-executor.class":"org.apache.hadoop.yarn.server.nodemanager.LinuxContainerExecutor"
        }
    },
    {
        "Classification":"container-executor",
        "Properties":{
            
        },
        "Configurations":[
            {
                "Classification":"gpu",
                "Properties":{
                    "module.enabled":"true"
                }
            },
            {
                "Classification":"cgroups",
                "Properties":{
                    "root":"/spark-rapids-cgroup",
                    "yarn-hierarchy":"yarn"
                }
            }
        ]
    },
    {
        "Classification":"spark-defaults",
        "Properties":{
            "spark.plugins":"com.nvidia.spark.SQLPlugin",
            "spark.executor.resource.gpu.discoveryScript":"/usr/lib/spark/scripts/gpu/getGpusResources.sh",
            "spark.executor.extraLibraryPath":"/usr/local/cuda/targets/x86_64-linux/lib:/usr/local/cuda/extras/CUPTI/lib64:/usr/local/cuda/compat/lib:/usr/local/cuda/lib:/usr/local/cuda/lib64:/usr/lib/hadoop/lib/native:/usr/lib/hadoop-lzo/lib/native:/docker/usr/lib/hadoop/lib/native:/docker/usr/lib/hadoop-lzo/lib/native",
            "spark.submit.pyFiles":"/usr/lib/spark/jars/xgboost4j-spark_3.0-1.4.2-0.3.0.jar",
            "spark.rapids.sql.concurrentGpuTasks":"1",
            "spark.executor.resource.gpu.amount":"1",
            "spark.executor.cores":"2",
            "spark.task.cpus":"1",
            "spark.task.resource.gpu.amount":"0.5",
            "spark.rapids.memory.pinnedPool.size":"0",
            "spark.executor.memoryOverhead":"2G",
            "spark.locality.wait":"0s",
            "spark.sql.shuffle.partitions":"200",
            "spark.sql.files.maxPartitionBytes":"512m"
        }
    },
    {
        "Classification":"capacity-scheduler",
        "Properties":{
            "yarn.scheduler.capacity.resource-calculator":"org.apache.hadoop.yarn.util.resource.DominantResourceCalculator"
        }
    }
]
```

------
#### [ Amazon EMR 6.x ]

**Amazon EMR 6.x용 예제 `my-configurations.json` 파일**

```
[
    {
        "Classification":"spark",
        "Properties":{
            "enableSparkRapids":"true"
        }
    },
    {
        "Classification":"yarn-site",
        "Properties":{
            "yarn.nodemanager.resource-plugins":"yarn.io/gpu",
            "yarn.resource-types":"yarn.io/gpu",
            "yarn.nodemanager.resource-plugins.gpu.allowed-gpu-devices":"auto",
            "yarn.nodemanager.resource-plugins.gpu.path-to-discovery-executables":"/usr/bin",
            "yarn.nodemanager.linux-container-executor.cgroups.mount":"true",
            "yarn.nodemanager.linux-container-executor.cgroups.mount-path":"/sys/fs/cgroup",
            "yarn.nodemanager.linux-container-executor.cgroups.hierarchy":"yarn",
            "yarn.nodemanager.container-executor.class":"org.apache.hadoop.yarn.server.nodemanager.LinuxContainerExecutor"
        }
    },
    {
        "Classification":"container-executor",
        "Properties":{
            
        },
        "Configurations":[
            {
                "Classification":"gpu",
                "Properties":{
                    "module.enabled":"true"
                }
            },
            {
                "Classification":"cgroups",
                "Properties":{
                    "root":"/sys/fs/cgroup",
                    "yarn-hierarchy":"yarn"
                }
            }
        ]
    },
    {
        "Classification":"spark-defaults",
        "Properties":{
            "spark.plugins":"com.nvidia.spark.SQLPlugin",
            "spark.executor.resource.gpu.discoveryScript":"/usr/lib/spark/scripts/gpu/getGpusResources.sh",
            "spark.executor.extraLibraryPath":"/usr/local/cuda/targets/x86_64-linux/lib:/usr/local/cuda/extras/CUPTI/lib64:/usr/local/cuda/compat/lib:/usr/local/cuda/lib:/usr/local/cuda/lib64:/usr/lib/hadoop/lib/native:/usr/lib/hadoop-lzo/lib/native:/docker/usr/lib/hadoop/lib/native:/docker/usr/lib/hadoop-lzo/lib/native",
            "spark.submit.pyFiles":"/usr/lib/spark/jars/xgboost4j-spark_3.0-1.4.2-0.3.0.jar",
            "spark.rapids.sql.concurrentGpuTasks":"1",
            "spark.executor.resource.gpu.amount":"1",
            "spark.executor.cores":"2",
            "spark.task.cpus":"1",
            "spark.task.resource.gpu.amount":"0.5",
            "spark.rapids.memory.pinnedPool.size":"0",
            "spark.executor.memoryOverhead":"2G",
            "spark.locality.wait":"0s",
            "spark.sql.shuffle.partitions":"200",
            "spark.sql.files.maxPartitionBytes":"512m"
        }
    },
    {
        "Classification":"capacity-scheduler",
        "Properties":{
            "yarn.scheduler.capacity.resource-calculator":"org.apache.hadoop.yarn.util.resource.DominantResourceCalculator"
        }
    }
]
```

------

## 클러스터에 대한 부트스트랩 작업 추가
<a name="emr-spark-rapids-bootstrap"></a>

클러스터를 생성할 때 부트스트랩 작업 스크립트를 제공하는 방법에 대한 자세한 내용은 *Amazon EMR 관리 안내서*에서 [부트스트랩 작업 기본 사항](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-plan-bootstrap.html#bootstrapUses)을 참조하세요.

다음 예제 스크립트에서는 Amazon EMR 6.x 및 7.x용 부트스트랩 작업 파일을 만드는 방법을 확인할 수 있습니다.

------
#### [ Amazon EMR 7.x ]

**Amazon EMR 7.x용 예제 `my-bootstrap-action.sh` 파일**

YARN을 사용하여 Amazon EMR 7.x 릴리스에서 GPU 리소스를 관리하기 위해서는 클러스터에 CGroup v1을 수동으로 마운트해야 합니다. 이 예제처럼 부트스트랩 작업 스크립트를 이용하여 이 작업을 할 수 있습니다.

```
#!/bin/bash
set -ex
 
sudo mkdir -p /spark-rapids-cgroup/devices
sudo mount -t cgroup -o devices cgroupv1-devices /spark-rapids-cgroup/devices
sudo chmod a+rwx -R /spark-rapids-cgroup
```

------
#### [ Amazon EMR 6.x ]

**Amazon EMR 6.x용 예제 `my-bootstrap-action.sh` 파일**

Amazon EMR 6.x 릴리스의 경우에는 클러스터에서 YARN에 대한 CGroup 권한을 열어야 합니다. 이 예제처럼 부트스트랩 작업 스크립트를 이용하여 이 작업을 할 수 있습니다.

```
#!/bin/bash
set -ex
 
sudo chmod a+rwx -R /sys/fs/cgroup/cpu,cpuacct
sudo chmod a+rwx -R /sys/fs/cgroup/devices
```

------

## 클러스터 시작
<a name="emr-spark-rapids-launchcluster"></a>

마지막 단계는 위에서 언급한 클러스터 구성으로 클러스터를 시작하는 것입니다. 다음은 Amazon EMR CLI에서 클러스터를 시작하는 예제 명령입니다.

```
 aws emr create-cluster \
--release-label emr-7.12.0 \
--applications Name=Hadoop Name=Spark \
--service-role EMR_DefaultRole_V2 \
--ec2-attributes KeyName=my-key-pair,InstanceProfile=EMR_EC2_DefaultRole \
--instance-groups InstanceGroupType=MASTER,InstanceCount=1,InstanceType=m4.4xlarge \                 
                  InstanceGroupType=CORE,InstanceCount=1,InstanceType=g4dn.2xlarge \    
                  InstanceGroupType=TASK,InstanceCount=1,InstanceType=g4dn.2xlarge \
--configurations file:///my-configurations.json \
--bootstrap-actions Name='My Spark Rapids Bootstrap action',Path=s3://amzn-s3-demo-bucket/my-bootstrap-action.sh
```

# Spark 쉘에 액세스
<a name="emr-spark-shell"></a>

Spark 쉘은 Scala REPL (Read-Eval-Print-Loop)을 기반으로 합니다. Scala REPL을 사용하면 Spark 프로그램을 대화식으로 생성하고 작업을 프레임워크로 제출할 수 있습니다. 프라이머리 노드를 SSH에 연결하고 `spark-shell`을 간접 호출하여 Spark 쉘에 액세스할 수 있습니다. SSH를 사용하여 프라이머리 노드에 연결하는 방법에 대한 자세한 내용은 *Amazon EMR 관리 안내서*에서 [SSH를 사용하여 프라이머리 노드에 연결](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-connect-master-node-ssh.html)을 참조하세요. 다음 예제에서는 Amazon S3에 저장된 Apache HTTP Server 액세스 로그가 사용됩니다.

**참고**  
이러한 예제의 Amazon 버킷은 미국 동부(버지니아 북부)에 액세스할 수 있는 클라이언트에서 사용 가능합니다.

 기본적으로 Spark 쉘은 `sc`라는 자체 [SparkContext](https://spark.apache.org/docs/1.3.1/api/scala/index.html#org.apache.spark.SparkContext) 객체를 생성합니다. REPL 내에서 필요한 경우 이 컨텍스트를 사용할 수 있습니다. 또한 sqlContext도 이 쉘에서 사용할 수 있으며, [HiveContext](https://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.sql.hive.HiveContext)입니다.

**Example Spark 쉘을 사용하여 Amazon S3에 저장된 파일에서 특정 문자열의 발생 개수 계산**  
이 예제에서는 `sc`를 사용하여 Amazon S3에 저장된 텍스트 파일을 읽습니다.  

```
scala> sc
res0: org.apache.spark.SparkContext = org.apache.spark.SparkContext@404721db

scala> val textFile = sc.textFile("s3://elasticmapreduce/samples/hive-ads/tables/impressions/dt=2009-04-13-08-05/ec2-0-51-75-39.amazon.com.rproxy.govskope.us-2009-04-13-08-05.log")
```
Spark에서 textFile 및 관련 [데이터 구조](https://spark.apache.org/docs/latest/programming-guide.html#resilient-distributed-datasets-rdds)가 생성됩니다. 그 다음, 이 예제는 로그 파일에서 "cartoonnetwork.com" 문자열이 나오는 행 수를 셉니다.  

```
scala> val linesWithCartoonNetwork = textFile.filter(line => line.contains("cartoonnetwork.com")).count()
linesWithCartoonNetwork: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[2] at filter at <console>:23
<snip>
<Spark program runs>
scala> linesWithCartoonNetwork
res2: Long = 9
```

**Example Python 기반 Spark 쉘을 사용하여 Amazon S3에 저장된 파일에서 특정 문자열의 발생 개수 계산**  
Spark에는 Python 기반 셸인 `pyspark`도 포함되어 있으며, 이 셸을 사용하여 Python에서 작성된 Spark 프로그램을 시제품화할 수 있습니다. `spark-shell`과 마찬가지로, 프라이머리 노드에서 `pyspark`를 간접 호출합니다. 이 쉘에도 동일한 [SparkContext](https://spark.apache.org/docs/latest/api/python/reference/api/pyspark.SparkContext.html#pyspark.SparkContext) 객체가 있습니다.  

```
>>> sc
<pyspark.context.SparkContext object at 0x7fe7e659fa50>
>>> textfile = sc.textFile("s3://elasticmapreduce/samples/hive-ads/tables/impressions/dt=2009-04-13-08-05/ec2-0-51-75-39.amazon.com.rproxy.govskope.us-2009-04-13-08-05.log")
```
Spark에서 textFile 및 관련 [데이터 구조](https://spark.apache.org/docs/latest/programming-guide.html#resilient-distributed-datasets-rdds)가 생성됩니다. 그 다음, 이 예제는 로그 파일에서 "cartoonnetwork.com" 문자열이 나오는 행 수를 셉니다.  

```
>>> linesWithCartoonNetwork = textfile.filter(lambda line: "cartoonnetwork.com" in line).count()
15/06/04 17:12:22 INFO lzo.GPLNativeCodeLoader: Loaded native gpl library from the embedded binaries
15/06/04 17:12:22 INFO lzo.LzoCodec: Successfully loaded & initialized native-lzo library [hadoop-lzo rev EXAMPLE]
15/06/04 17:12:23 INFO fs.EmrFileSystem: Consistency disabled, using com.amazon.ws.emr.hadoop.fs.s3n.S3NativeFileSystem as filesystem implementation
<snip>
<Spark program continues>
>>> linesWithCartoonNetwork
9
```

# 기계 학습에 Amazon SageMaker Spark 사용
<a name="emr-spark-sagemaker"></a>

Amazon EMR 릴리스 5.11.0 이상을 사용하면 Spark와 함께 `aws-sagemaker-spark-sdk` 구성 요소가 설치됩니다. 이 구성 요소는 Amazon SageMaker Spark 및 Spark와 [Amazon SageMaker](https://aws.amazon.com/sagemaker/)의 통합을 위한 관련 종속성을 설치합니다. Amazon EMR 7.x 이상에서는 `aws-sagemaker-spark-sdk` 구성 요소를 사용할 수 없습니다. Amazon SageMaker Spark를 사용하면 Amazon SageMaker 단계를 사용하여 Spark 기계 학습(ML) 파이프라인을 생성할 수 있습니다. 자세한 내용은 GitHub에서 [Amazon SageMaker Spark README](https://github.com/aws/sagemaker-spark/blob/master/README.md)와 [Amazon SageMaker 개발자 안내서](https://docs.aws.amazon.com/sagemaker/latest/dg/apache-spark.html)에서 *Using Apache Spark with Amazon SageMaker*를 참조하세요.

# Spark 애플리케이션 작성
<a name="emr-spark-application"></a>

[Spark](https://aws.amazon.com/big-data/what-is-spark/) 애플리케이션은 Scala, Java, 또는 Python으로 작성할 수 있습니다. Apache Spark 설명서에서 [Spark examples](https://spark.apache.org/examples.html) 주제에 여러 Spark 애플리케이션 예제가 있습니다. 아래에는 기본적으로 지원되는 세 가지 애플리케이션 중 Estimating Pi 예제가 표시되어 있습니다. 또한 `$SPARK_HOME/examples` 및 [GitHub](https://github.com/apache/spark/tree/master/examples/src/main)에서 전체 예제를 볼 수 있습니다. Spark용 JAR 빌드 방법에 대한 자세한 내용은 Apache Spark 문서에서 [Quick Start](https://spark.apache.org/docs/latest/quick-start.html) 주제를 참조하세요.

## Scala
<a name="emr-spark-application-scala"></a>

Scala 호환성 문제를 방지하려면 Amazon EMR 클러스터용 Spark 애플리케이션을 컴파일할 때 올바른 Scala 버전에 대한 Spark 종속성을 사용하는 것이 좋습니다. 사용해야 하는 Scala 버전은 클러스터에 설치된 Spark 버전에 따라 다릅니다. 예를 들어, Amazon EMR 릴리스 5.30.1은 Scala 2.11과 함께 빌드된 Spark 2.4.5를 사용합니다. 클러스터에서 Amazon EMR 릴리스 5.30.1을 사용하는 경우 Scala 2.11의 Spark 종속성을 사용합니다. Spark에서 사용하는 Scala 버전에 대한 자세한 내용은 [Apache Spark 설명서](https://spark.apache.org/documentation.html)를 참조하세요.

```
package org.apache.spark.examples
import scala.math.random
import org.apache.spark._

/** Computes an approximation to pi */
object SparkPi {
  def main(args: Array[String]) {
    val conf = new SparkConf().setAppName("Spark Pi")
    val spark = new SparkContext(conf)
    val slices = if (args.length > 0) args(0).toInt else 2
    val n = math.min(100000L * slices, Int.MaxValue).toInt // avoid overflow
    val count = spark.parallelize(1 until n, slices).map { i =>
      val x = random * 2 - 1
      val y = random * 2 - 1
      if (x*x + y*y < 1) 1 else 0
    }.reduce(_ + _)
    println("Pi is roughly " + 4.0 * count / n)
    spark.stop()
  }
}
```

## Java
<a name="emr-spark-application-java"></a>

```
package org.apache.spark.examples;

import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.Function;
import org.apache.spark.api.java.function.Function2;

import java.util.ArrayList;
import java.util.List;

/** 
 * Computes an approximation to pi
 * Usage: JavaSparkPi [slices]
 */
public final class JavaSparkPi {

  public static void main(String[] args) throws Exception {
    SparkConf sparkConf = new SparkConf().setAppName("JavaSparkPi");
    JavaSparkContext jsc = new JavaSparkContext(sparkConf);

    int slices = (args.length == 1) ? Integer.parseInt(args[0]) : 2;
    int n = 100000 * slices;
    List<Integer> l = new ArrayList<Integer>(n);
    for (int i = 0; i < n; i++) {
      l.add(i);
    }

    JavaRDD<Integer> dataSet = jsc.parallelize(l, slices);

    int count = dataSet.map(new Function<Integer, Integer>() {
      @Override
      public Integer call(Integer integer) {
        double x = Math.random() * 2 - 1;
        double y = Math.random() * 2 - 1;
        return (x * x + y * y < 1) ? 1 : 0;
      }
    }).reduce(new Function2<Integer, Integer, Integer>() {
      @Override
      public Integer call(Integer integer, Integer integer2) {
        return integer + integer2;
      }
    });

    System.out.println("Pi is roughly " + 4.0 * count / n);

    jsc.stop();
  }
}
```

## Python
<a name="emr-spark-application-spark27"></a>

```
import argparse
import logging
from operator import add
from random import random

from pyspark.sql import SparkSession

logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")


def calculate_pi(partitions, output_uri):
    """
    Calculates pi by testing a large number of random numbers against a unit circle
    inscribed inside a square. The trials are partitioned so they can be run in
    parallel on cluster instances.

    :param partitions: The number of partitions to use for the calculation.
    :param output_uri: The URI where the output is written, typically an Amazon S3
                       bucket, such as 's3://example-bucket/pi-calc'.
    """

    def calculate_hit(_):
        x = random() * 2 - 1
        y = random() * 2 - 1
        return 1 if x**2 + y**2 < 1 else 0

    tries = 100000 * partitions
    logger.info(
        "Calculating pi with a total of %s tries in %s partitions.", tries, partitions
    )
    with SparkSession.builder.appName("My PyPi").getOrCreate() as spark:
        hits = (
            spark.sparkContext.parallelize(range(tries), partitions)
            .map(calculate_hit)
            .reduce(add)
        )
        pi = 4.0 * hits / tries
        logger.info("%s tries and %s hits gives pi estimate of %s.", tries, hits, pi)
        if output_uri is not None:
            df = spark.createDataFrame([(tries, hits, pi)], ["tries", "hits", "pi"])
            df.write.mode("overwrite").json(output_uri)


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "--partitions",
        default=2,
        type=int,
        help="The number of parallel partitions to use when calculating pi.",
    )
    parser.add_argument(
        "--output_uri", help="The URI where output is saved, typically an S3 bucket."
    )
    args = parser.parse_args()

    calculate_pi(args.partitions, args.output_uri)
```

# 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 | 요청을 시도할 수 있는 최대 시도 횟수를 설정합니다. | 

# Spark 단계 추가
<a name="emr-spark-submit-step"></a>

Amazon EMR 단계를 사용하여 EMR 클러스터에 설치된 Spark 프레임워크로 작업을 제출할 수 있습니다. 자세한 내용은 Amazon EMR 관리 안내서에서 [단계](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-overview.html#emr-overview-data-processing)를 참조하세요. 콘솔 및 CLI에서 Spark 애플리케이션 단계를 사용하여 이 작업을 수행할 수 있습니다. 그러면 사용자를 대신하여 `spark-submit` 스크립트가 실행됩니다. API에서는 단계를 사용하여 `spark-submit` 파일을 통해 `command-runner.jar`를 호출할 수 있습니다.

Spark로 애플리케이션 제출에 대한 자세한 내용은 Apache Spark 설명서에서 [Submitting applications](https://spark.apache.org/docs/latest/submitting-applications.html) 주제를 참조하세요.

**콘솔을 사용하여 Spark 단계를 제출하려면**

1. [https://console.aws.amazon.com/emr](https://console.aws.amazon.com/emr/) Amazon EMR 콘솔을 엽니다.

1. **클러스터 목록**에서 클러스터의 이름을 선택합니다.

1. **단계** 섹션으로 스크롤하여 섹션을 확장한 후 **단계 추가**를 선택합니다.

1. **단계 추가** 대화 상자에서 다음을 수행합니다.
   + **단계 유형**에서 **Spark 애플리케이션**을 선택합니다.
   + **이름**에서 기본 이름(Spark 애플리케이션)을 그대로 사용하거나 새 이름을 입력합니다.
   + **Deploy mode(배포 모드)**에서 **클라이언트** 또는 **클러스터** 모드를 선택합니다. 클라이언트 모드는 클러스터의 프라이머리 인스턴스에서 드라이버 프로그램을 시작하고, 클러스터 모드는 클러스터에서 드라이버 프로그램을 시작합니다. 클라이언트 모드의 경우 드라이버의 로그 출력이 단계 로그에 나타나고, 클러스터 모드의 경우 드라이버의 로그 출력이 첫 번째 YARN 컨테이너의 로그에 나타납니다. 자세한 내용은 Apache Spark 설명서의 [Cluster mode overview](https://spark.apache.org/docs/latest/cluster-overview.html)를 참조하세요.
   + 원하는 **Spark-submit 옵션**을 지정합니다. `spark-submit` 옵션에 대한 자세한 내용은 [Launching applications with spark-submit](https://spark.apache.org/docs/latest/submitting-applications.html#launching-applications-with-spark-submit)을 참조하세요.
   + **애플리케이션 위치**에는 해당 애플리케이션의 로컬 또는 S3 URI 경로를 지정합니다.
   + **인수**에서 필드를 비워 둡니다.
   + **실패 시 작업**에서 기본 옵션(**계속**)을 그대로 사용합니다.

1. **추가**를 선택합니다. 단계가 콘솔에 [Pending] 상태로 나타납니다.

1. 단계의 상태는 단계가 실행됨에 따라 **대기 중**에서 **실행 중**을 거쳐 **완료됨**으로 바뀝니다. 상태를 업데이트하려면 **작업** 열 위의 **새로 고침** 아이콘을 선택합니다.

1. 단계 결과는 로깅을 구성한 경우 Amazon EMR 콘솔 클러스터 세부 정보 페이지에서 **로그 파일** 아래 단계 옆에 있습니다. 또는 클러스터를 시작할 때 구성한 로그 버킷에서도 단계 정보를 찾아볼 수 있습니다.

**를 사용하여 Spark에 작업을 제출하려면 AWS CLI**

클러스터 생성 시 단계를 제출하거나 기존 클러스터에서 `aws emr add-steps` 하위 명령을 사용합니다.

1. 다음 예제에 표시된 대로 `create-cluster`를 사용합니다.
**참고**  
가독성을 위해 Linux 줄 연속 문자(\$1)가 포함됩니다. Linux 명령에 사용하거나 제외할 수 있습니다. Windows에서는 제외시키거나 캐럿(^)으로 바꿉니다.

   ```
   aws emr create-cluster --name "Add Spark Step Cluster" --release-label emr-7.12.0 --applications Name=Spark \
   --ec2-attributes KeyName=myKey --instance-type m5.xlarge --instance-count 3 \
   --steps Type=Spark,Name="Spark Program",ActionOnFailure=CONTINUE,Args=[--class,org.apache.spark.examples.SparkPi,/usr/lib/spark/examples/jars/spark-examples.jar,10] --use-default-roles
   ```

   또는 다음 예제에 표시된 대로 `command-runner.jar`을 사용할 수 있습니다.

   ```
   aws emr create-cluster --name "Add Spark Step Cluster" --release-label emr-7.12.0 \
   --applications Name=Spark --ec2-attributes KeyName=myKey --instance-type m5.xlarge --instance-count 3 \
   --steps Type=CUSTOM_JAR,Name="Spark Program",Jar="command-runner.jar",ActionOnFailure=CONTINUE,Args=[spark-example,SparkPi,10] --use-default-roles
   ```
**참고**  
가독성을 위해 Linux 줄 연속 문자(\$1)가 포함됩니다. Linux 명령에 사용하거나 제외할 수 있습니다. Windows에서는 제외시키거나 캐럿(^)으로 바꿉니다.

1. 또는 이미 실행 중인 클러스터에 단계를 추가합니다. `add-steps`를 사용합니다.

   ```
   aws emr add-steps --cluster-id j-2AXXXXXXGAPLF --steps Type=Spark,Name="Spark Program",ActionOnFailure=CONTINUE,Args=[--class,org.apache.spark.examples.SparkPi,/usr/lib/spark/examples/jars/spark-examples.jar,10]
   ```

   또는 다음 예제에 표시된 대로 `command-runner.jar`을 사용할 수 있습니다.

   ```
   aws emr add-steps --cluster-id j-2AXXXXXXGAPLF --steps Type=CUSTOM_JAR,Name="Spark Program",Jar="command-runner.jar",ActionOnFailure=CONTINUE,Args=[spark-example,SparkPi,10]
   ```

**SDK for Java를 사용하여 작업을 Spark로 제출하는 방법**

1. 다음은 Java를 사용하여 Spark가 설치된 클러스터에 단계를 추가하는 방법을 보여주는 예제입니다.

   ```
   AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
   AmazonElasticMapReduce emr = new AmazonElasticMapReduceClient(credentials);
    
   StepFactory stepFactory = new StepFactory();
   AmazonElasticMapReduceClient emr = new AmazonElasticMapReduceClient(credentials);
   AddJobFlowStepsRequest req = new AddJobFlowStepsRequest();
   req.withJobFlowId("j-1K48XXXXXXHCB");
   
   List<StepConfig> stepConfigs = new ArrayList<StepConfig>();
   		
   HadoopJarStepConfig sparkStepConf = new HadoopJarStepConfig()
   			.withJar("command-runner.jar")
   			.withArgs("spark-submit","--executor-memory","1g","--class","org.apache.spark.examples.SparkPi","/usr/lib/spark/examples/jars/spark-examples.jar","10");			
   		
   StepConfig sparkStep = new StepConfig()
   			.withName("Spark Step")
   			.withActionOnFailure("CONTINUE")
   			.withHadoopJarStep(sparkStepConf);
   
   stepConfigs.add(sparkStep);
   req.withSteps(stepConfigs);
   AddJobFlowStepsResult result = emr.addJobFlowSteps(req);
   ```

1. 단계에 대한 로그를 검토하여 단계의 결과를 살펴봅니다. 단계를 선택하고 **단계를** 선택한 다음 로그 **파일**에서 `stdout` 또는 중 하나를 선택하여 로깅을 활성화한 AWS Management Console 경우에서이 작업을 수행할 수 있습니다`stderr`. 사용할 수 있는 로그를 보려면 **로그 보기**를 선택합니다.

## Spark 기본 구성 설정 재정의
<a name="dynamic-configuration"></a>

애플리케이션마다 Spark 기본 구성 값을 재정의해야 할 때가 있습니다. 이 작업은 단계를 사용하여 애플리케이션을 제출할 때 기본적으로 옵션을 `spark-submit`에 전달함으로써 수행할 수 있습니다. 예를 들면 `spark.executor.memory`를 변경하여 실행자 프로세스에 할당된 메모리를 변경해야 할 때가 있습니다. 다음과 같은 인수를 사용하여 `--executor-memory`를 지정합니다.

```
spark-submit --executor-memory 1g --class org.apache.spark.examples.SparkPi /usr/lib/spark/examples/jars/spark-examples.jar 10
```

마찬가지로, `--executor-cores` 및 `--driver-memory`를 조정할 수 있습니다. 단계에서 다음 인수를 단계에 제공합니다.

```
--executor-memory 1g --class org.apache.spark.examples.SparkPi /usr/lib/spark/examples/jars/spark-examples.jar 10
```

또한 `--conf` 옵션을 사용하여 기본 제공 스위치가 없는 설정을 조정할 수도 있습니다. 조정 가능한 다양한 설정에 대한 자세한 내용은 Apache Spark 설명서의 [Dynamically Loading Spark Properties](https://spark.apache.org/docs/latest/configuration.html#dynamically-loading-spark-properties) 주제를 참조하세요.

# Spark 애플리케이션 기록 보기
<a name="emr-spark-application-history"></a>

콘솔의 클러스터 세부 정보 페이지에서 **애플리케이션 사용자 인터페이스** 탭을 사용하여 Spark, YARN 애플리케이션 및 Tez UI 세부 정보를 볼 수 있습니다. Amazon EMR 애플리케이션 사용자 인터페이스(UI)를 사용하면 활성 작업 및 작업 내역을 쉽게 분석하고 관련 문제를 해결할 수 있습니다.

자세한 내용은 *Amazon EMR 관리 안내서*에서 [애플리케이션 기록 보기](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-cluster-application-history.html)를 참조하세요.

# Spark 웹 UI에 액세스
<a name="emr-spark-webui"></a>

Amazon EMR 관리 안내서에서 [클러스터에 연결](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-connect-master-node.html) 섹션에 나온 SSH 터널을 생성하거나 프록시를 생성하는 절차를 수행한 다음, 클러스터의 YARN ResourceManager로 이동하여 Spark 웹 UI를 볼 수 있습니다. 애플리케이션의 **Tracking UI**(추적 UI)에서 링크를 선택합니다. 애플리케이션이 실행 중인 경우 **ApplicationMaster**가 표시됩니다. ApplicationMaster는 드라이버가 있는 경우 언제든지 포트 20888의 애플리케이션 마스터 웹 UI로 안내합니다. YARN 클라이언트 모드로 실행하는 경우 드라이버는 클러스터의 프라이머리 노드에 있을 수 있습니다. 애플리케이션을 YARN 클러스터 모드에서 실행 중인 경우 드라이버는 클러스터에서 해당 애플리케이션에 대한 ApplicationMaster에 있습니다. 애플리케이션이 완료된 경우에는 **기록**이 표시되며, EMR 클러스터 프라이머리 노드의 포트 번호 18080에 있는 Spark HistoryServer UI로 안내합니다. 이 설명은 이미 완료된 애플리케이션에 적용됩니다. 또한 http://*master-public-dns-name*:18080/에서 Spark HistoryServer UI로 직접 이동할 수도 있습니다.

Amazon EMR 릴리스 5.25.0 이상에서는 SSH 연결을 통해 웹 프록시를 설정하지 않고도 콘솔에서 Spark 기록 서버 UI에 액세스할 수 있습니다. 자세한 내용은 [영구 애플리케이션 사용자 인터페이스 보기](https://docs.aws.amazon.com/emr/latest/ManagementGuide/app-history-spark-UI.html)를 참조하세요.

# Spark 구조화된 스트리밍 Amazon Kinesis Data Streams 커넥터 사용
<a name="emr-spark-structured-streaming-kinesis"></a>

Amazon EMR 릴리스 7.1.0 이상에는 릴리스 이미지에 Spark 구조화된 스트리밍 Amazon Kinesis Data Streams 커넥터가 포함되어 있습니다. 이 커넥터를 사용하면 Amazon EMR에서 Spark를 사용하여 Amazon Kinesis Data Streams에 저장된 데이터를 처리할 수 있습니다. 커넥터는 `GetRecords`(공유 처리량) 및 `SubscribeToShard`(향상된 팬아웃)의 소비자 유형을 모두 지원합니다. 이 통합은 [https://github.com/awslabs/spark-sql-kinesis-connector](https://github.com/awslabs/spark-sql-kinesis-connector)에 기반합니다. 커넥터 사용을 시작하는 방법에 대한 자세한 내용은 [README](https://github.com/awslabs/spark-sql-kinesis-connector/blob/main/README.md)를 참조하세요.

다음 예제에서는 커넥터를 사용하여 Amazon EMR에서 Spark 애플리케이션을 시작하는 방법을 보여줍니다.

```
spark-submit my_kinesis_streaming_script.py
```

# Amazon EMR에서 Apache Spark용 Amazon Redshift 통합 사용
<a name="emr-spark-redshift"></a>

Amazon EMR 릴리스 6.4.0 이상에서 모든 릴리스 이미지에 [Apache Spark](https://aws.amazon.com/emr/features/spark/)와 Amazon Redshift 간 커넥터가 포함됩니다. 이 커넥터를 사용하면 Amazon EMR에서 Spark를 사용하여 Amazon Redshift에 저장된 데이터를 처리할 수 있습니다. Amazon EMR 릴리스 6.4.0\$16.8.0의 경우 통합은 [`spark-redshift` 오픈 소스 커넥터](https://github.com/spark-redshift-community/spark-redshift#readme)를 기반으로 합니다. Amazon EMR 릴리스 6.9.0 이상의 경우 [Apache Spark용 Amazon Redshift 통합](https://docs.aws.amazon.com/redshift/latest/mgmt/spark-redshift-connector.html)이 커뮤니티 버전에서 네이티브 통합으로 마이그레이션되었습니다.

**Topics**
+ [Apache Spark용 Amazon Redshift 통합을 사용하여 Spark 애플리케이션 시작](emr-spark-redshift-launch.md)
+ [Apache Spark용 Amazon Redshift 통합으로 인증](emr-spark-redshift-auth.md)
+ [Amazon Redshift에서 읽고 쓰기](emr-spark-redshift-readwrite.md)
+ [Spark 커넥터 사용 시 고려 사항 및 제한 사항](emr-spark-redshift-considerations.md)

# Apache Spark용 Amazon Redshift 통합을 사용하여 Spark 애플리케이션 시작
<a name="emr-spark-redshift-launch"></a>

Amazon EMR 릴리스 6.4\$16.9의 경우 `--jars` 또는 `--packages` 옵션을 사용하여 다음 JAR 파일 중 사용하려는 파일을 지정해야 합니다. `--jars` 옵션은 로컬, HDFS 또는 HTTP 및 HTTPS를 사용하여 저장되는 종속 항목을 지정합니다. `--jars` 옵션에서 지원하는 다른 파일 위치를 보려면 Spark 설명서에서 [Advanced Dependency Management](https://spark.apache.org/docs/latest/submitting-applications.html#advanced-dependency-management)를 참조하세요. `--packages` 옵션은 퍼블릭 Maven 리포지토리에 저장된 종속성을 지정합니다.
+ `spark-redshift.jar`
+ `spark-avro.jar`
+ `RedshiftJDBC.jar`
+ `minimal-json.jar`

Amazon EMR 릴리스 6.10.0 이상에서는 `minimal-json.jar` 종속성이 필요하지 않으며 기본적으로 다른 종속성을 각 클러스터에 자동으로 설치합니다. 다음 예제에서는 Apache Spark용 Amazon Redshift 통합을 사용하여 Spark 애플리케이션을 시작하는 방법을 보여줍니다.

------
#### [ Amazon EMR 6.10.0 \$1 ]

다음 예제는 Amazon EMR 릴리스 6.10 이상에서 `spark-redshift` 커넥터를 사용하여 Spark 애플리케이션을 시작하는 방법을 보여줍니다.

```
spark-submit my_script.py
```

------
#### [ Amazon EMR 6.4.0 - 6.9.x ]

Amazon EMR 릴리스 6.4\$16.9에서 `spark-redshift` 커넥터를 사용하여 Spark 애플리케이션을 시작하려면 다음 예제와 같이 `--jars` 또는 `--packages` 옵션을 사용해야 합니다. `--jars` 옵션과 함께 나열된 경로는 JAR 파일의 기본 경로입니다.

```
spark-submit \
  --jars /usr/share/aws/redshift/jdbc/RedshiftJDBC.jar,/usr/share/aws/redshift/spark-redshift/lib/spark-redshift.jar,/usr/share/aws/redshift/spark-redshift/lib/spark-avro.jar,/usr/share/aws/redshift/spark-redshift/lib/minimal-json.jar \
  my_script.py
```

------

# Apache Spark용 Amazon Redshift 통합으로 인증
<a name="emr-spark-redshift-auth"></a>

## AWS Secrets Manager 를 사용하여 자격 증명을 검색하고 Amazon Redshift에 연결
<a name="emr-spark-redshift-secrets"></a>

다음 코드 샘플은 AWS Secrets Manager 를 사용하여 자격 증명을 검색하여 Python의 Apache Spark용 PySpark 인터페이스를 사용하여 Amazon Redshift 클러스터에 연결하는 방법을 보여줍니다.

```
from pyspark.sql import SQLContext
import boto3

sc = # existing SparkContext
sql_context = SQLContext(sc)

secretsmanager_client = boto3.client('secretsmanager')
secret_manager_response = secretsmanager_client.get_secret_value(
    SecretId='string',
    VersionId='string',
    VersionStage='string'
)
username = # get username from secret_manager_response
password = # get password from secret_manager_response
url = "jdbc:redshift://redshifthost:5439/database?user=" + username + "&password=" + password

# Read data from a table
df = sql_context.read \
    .format("io.github.spark_redshift_community.spark.redshift") \
    .option("url", url) \
    .option("dbtable", "my_table") \
    .option("tempdir", "s3://path/for/temp/data") \
    .load()
```

## IAM을 사용하여 보안 인증을 검색하고 Amazon Redshift에 연결
<a name="emr-spark-redshift-iam"></a>

Amazon Redshift 제공 JDBC 드라이버 버전 2 드라이버를 사용하여 Spark 커넥터로 Amazon Redshift에 연결할 수 있습니다. AWS Identity and Access Management (IAM)[를 사용하려면 IAM 인증을 사용하도록 JDBC URL을 구성합니다](https://docs.aws.amazon.com/redshift/latest/mgmt/generating-iam-credentials-configure-jdbc-odbc.html). Amazon EMR에서 Redshift 클러스터에 연결하려면 임시 IAM 보안 인증을 검색할 권한을 IAM 역할에 부여해야 합니다. 보안 인증을 검색하고 Amazon S3 작업을 실행할 수 있도록 IAM 역할에 다음 권한을 할당합니다.
+  [Redshift:GetClusterCredentials](https://docs.aws.amazon.com/redshift/latest/APIReference/API_GetClusterCredentials.html)(프로비저닝된 Amazon Redshift 클러스터용) 
+  [Redshift:DescribeClusters](https://docs.aws.amazon.com/redshift/latest/APIReference/API_DescribeClusters.html)(프로비저닝된 Amazon Redshift 클러스터용) 
+ [Redshift:GetWorkgroup](https://docs.aws.amazon.com/redshift-serverless/latest/APIReference/API_GetWorkgroup.html)(Amazon Redshift Serverless 작업 그룹용)
+  [Redshift:GetCredentials](https://docs.aws.amazon.com/redshift-serverless/latest/APIReference/API_GetCredentials.html)(Amazon Redshift Serverless 작업 그룹용) 
+  [s3:GetBucket](https://docs.aws.amazon.com/AmazonS3/latest/API/API_control_GetBucket.html) 
+  [s3:GetBucketLocation](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLocation.html) 
+  [s3:GetObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html) 
+  [s3:PutObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html) 
+  [s3:GetBucketLifecycleConfiguration](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLifecycleConfiguration.html) 

`GetClusterCredentials`에 대한 자세한 내용은 [`GetClusterCredentials`에 대한 리소스 정책](https://docs.aws.amazon.com/redshift/latest/mgmt/redshift-iam-access-control-identity-based.html#redshift-policy-resources.getclustercredentials-resources)을 참조하세요.

또한 `COPY` 및 `UNLOAD` 작업 중에 Amazon Redshift가 IAM 역할을 맡을 수 있는지 확인해야 합니다.

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "sts:AssumeRole"
      ],
      "Resource": "arn:aws:iam::123456789012:role/RedshiftServiceRole",
      "Sid": "AllowSTSAssumerole"
    }
  ]
}
```

------

다음 예제에서는 Spark와 Amazon Redshift 사이에서 IAM 인증을 사용합니다.

```
from pyspark.sql import SQLContext
import boto3

sc = # existing SparkContext
sql_context = SQLContext(sc)

url = "jdbc:redshift:iam://redshift-host:redshift-port/db-name"
iam_role_arn = "arn:aws:iam::account-id:role/role-name"

# Read data from a table
df = sql_context.read \
    .format("io.github.spark_redshift_community.spark.redshift") \
    .option("url", url) \
    .option("aws_iam_role", iam_role_arn) \
    .option("dbtable", "my_table") \
    .option("tempdir", "s3a://path/for/temp/data") \
    .mode("error") \
    .load()
```

# Amazon Redshift에서 읽고 쓰기
<a name="emr-spark-redshift-readwrite"></a>

다음 코드 예제는 데이터 소스 API와 SparkSQL을 통해 Amazon Redshift 데이터베이스에서 샘플 데이터를 읽고 쓰는 데 PySpark를 사용합니다.

------
#### [ Data source API ]

PySpark를 사용하여 데이터 소스 API를 통해 Amazon Redshift 데이터베이스에서 샘플 데이터를 읽고 씁니다.

```
import boto3
from pyspark.sql import SQLContext

sc = # existing SparkContext
sql_context = SQLContext(sc)

url = "jdbc:redshift:iam://redshifthost:5439/database"
aws_iam_role_arn = "arn:aws:iam::accountID:role/roleName"

df = sql_context.read \
    .format("io.github.spark_redshift_community.spark.redshift") \
    .option("url", url) \
    .option("dbtable", "tableName") \
    .option("tempdir", "s3://path/for/temp/data") \
    .option("aws_iam_role", "aws_iam_role_arn") \
    .load()

df.write \
    .format("io.github.spark_redshift_community.spark.redshift") \
    .option("url", url) \
    .option("dbtable", "tableName_copy") \
    .option("tempdir", "s3://path/for/temp/data") \
    .option("aws_iam_role", "aws_iam_role_arn") \
    .mode("error") \
    .save()
```

------
#### [ SparkSQL ]

PySpark를 사용하여 SparkSQL을 통해 Amazon Redshift 데이터베이스에서 샘플 데이터를 읽고 씁니다.

```
import boto3
import json
import sys
import os
from pyspark.sql import SparkSession

spark = SparkSession \
    .builder \
    .enableHiveSupport() \
    .getOrCreate()
    
url = "jdbc:redshift:iam://redshifthost:5439/database"
aws_iam_role_arn = "arn:aws:iam::accountID:role/roleName"
    
bucket = "s3://path/for/temp/data"
tableName = "tableName" # Redshift table name

s = f"""CREATE TABLE IF NOT EXISTS {tableName} (country string, data string) 
    USING io.github.spark_redshift_community.spark.redshift 
    OPTIONS (dbtable '{tableName}', tempdir '{bucket}', url '{url}', aws_iam_role '{aws_iam_role_arn}' ); """

spark.sql(s)
         
columns = ["country" ,"data"]
data = [("test-country","test-data")]
df = spark.sparkContext.parallelize(data).toDF(columns)

# Insert data into table
df.write.insertInto(tableName, overwrite=False)
df = spark.sql(f"SELECT * FROM {tableName}")
df.show()
```

------

# Spark 커넥터 사용 시 고려 사항 및 제한 사항
<a name="emr-spark-redshift-considerations"></a>
+ Amazon EMR의 Spark에서 Amazon Redshift로의 JDBC 연결을 위해 SSL을 켜는 것이 좋습니다.
+ 모범 사례로 AWS Secrets Manager 에서 Amazon Redshift 클러스터의 보안 인증을 관리하는 것이 좋습니다. 예제[AWS Secrets Manager 는를 사용하여 Amazon Redshift에 연결하기 위한 자격 증명 검색을](https://docs.aws.amazon.com/redshift/latest/mgmt/redshift-secrets-manager-integration.html) 참조하세요.
+ Amazon Redshift 인증 파라미터에 대해 `aws_iam_role` 파라미터를 사용하여 IAM 역할을 전달하는 것이 좋습니다.
+ `tempdir` URI는 Amazon S3 위치를 가리킵니다. 이 임시 디렉터리는 자동으로 정리되지 않으므로, 추가 비용이 발생할 수 있습니다.
+ Amazon Redshift에 대한 다음 권장 사항을 고려합니다.
  + Amazon Redshift 클러스터에 대한 퍼블릭 액세스를 차단하는 것이 좋습니다.
  + [Amazon Redshift 감사 로깅](https://docs.aws.amazon.com/redshift/latest/mgmt/db-auditing.html)을 켜는 것이 좋습니다.
  + [Amazon Redshift 저장 데이터 암호화](https://docs.aws.amazon.com/redshift/latest/mgmt/security-server-side-encryption.html)를 켜는 것이 좋습니다.
+ Amazon S3에 대한 다음 권장 사항을 고려합니다.
  + [Amazon S3 버킷에 대한 퍼블릭 액세스를 차단](https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html)하는 것이 좋습니다.
  + [Amazon S3 서버 측 암호화](https://docs.aws.amazon.com/AmazonS3/latest/userguide/serv-side-encryption.html)를 사용하여 사용된 Amazon S3 버킷을 암호화하는 것이 좋습니다.
  + [Amazon S3 수명 주기 정책](https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lifecycle-mgmt.html)을 사용하여 Amazon S3 버킷에 대한 보존 규칙을 정의하는 것이 좋습니다.
  + Amazon EMR은 오픈 소스에서 이미지로 가져온 코드를 항상 확인합니다. 보안을 위해 Spark에서 Amazon S3로의 다음 인증 방법은 지원되지 않습니다.
    + `hadoop-env` 구성 분류에서 AWS 액세스 키 설정
    + `tempdir` URI에서 AWS 액세스 키 인코딩

커넥터 사용 및 지원되는 파라미터에 대한 자세한 내용은 다음 리소스를 참조하세요.
+ *Amazon Redshift 관리 안내서*의 [Apache Spark용 Amazon Redshift 통합](https://docs.aws.amazon.com/redshift/latest/mgmt/spark-redshift-connector.html)
+ Github의 [`spark-redshift` community repository](https://github.com/spark-redshift-community/spark-redshift#readme)

# Spark 릴리스 기록
<a name="Spark-release-history"></a>

다음 테이블에는 애플리케이션과 함께 설치된 구성 요소 외에도 Amazon EMR의 최신 릴리스에 포함된 Spark의 버전이 나열되어 있습니다. 각 릴리스의 구성 요소 버전은 [Amazon EMR 7.x 릴리스 버전](emr-release-7x.md), [Amazon EMR 6.x 릴리스 버전](emr-release-6x.md) 또는 [Amazon EMR 5.x 릴리스 버전](emr-release-5x.md)의 릴리스의 구성 요소 버전 섹션을 참조하세요.

**중요**  
Amazon EMR 릴리스 5.16.0부터 사용할 수 있는 Apache Spark 버전 2.3.1은 [CVE-2018-8024](https://nvd.nist.gov/vuln/detail/CVE-2018-8024) 및 [CVE-2018-1334](https://nvd.nist.gov/vuln/detail/CVE-2018-1334)를 처리합니다. Spark의 이전 버전을 Spark 버전 2.3.1 이상으로 마이그레이션하는 것이 좋습니다.


**Spark 버전 정보**  

| Amazon EMR 릴리스 레이블 | Spark 버전 | Spark와 함께 설치된 구성 요소 | 
| --- | --- | --- | 
| emr-7.12.0 | 3.5.6-amzn-1 | delta, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-hdfs-zkfc, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-7.11.0 | 3.5.6-amzn-0 | delta, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-hdfs-zkfc, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-7.10.0 | 3.5.5-amzn-1 | delta, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-7.9.0 | 3.5.5-amzn-0 | delta, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-7.8.0 | 3.5.4-amzn-0 | delta, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-7.7.0 | 3.5.3-amzn-1 | delta, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-7.6.0 | 3.5.3-amzn-0 | delta, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-7.5.0 | 3.5.2-amzn-1 | delta, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-7.4.0 | 3.5.2-amzn-0 | delta, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-7.3.0 | 3.5.1-amzn-1 | delta, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-7.2.0 | 3.5.1-amzn-0 | delta, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.36.2 | 2.4.8-amzn-2 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-7.1.0 | 3.5.0-amzn-1 | delta, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-7.0.0 | 3.5.0-amzn-0 | delta, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-6.15.0 | 3.4.1-amzn-2 | aws-sagemaker-spark-sdk, delta, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-6.14.0 | 3.4.1-amzn-1 | aws-sagemaker-spark-sdk, delta, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-6.13.0 | 3.4.1-amzn-0 | aws-sagemaker-spark-sdk, delta, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-6.12.0 | 3.4.0-amzn-0 | aws-sagemaker-spark-sdk, delta, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-6.11.1 | 3.3.2-amzn-0.1 | aws-sagemaker-spark-sdk, delta, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-6.11.0 | 3.3.2-amzn-0 | aws-sagemaker-spark-sdk, delta, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-6.10.1 | 3.3.1-amzn-0.1 | aws-sagemaker-spark-sdk, delta, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-6.10.0 | 3.3.1-amzn-0 | aws-sagemaker-spark-sdk, delta, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-6.9.1 | 3.3.0-amzn-1.1 | aws-sagemaker-spark-sdk, delta, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-6.9.0 | 3.3.0-amzn-1 | aws-sagemaker-spark-sdk, delta, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-6.8.1 | 3.3.0-amzn-0.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-6.8.0 | 3.3.0-amzn-0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-6.7.0 | 3.2.1-amzn-0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.36.1 | 2.4.8-amzn-2 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.36.0 | 2.4.8-amzn-2 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-6.6.0 | 3.2.0-amzn-0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.35.0 | 2.4.8-amzn-1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-6.5.0 | 3.1.2-amzn-1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, iceberg, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-6.4.0 | 3.1.2-amzn-0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-6.3.1 | 3.1.1-amzn-0.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-6.3.0 | 3.1.1-amzn-0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-6.2.1 | 3.0.1-amzn-0.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-6.2.0 | 3.0.1-amzn-0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-6.1.1 | 3.0.0-amzn-0.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-6.1.0 | 3.0.0-amzn-0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-6.0.1 | 2.4.4 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-6.0.0 | 2.4.4 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.34.0 | 2.4.8-amzn-0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.33.1 | 2.4.7-amzn-1.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.33.0 | 2.4.7-amzn-1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.32.1 | 2.4.7-amzn-0.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.32.0 | 2.4.7-amzn-0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.31.1 | 2.4.6-amzn-0.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.31.0 | 2.4.6-amzn-0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.30.2 | 2.4.5-amzn-0.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.30.1 | 2.4.5-amzn-0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.30.0 | 2.4.5-amzn-0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-notebook-env, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.29.0 | 2.4.4 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.28.1 | 2.4.4 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.28.0 | 2.4.4 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.27.1 | 2.4.4 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.27.0 | 2.4.4 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.26.0 | 2.4.3 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.25.0 | 2.4.3 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.24.1 | 2.4.2 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.24.0 | 2.4.2 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.23.1 | 2.4.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.23.0 | 2.4.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.22.0 | 2.4.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.21.2 | 2.4.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.21.1 | 2.4.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.21.0 | 2.4.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.20.1 | 2.4.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.20.0 | 2.4.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.19.1 | 2.3.2 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.19.0 | 2.3.2 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.18.1 | 2.3.2 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.18.0 | 2.3.2 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, nginx, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.17.2 | 2.3.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.17.1 | 2.3.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.17.0 | 2.3.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, emr-s3-select, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.16.1 | 2.3.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.16.0 | 2.3.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.15.1 | 2.3.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.15.0 | 2.3.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.14.2 | 2.3.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.14.1 | 2.3.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.14.0 | 2.3.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.13.1 | 2.3.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.13.0 | 2.3.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.12.3 | 2.2.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.12.2 | 2.2.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.12.1 | 2.2.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.12.0 | 2.2.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.11.4 | 2.2.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.11.3 | 2.2.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.11.2 | 2.2.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.11.1 | 2.2.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.11.0 | 2.2.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.10.1 | 2.2.0 | emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.10.0 | 2.2.0 | emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, livy-server, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.9.1 | 2.2.0 | emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.9.0 | 2.2.0 | emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.8.3 | 2.2.0 | emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.8.2 | 2.2.0 | emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.8.1 | 2.2.0 | emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.8.0 | 2.2.0 | emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.7.1 | 2.1.1 | emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.7.0 | 2.1.1 | emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.6.1 | 2.1.1 | emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.6.0 | 2.1.1 | emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.5.4 | 2.1.0 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.5.3 | 2.1.0 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.5.2 | 2.1.0 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.5.1 | 2.1.0 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.5.0 | 2.1.0 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.4.1 | 2.1.0 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.4.0 | 2.1.0 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.3.2 | 2.1.0 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.3.1 | 2.1.0 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.3.0 | 2.1.0 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.2.3 | 2.0.2 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.2.2 | 2.0.2 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.2.1 | 2.0.2 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.2.0 | 2.0.2 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.1.1 | 2.0.1 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.1.0 | 2.0.1 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.0.3 | 2.0.1 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.0.2 | 2.0.0 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.0.1 | 2.0.0 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-5.0.0 | 2.0.0 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-4.9.6 | 1.6.3 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-4.9.5 | 1.6.3 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-4.9.4 | 1.6.3 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-4.9.3 | 1.6.3 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-4.9.2 | 1.6.3 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-4.9.1 | 1.6.3 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-4.8.5 | 1.6.3 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-4.8.4 | 1.6.3 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-4.8.3 | 1.6.3 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-4.8.2 | 1.6.2 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-4.8.1 | 1.6.2 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-4.8.0 | 1.6.2 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-4.7.4 | 1.6.2 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-4.7.3 | 1.6.2 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-4.7.2 | 1.6.2 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-4.7.1 | 1.6.1 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-4.7.0 | 1.6.1 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-4.6.1 | 1.6.1 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-4.6.0 | 1.6.1 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-4.5.0 | 1.6.1 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-4.4.0 | 1.6.0 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-4.3.0 | 1.6.0 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-4.2.0 | 1.5.2 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-4.1.0 | 1.5.0 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 
| emr-4.0.0 | 1.4.1 | emrfs, emr-goodies, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-namenode, hadoop-httpfs-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave | 

# Amazon EMR에서 구체화된 뷰 사용
<a name="emr-spark-materialized-views"></a>

Amazon EMR 릴리스 7.12.0 이상은 AWS Glue 데이터 카탈로그에서 Apache Iceberg 구체화된 뷰 생성 및 관리를 지원합니다. 구체화된 뷰는 SQL 쿼리의 사전 계산된 결과를 Apache Iceberg 형식으로 저장하고 기본 소스 테이블이 변경될 때 증분 업데이트하는 관리형 테이블입니다. 구체화된 뷰를 사용하여 데이터 변환 파이프라인을 간소화하고 복잡한 분석 워크로드의 쿼리 성능을 가속화할 수 있습니다.

Amazon EMR에서 Spark를 사용하여 구체화된 뷰를 생성하면 뷰 정의와 메타데이터가 AWS Glue 데이터 카탈로그에 저장됩니다. 사전 계산된 결과는 AWS 계정 내의 Amazon S3 Tables 버킷 또는 Amazon S3 범용 버킷에 Apache Iceberg 테이블로 저장됩니다. AWS Glue 데이터 카탈로그는 관리형 컴퓨팅 인프라를 사용하여 소스 테이블을 자동으로 모니터링하고 구체화된 뷰를 새로 고칩니다.

**Topics**
+ [구체화된 뷰가 Amazon EMR에서 작동하는 방식](#emr-spark-materialized-views-how-it-works)
+ [사전 조건](#emr-spark-materialized-views-prerequisites)
+ [구체화된 뷰를 사용하도록 Spark 구성](#emr-spark-materialized-views-configure)
+ [구체화된 뷰 생성](#emr-spark-materialized-views-create)
+ [구체화된 뷰 쿼리](#emr-spark-materialized-views-query)
+ [구체화된 뷰 새로 고침](#emr-spark-materialized-views-refresh)
+ [구체화된 뷰 관리](#emr-spark-materialized-views-manage)
+ [구체화된 뷰에 대한 권한](#emr-spark-materialized-views-permissions)
+ [구체화된 뷰 작업 모니터링](#emr-spark-materialized-views-monitoring)
+ [예제: 전체 워크플로](#emr-spark-materialized-views-example)
+ [고려 사항 및 제한 사항](#emr-spark-materialized-views-limitations)

## 구체화된 뷰가 Amazon EMR에서 작동하는 방식
<a name="emr-spark-materialized-views-how-it-works"></a>

구체화된 뷰는 Apache Spark의 Iceberg 지원을 통해 Amazon EMR과 통합됩니다. AWS Glue 데이터 카탈로그를 사용하도록 Spark 세션을 구성할 때 표준 SQL 구문을 사용하여 구체화된 뷰를 생성할 수 있습니다. Spark 옵티마이저는 더 나은 성능을 제공할 때 구체화된 뷰를 사용하도록 쿼리를 자동으로 재작성할 수 있으므로 애플리케이션 코드를 수동으로 수정할 필요가 없습니다.

 AWS Glue 데이터 카탈로그는 다음을 포함하여 구체화된 뷰 유지 관리의 모든 운영 측면을 처리합니다.
+ Apache Iceberg의 메타데이터 계층을 사용하여 소스 테이블의 변경 사항 탐지
+ 관리형 Spark 컴퓨팅을 사용하여 새로 고침 작업 예약 및 실행
+ 데이터 변경을 기반으로 전체 새로 고침 수행 또는 증분 새로 고침 수행 여부 결정
+ 다중 엔진 액세스를 위해 사전 계산된 결과를 Apache Iceberg 형식으로 저장

일반 테이블에 사용하는 것과 동일한 Spark SQL 인터페이스를 사용하여 Amazon EMR에서 구체화된 뷰를 쿼리할 수 있습니다. Amazon Athena와 Amazon Redshift를 포함한 다른 서비스에서도 사전 계산된 데이터에 액세스할 수 있습니다.

## 사전 조건
<a name="emr-spark-materialized-views-prerequisites"></a>

Amazon EMR에서 구체화된 뷰를 사용하려면 다음이 필요합니다.
+  AWS 계정
+ 릴리스 7.12.0 이상을 실행하는 Amazon EMR 클러스터
+  AWS Glue 데이터 카탈로그에 등록된 Apache Iceberg 형식의 소스 테이블
+ AWS 소스 테이블 및 대상 데이터베이스에 대해 구성된 Lake Formation 권한
+ 구체화된 뷰 데이터를 저장하기 위해 Lake Formation에 AWS 등록된 S3 Tables 버킷 또는 S3 범용 버킷

## 구체화된 뷰를 사용하도록 Spark 구성
<a name="emr-spark-materialized-views-configure"></a>

구체화된 뷰를 생성하고 관리하려면 필수 Iceberg 확장 및 카탈로그 설정으로 Spark 세션을 구성합니다. 구성은 소스 테이블과 구체화된 뷰가 S3 Tables 버킷을 사용하는지 아니면 S3 범용 버킷을 사용하는지에 따라 달라집니다.

### S3 테이블 구성
<a name="emr-spark-materialized-views-configure-s3-tables"></a>

구체화된 뷰에 S3 Tables 버킷을 사용하는 경우 소스 테이블과 구체화된 뷰에 대해 별도의 카탈로그 참조를 구성합니다.

```
spark-sql \
  --conf spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions \
  --conf spark.sql.catalog.glue_catalog=org.apache.iceberg.spark.SparkCatalog \
  --conf spark.sql.catalog.glue_catalog.type=glue \
  --conf spark.sql.catalog.glue_catalog.warehouse=s3://amzn-s3-demo-bucket/warehouse \
  --conf spark.sql.catalog.glue_catalog.glue.region=us-east-1 \
  --conf spark.sql.catalog.glue_catalog.glue.id=111122223333 \
  --conf spark.sql.catalog.glue_catalog.glue.account-id=111122223333 \
  --conf spark.sql.catalog.glue_catalog.glue.lakeformation-enabled=true \
  --conf spark.sql.catalog.s3t_catalog=org.apache.iceberg.spark.SparkCatalog \
  --conf spark.sql.catalog.s3t_catalog.type=glue \
  --conf spark.sql.catalog.s3t_catalog.glue.id=111122223333:s3tablescatalog/my-table-bucket \
  --conf spark.sql.catalog.s3t_catalog.glue.account-id=111122223333 \
  --conf spark.sql.catalog.s3t_catalog.glue.lakeformation-enabled=true \
  --conf spark.sql.catalog.s3t_catalog.warehouse=s3://amzn-s3-demo-bucket/mv-warehouse \
  --conf spark.sql.catalog.s3t_catalog.glue.region=us-east-1 \
  --conf spark.sql.defaultCatalog=s3t_catalog \
  // turn on automatic query rewrite (optional)
  --conf spark.sql.optimizer.answerQueriesWithMVs.enabled=true
```

### S3 범용 버킷에 대한 구성
<a name="emr-spark-materialized-views-configure-s3-general"></a>

S3 범용 버킷을 사용하는 경우 단일 카탈로그 참조를 구성합니다.

```
spark-sql \
  --conf spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions \
  --conf spark.sql.catalog.glue_catalog=org.apache.iceberg.spark.SparkCatalog \
  --conf spark.sql.catalog.glue_catalog.type=glue \
  --conf spark.sql.catalog.glue_catalog.warehouse=s3://amzn-s3-demo-bucket/warehouse \
  --conf spark.sql.catalog.glue_catalog.glue.region=us-east-1 \
  --conf spark.sql.catalog.glue_catalog.glue.id=111122223333 \
  --conf spark.sql.catalog.s3t_catalog.glue.account-id=111122223333 \
  --conf spark.sql.catalog.s3t_catalog.glue.lakeformation-enabled=true \
  --conf spark.sql.defaultCatalog=glue_catalog \
  // turn on automatic query rewrite (optional)
  --conf spark.sql.optimizer.answerQueriesWithMVs.enabled=true
```

### 증분 새로 고침 활성화
<a name="emr-spark-materialized-views-configure-incremental"></a>

증분 새로 고침 최적화를 활성화하려면 Spark 세션에 다음 구성 속성을 추가합니다.

```
spark-sql \
  --conf spark.sql.optimizer.incrementalMVRefresh.enabled=true \
```

### 구성 파라미터
<a name="emr-spark-materialized-views-configure-parameters"></a>

다음 구성 파라미터는 구체화된 뷰 동작을 제어합니다.
+ `spark.sql.extensions` - 구체화된 뷰 지원에 필요한 Iceberg Spark 세션 확장을 활성화합니다.
+ `spark.sql.optimizer.answerQueriesWithMVs.enabled` - 구체화된 뷰를 사용하기 위한 자동 쿼리 재작성을 활성화합니다. 이 최적화를 활성화하려면 true로 설정합니다.
+ `spark.sql.optimizer.incrementalMVRefresh.enabled` - 증분 새로 고침 최적화를 활성화합니다. 새로 고침 작업 중에 변경된 데이터만 처리하려면 true로 설정합니다.

## 구체화된 뷰 생성
<a name="emr-spark-materialized-views-create"></a>

CREATE MATERIALIZED VIEW SQL 문을 사용하여 구체화된 뷰를 생성합니다. 뷰 정의는 변환 로직을 하나 이상의 소스 테이블을 참조하는 SQL 쿼리로 지정합니다.

### DLLs
<a name="emr-spark-materialized-views-create-dlls"></a>

**뷰 생성**

```
{ CREATE OR REPLACE MATERIALIZED VIEW | CREATE MATERIALIZED VIEW [ IF NOT EXISTS ] }
   view_identifier
  [ view_clauses ]
  [ schedule_clauses ]
  AS [ select_statement ]

view_clauses =
  { [ LOCATION location ] |
    [ PARTITIONED BY (col [, ...]) ] |
    [ COMMENT view_comment ] |
    [ SCHEDULE [ REFRESH ] schedule_clause ] }

schedule_clause =
  { EVERY number { HOUR | HOURS | DAY | DAYS | WEEK | WEEKS } }
```

**참고**  
view\$1clauses는 select\$1statement 앞에 나타나야 합니다.

### 기본 구체화된 뷰 생성
<a name="emr-spark-materialized-views-create-basic"></a>

다음 예제에서는 고객별로 주문 데이터를 집계하는 구체화된 보기를 생성하고 보기 정의에서 세 부분으로 구성된 이름 지정 규칙과 함께 정규화된 테이블 이름을 사용합니다.

```
CREATE MATERIALIZED VIEW customer_orders
AS 
SELECT 
    customer_name, 
    COUNT(*) as order_count, 
    SUM(amount) as total_amount 
FROM glue_catalog.sales.orders
GROUP BY customer_name;
```

### 자동 새로 고침을 사용하여 구체화된 뷰 생성
<a name="emr-spark-materialized-views-create-auto-refresh"></a>

자동 새로 고침을 구성하려면 뷰 정의에서 세 부분으로 구성된 이름 지정 규칙과 함께 정규화된 테이블 이름을 사용하여 뷰를 생성할 때 새로 고침 일정을 지정합니다.

```
CREATE MATERIALIZED VIEW customer_orders
SCHEDULE REFRESH EVERY 1 HOUR
AS 
SELECT 
    customer_name, 
    COUNT(*) as order_count, 
    SUM(amount) as total_amount 
FROM glue_catalog.sales.orders
GROUP BY customer_name;
```

### 카탈로그 간 참조를 사용하여 구체화된 뷰 생성
<a name="emr-spark-materialized-views-create-cross-catalog"></a>

소스 테이블이 구체화된 뷰와 다른 카탈로그에 있는 경우 뷰 이름과 뷰 정의 모두에서 3가지 부분으로 구성된 이름 지정 규칙으로 정규화된 테이블 이름을 사용합니다.

```
CREATE MATERIALIZED VIEW s3t_catalog.analytics.customer_summary
AS 
SELECT 
    customer_name, 
    COUNT(*) as order_count, 
    SUM(amount) as total_amount 
FROM glue_catalog.sales.orders
GROUP BY customer_name;
```

## 구체화된 뷰 쿼리
<a name="emr-spark-materialized-views-query"></a>

구체화된 뷰를 생성한 후 표준 SQL SELECT 문을 사용하여 다른 테이블처럼 쿼리할 수 있습니다.

```
SELECT * FROM customer_orders;
```

### 자동 쿼리 재작성
<a name="emr-spark-materialized-views-query-rewrite"></a>

자동 쿼리 재작성이 활성화되면 Spark 옵티마이저는 쿼리를 분석하여 성능을 개선할 수 있을 때 구체화된 뷰를 자동으로 사용합니다. 예를 들어 다음 쿼리를 실행하는 경우:

```
SELECT 
    customer_name, 
    COUNT(*) as order_count, 
    SUM(amount) as total_amount 
FROM orders
GROUP BY customer_name;
```

Spark 옵티마이저는 구체화된 뷰가 최신 상태인 경우 기본 주문 테이블을 처리하는 대신 customer\$1orders 구체화된 뷰를 사용하도록 이 쿼리를 자동으로 재작성합니다.

### 자동 쿼리 재작성 확인
<a name="emr-spark-materialized-views-query-verify"></a>

쿼리가 자동 쿼리 재작성을 사용하는지 확인하려면 EXPLAIN EXTENDED 명령을 사용합니다.

```
EXPLAIN EXTENDED
SELECT customer_name, COUNT(*) as order_count, SUM(amount) as total_amount 
FROM orders
GROUP BY customer_name;
```

실행 계획의 BatchScan 작업에서 구체화된 뷰 이름을 찾습니다. 계획에 BatchScan glue\$1catalog.sales.orders 대신 BatchScan glue\$1catalog.analytics.customer\$1orders가 표시되면 구체화된 뷰를 사용하도록 쿼리가 자동으로 재작성된 것입니다.

**참고**  
자동 쿼리 재작성에는 구체화된 뷰를 생성한 후 Spark 메타데이터 캐시가 채워지는 데 시간이 필요합니다. 이 프로세스는 일반적으로 30초 내에 완료됩니다.

## 구체화된 뷰 새로 고침
<a name="emr-spark-materialized-views-refresh"></a>

전체 새로 고침과 증분 새로 고침이라는 2가지 방법을 사용하여 구체화된 뷰를 새로 고칠 수 있습니다. 전체 새로 고침은 모든 기본 테이블 데이터에서 전체 구체화된 뷰를 다시 계산하는 반면, 증분 새로 고침은 마지막 새로 고침 이후 변경된 데이터만 처리합니다.

### 수동 전체 새로 고침
<a name="emr-spark-materialized-views-refresh-full"></a>

구체화된 뷰의 전체 새로 고침을 수행하려면

```
REFRESH MATERIALIZED VIEW customer_orders FULL;
```

이 명령을 실행한 후 구체화된 뷰를 쿼리하여 업데이트된 결과를 확인합니다.

```
SELECT * FROM customer_orders;
```

### 수동 증분 새로 고침
<a name="emr-spark-materialized-views-refresh-incremental"></a>

증분 새로 고침을 수행하려면 Spark 세션 구성에서 증분 새로 고침이 활성화되어 있는지 확인한 후 다음을 실행합니다.

```
REFRESH MATERIALIZED VIEW customer_orders;
```

 AWS Glue 데이터 카탈로그는 뷰 정의와 변경된 데이터의 양을 기반으로 증분 새로 고침을 적용할 수 있는지 여부를 자동으로 결정합니다. 증분 새로 고침이 불가능한 경우 작업은 전체 새로 고침으로 돌아갑니다.

### 증분 새로 고침 실행 확인
<a name="emr-spark-materialized-views-refresh-verify"></a>

증분 새로 고침이 성공적으로 실행되었는지 확인하려면 다음 명령을 실행하여 `lastRefreshType` 테이블 속성을 확인할 수 있습니다.

```
SHOW TBLPROPERTIES <mvName>("lastRefreshType")
```

또한 Spark 로그 구성을 수정하여 디버그 로깅을 활성화하여 이를 달성할 수도 있습니다.

1. Spark log4j 구성 파일을 엽니다.

   ```
   sudo vim /usr/lib/spark/conf/log4j2.properties
   ```

1. 다음 로거 구성을 추가합니다.

   ```
   logger.spark.name = org.apache.spark.sql
   logger.spark.level = debug
   
   logger.inmemcache.name = org.apache.spark.sql.InMemMvMetadataCache
   logger.inmemcache.level = off
   ```

1. 새로 고침 작업을 실행한 후 Spark 출력에서 다음 메시지를 검색합니다.

   ```
   DEBUG RefreshMaterializedViewExec: Executed Incremental Refresh
   ```

## 구체화된 뷰 관리
<a name="emr-spark-materialized-views-manage"></a>

Amazon EMR은 구체화된 뷰의 수명 주기를 관리하기 위한 SQL 명령을 제공합니다.

### 구체화된 뷰 설명
<a name="emr-spark-materialized-views-manage-describe"></a>

정의, 새로 고침 상태, 마지막 새로 고침 타임스탬프를 포함하여 구체화된 뷰에 대한 메타데이터를 보려면:

```
DESCRIBE EXTENDED customer_orders;
```

### 구체화된 뷰 변경
<a name="emr-spark-materialized-views-manage-alter"></a>

기존 구체화된 뷰의 새로 고침 일정을 수정하려면

```
ALTER MATERIALIZED VIEW customer_orders 
ADD SCHEDULE REFRESH EVERY 2 HOURS;
```

자동 새로 고침을 제거하려면

```
ALTER MATERIALIZED VIEW customer_orders 
DROP SCHEDULE;
```

### 구체화된 뷰 삭제
<a name="emr-spark-materialized-views-manage-drop"></a>

구체화된 뷰를 삭제하려면

```
DROP MATERIALIZED VIEW customer_orders;
```

이 명령은 AWS Glue 데이터 카탈로그에서 구체화된 뷰 정의를 제거하고 S3 버킷에서 기본 Iceberg 테이블 데이터를 삭제합니다.

## 구체화된 뷰에 대한 권한
<a name="emr-spark-materialized-views-permissions"></a>

구체화된 뷰를 생성하고 관리하려면 AWS Lake Formation 권한을 구성해야 합니다. 구체화된 뷰를 생성하는 IAM 역할(정의자 역할)에는 소스 테이블 및 대상 데이터베이스에 대한 특정 권한이 필요합니다.

### 정의자 역할에 필요한 권한
<a name="emr-spark-materialized-views-permissions-definer"></a>

정의자 역할에는 다음과 같은 Lake Formation 권한이 있어야 합니다.
+ 소스 테이블에서 - 행, 열 또는 셀 필터가 없는 SELECT 또는 ALL 권한
+ 대상 데이터베이스에서 - CREATE\$1TABLE 권한
+ Glue 데이터 카탈로그에서 AWS - GetTable 및 CreateTable API 권한

구체화된 뷰를 생성하면 정의자 역할의 ARN이 뷰 정의에 저장됩니다. AWS Glue 데이터 카탈로그는 자동 새로 고침 작업을 실행할 때이 역할을 수임합니다. 정의자 역할이 소스 테이블에 대한 액세스 권한을 상실하면 권한이 복원될 때까지 새로 고침 작업이 실패합니다.

### 구체화된 뷰에 대한 액세스 권한 부여
<a name="emr-spark-materialized-views-permissions-access"></a>

다른 사용자에게 구체화된 뷰를 쿼리할 수 있는 액세스 권한을 부여하려면 AWS Lake Formation을 사용하여 구체화된 뷰 테이블에 대한 SELECT 권한을 부여합니다. 사용자는 기본 소스 테이블에 직접 액세스할 필요 없이 구체화된 뷰를 쿼리할 수 있습니다.

Lake Formation 권한 구성에 대한 자세한 내용은 AWS Lake Formation 개발자 안내서의 데이터 카탈로그 리소스에 대한 권한 부여 및 취소를 참조하세요.

## 구체화된 뷰 작업 모니터링
<a name="emr-spark-materialized-views-monitoring"></a>

 AWS Glue 데이터 카탈로그는 구체화된 보기 새로 고침 작업에 대한 지표와 로그를 Amazon CloudWatch에 게시합니다. CloudWatch 지표를 통해 새로 고침 상태, 기간, 처리되는 데이터 볼륨을 모니터링할 수 있습니다.

### 새로 고침 지표 보기
<a name="emr-spark-materialized-views-monitoring-metrics"></a>

구체화된 보기 새로 고침 지표를 보려면

1. CloudWatch 콘솔을 엽니다.

1. 탐색 창에서 지표를 선택합니다.

1. Glue 네임스페이스를 선택합니다.

1. 구체화된 뷰 이름을 기준으로 지표를 필터링합니다.

### 경보 설정
<a name="emr-spark-materialized-views-monitoring-alarms"></a>

새로 고침 작업이 실패하거나 예상 기간을 초과할 때 알림을 받으려면 구체화된 뷰 지표에 대한 CloudWatch 경보를 생성합니다. Amazon EventBridge 규칙을 구성하여 새로 고침 이벤트에 대한 자동 응답을 트리거할 수도 있습니다.

## 예제: 전체 워크플로
<a name="emr-spark-materialized-views-example"></a>

다음 예제에서는 Amazon EMR에서 구체화된 뷰를 생성하고 사용하기 위한 전체 워크플로를 보여줍니다.

1. SSH를 사용하여 EMR 클러스터 프라이머리 노드에 연결합니다.

1. 샘플 데이터가 포함된 기본 테이블을 생성합니다.

   ```
   spark-sql \
     --conf spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions \
     --conf spark.sql.catalog.glue_catalog=org.apache.iceberg.spark.SparkCatalog \
     --conf spark.sql.catalog.glue_catalog.type=glue \
     --conf spark.sql.catalog.glue_catalog.warehouse=s3://amzn-s3-demo-bucket/warehouse \
     --conf spark.sql.catalog.glue_catalog.glue.region=us-east-1 \
     --conf spark.sql.catalog.glue_catalog.glue.id=111122223333 \
     --conf spark.sql.catalog.glue_catalog.glue.account-id=111122223333 \
     --conf spark.sql.catalog.glue_catalog.glue.lakeformation-enabled=true \
     --conf spark.sql.defaultCatalog=glue_catalog \
     --conf spark.sql.optimizer.answerQueriesWithMVs.enabled=true 
   
   
   CREATE DATABASE IF NOT EXISTS sales;
   
   USE sales;
   
   CREATE TABLE orders (
       id INT,
       customer_name STRING,
       amount DECIMAL(10,2),
       order_date DATE
   );
   
   INSERT INTO orders VALUES 
       (1, 'John Doe', 150.00, DATE('2024-01-15')),
       (2, 'Jane Smith', 200.50, DATE('2024-01-16')),
       (3, 'Bob Johnson', 75.25, DATE('2024-01-17'));
   ```

1. 구체화된 뷰 생성:

   ```
   CREATE MATERIALIZED VIEW customer_summary
   AS 
   SELECT 
       customer_name, 
       COUNT(*) as order_count, 
       SUM(amount) as total_amount 
   FROM glue_catalog.sales.orders
   GROUP BY customer_name;
   ```

1. 구체화된 뷰를 쿼리합니다.

   ```
   SELECT * FROM customer_summary;
   ```

1. 기본 테이블에 추가 데이터를 삽입합니다.

   ```
   INSERT INTO orders VALUES 
       (4, 'Jane Smith', 350.00, DATE('2024-01-18')),
       (5, 'Bob Johnson', 100.25, DATE('2024-01-19'));
   ```

1. 구체화된 뷰를 새로 고침:

   ```
   REFRESH MATERIALIZED VIEW customer_summary FULL;
   ```

1. 업데이트된 결과를 확인합니다.

   ```
   SELECT * FROM customer_summary;
   ```

## 고려 사항 및 제한 사항
<a name="emr-spark-materialized-views-limitations"></a>

Amazon EMR에서 구체화된 뷰를 사용할 때는 다음 사항을 고려하세요.
+ 구체화된 뷰에는 Amazon EMR 릴리스 7.12.0 이상이 필요합니다.
+ 소스 테이블은 AWS Glue 데이터 카탈로그에 등록된 Apache Iceberg 테이블이어야 합니다. Apache Hive, Apache Hudi, Linux Foundation Delta Lake 테이블은 시작 시 지원되지 않습니다.
+ 소스 테이블은 구체화된 뷰와 동일한 AWS 리전 및 AWS 계정에 있어야 합니다.
+ 모든 소스 테이블은 AWS Lake Formation에서 관리해야 합니다. IAM 전용 권한과 하이브리드 액세스는 지원되지 않습니다.
+ 구체화된 뷰는 AWS Glue 데이터 카탈로그 뷰, 다중 언어 뷰 또는 기타 구체화된 뷰를 소스 테이블로 참조할 수 없습니다.
+ 뷰 정의자 역할에는 행, 열 또는 셀 필터가 적용되지 않은 모든 소스 테이블에 대한 전체 읽기 액세스 권한(SELECT 또는 ALL 권한)이 있어야 합니다.
+ 구체화된 뷰는 소스 테이블과 최종적으로 일관됩니다. 새로 고침 기간 동안 쿼리는 오래된 데이터를 반환할 수 있습니다. 즉각적인 일관성을 위해 수동 새로 고침을 실행합니다.
+ 최소 자동 새로 고침 간격은 1시간입니다.
+ 증분 새로 고침은 제한된 SQL 작업 하위 집합을 지원합니다. 뷰 정의는 단일 SELECT-FROM-WHERE-GROUP BY-HAVING 블록이어야 하며, 설정 작업, 하위 쿼리, SELECT 또는 집계 함수의 DISTINCT 키워드, 창 함수 또는 INNER JOIN 이외의 조인을 포함할 수 없습니다.
+ 증분 새로 고침은 사용자 정의 함수 또는 특정 내장 함수를 지원하지 않습니다. Spark SQL 내장 함수의 하위 집합만 지원됩니다.
+ 쿼리 자동 재작성은 증분 새로 고침 제한과 유사한 제한된 SQL 하위 집합에 정의가 속하는 구체화된 뷰만 고려합니다.
+ 전체 새로 고침 작업은 전체 테이블을 재정의하고 이전 스냅샷을 사용할 수 없게 만듭니다.
+ 영숫자와 밑줄 이외의 특수 문자가 포함된 식별자는 CREATE MATERIALIZED VIEW 쿼리에서 지원되지 않습니다.
+ \$1\$1ivm 접두사로 시작하는 구체화된 뷰 열은 시스템용으로 예약되어 있습니다. AWS 는 향후 릴리스에서 이러한 열을 수정하거나 제거할 수 있는 권한을 보유합니다.
+ SORT BY, LIMIT, OFFSET, CLUSTER BY, ORDER BY 절은 구체화된 뷰 정의에서 지원되지 않습니다.
+ 교차 리전 및 교차 계정 소스 테이블은 지원되지 않습니다.
+ rand() 또는 current\$1timestamp()와 같은 비결정적 함수는 구체화된 뷰 정의에서 지원되지 않습니다.