Amazon EC2 스팟 인스턴스를 통한 EMR 기반 Apache Spark 활용 10가지 모범 사례
Apache Spark는 사용 편의성, 빠른 성능, 메모리 및 디스크 사용률과 내결함성 등 다양한 이유로 가장 인기 있는 오픈소스 빅데이터 분석 플랫폼이 되었습니다. 이러한 기능은 인스턴스의 폐기 및 삭제가 가능한 클라우드 컴퓨팅의 개념과 매우 깊은 관련이 있습니다.
Amazon EMR은 EC2 인스턴스를 사용하여 방대한 양의 데이터를 쉽고 빠르고 경제적으로 처리할 수 있는 관리형 하둡 프레임워크를 제공합니다. Amazon EMR을 사용하면 Spark 소프트웨어(또는 하둡 프레임워크의 다른 모든 도구)의 설치, 업그레이드 및 유지 관리를 걱정할 필요가 없습니다. 기반 하드웨어 또는 운영 체제의 설치 및 유지 관리에 대해서도 걱정할 필요가 없습니다. 대신, 비즈니스 애플리케이션에 집중할 수 있으며 별 다를 것이 없는 힘든 작업은 Amazon EMR을 통해 제거할 수 있습니다.
EC2 스팟 인스턴스 구매 옵션은 온디맨드 요금에 비해 대폭 할인된 요금으로 AWS 클라우드에서 사용 가능한 예비 컴퓨팅 용량을 제공합니다. EC2에서 용량을 다시 사용해야 할 때는 2분 전에 알림을 제공하여 스팟 인스턴스를 중지할 수 있습니다. 고객은 내결함성 및 유연성을 갖춘 다양한 애플리케이션에 스팟 인스턴스를 사용할 수 있습니다. 예를 들어 분석, 컨테이너식 워크로드, HPC(고성능 컴퓨팅), 상태 비저장 웹 서버, 렌더링, CI/CD와 기타 테스트 및 개발 워크로드가 여기에 포함됩니다.
이 글에서는 Amazon EMR에서 스팟 인스턴스를 사용하여 Spark 애플리케이션의 비용을 최적화하고 효율적으로 실행하는 방법을 중점적으로 살펴봅니다. Spark 애플리케이션의 내결함성을 강화하고 스팟 인스턴스를 사용하는 몇 가지 모범 사례가 있습니다. 이러한 모범 사례는 가용성, 성능 또는 작업 기간에 큰 영향을 미치지 않습니다.
1. 스팟 인스턴스 어드바이저를 통한 적합한 작업 유형 결정하기
스팟 인스턴스는 EC2에서 용량을 다시 사용해야 하는 경우 중단될 수 있습니다. 이 블로그 게시물에서는 스팟 중단으로 인한 기반 EC2 인스턴스의 간헐적인 손실을 견딜 수 있도록 Spark 애플리케이션의 내결함성을 강화하는 방법이 필요합니다. 특히, 중단 비율이 낮은 EC2 스팟 인스턴스를 대상 인스턴스로 결정하는 것이 더 큰 도움이 될 수 있습니다. 이렇게 하면 중단이 발생할 경우 Spark에서 일부 작업을 다시 실행하여 작업이 길어지는 가능성을 줄일 수 있습니다.
스팟 인스턴스 어드바이저를 사용하여 중단 비율을 확인하고 기록상 중단 비율이 낮은 인스턴스 유형을 사용하여 Amazon EMR 클러스터를 생성해 볼 수 있습니다. 예를 들어 이 게시물의 작성 시점을 기준으로 미국 동부(오하이오) 리전에서 r4.2xlarge의 중단 빈도는 5% 미만입니다. 다시 말해, 지난 30일간 시작된 전체 r4.2xlarge 스팟 인스턴스의 5% 미만이 EC2에 의해 중단되었습니다.
2. 다양한 인스턴스 세트로 작업 실행하기
EC2 인스턴스에서 워크로드(분석 또는 기타)를 실행하고 온디맨드 또는 예약 인스턴스 구매 옵션을 사용하는 경우 일반적으로 전체 클러스터에서 단일 인스턴스 유형을 사용합니다. 벤치마킹을 통해 애플리케이션 요구 사항에 적합한 인스턴스 유형을 찾은 후 단일 인스턴스 유형을 사용하게 될 수 있습니다. 그러나 스팟 인스턴스에서는 클러스터에서 여러 스팟 용량 풀(가용 영역의 인스턴스 유형)을 사용하는 것이 중요합니다. 이렇게 하면 확장성을 확보하고 작업 실행에 필요한 용량을 보존할 수 있습니다.
예를 들어 온디맨드 r4.xlarge 인스턴스(30.5GiB 메모리 및 vCPU 4개)를 사용하여 Spark 애플리케이션을 실행한다고 합시다. 스팟 인스턴스 사용을 시작할 때 vCPU 대 메모리 비율(vCPU당 약 7GB)이 유사한 여러 인스턴스 유형을 사용하여 Amazon EMR 클러스터의 코어 또는 작업 인스턴스 플릿을 구성하고 클러스터에서 실행할 적합한 인스턴스 유형을 자동으로 선택하도록 EMR을 구성할 수 있습니다. 여기에는 r4.2xlarge, r5.xlarge, i3.2xlarge 및 i3.4xlarge가 포함됩니다. 이 접근 방식을 사용하면 클러스터를 시작하기에 충분한 스팟 용량을 확보할 가능성이 더 높아집니다. 또한 EC2 스팟 중단에 의해 클러스터의 일부 용량이 종료될 경우 Amazon EMR이 클러스터의 지속적인 실행에 필요한 용량을 다른 용량 풀에서 보충할 수 있는 가능성도 높아집니다.
인스턴스 유형 | vCPU 수 | RAM(GB) |
R4.xlarge | 4 | 30.5 |
R4.2xlarge | 8 | 61 |
R5.xlarge | 4 | 32 |
I3.2xlarge | 8 | 61 |
I3.4xlarge | 16 | 122 |
3. 다양한 인스턴스 타입을 위한 Spark 실행기 수 조정하기
방금 설명한 대로 스팟 인스턴스 기반 실행의 핵심 요소 중 하나는 다양한 인스턴스 플릿(Fleet)을 사용하는 것입니다. 이 방법을 사용하면 스팟 중단이 작업에 미치는 영향을 낮출 수 있습니다. 이 접근 방식은 Spark 애플리케이션의 아키텍처를 고려한 것입니다.
메모리 집약적인 실행기(20GB 이상 RAM)를 실행하는 경우 애플리케이션을 특정 인스턴스 유형 세트에 맞춰야 합니다. 이러한 인스턴스 유형에는 클러스터를 구동하는 데 충분한 스팟 용량이 없거나 스팟 중단 비율이 높아 실행 중인 작업에 영향을 미칠 수 있습니다.
예를 들어 RAM이 90GiB이고 실행기당 코어 수가 15개인 Spark 애플리케이션의 경우 하드웨어 요구 사항을 충족하고 스팟 중단 비율이 20% 미만인 인스턴스 유형은 11개 뿐입니다. 여기서 코어당 6GiB RAM을 유지하면서 실행기당 코어 수 2개로 실행기를 분리하면 20% 미만의 중단 비율로 작업을 실행할 수 있는 인스턴스 유형이 20개가 추가됩니다.
실행기 수를 조정하는 적절한 접근 방식은 애플리케이션을 실행할 코어의 최소 수를 결정하는 것입니다. 처음에는 2개가 적당합니다. 이후 다음 계산을 사용하여 메모리를 할당합니다.
NUM_CORES * ((EXECUTOR_MEMORY + MEMORY_OVERHEAD) / EXECUTOR_CORES)
이 예에서는 2 * ((90+20) / 15) = 15GB입니다.
memoryOverhead 설정에 대한 자세한 내용은 Spark 설명서를 참조하십시오.
4. Spark에서 다량의 셔플 방지하기
Amazon EMR 클러스터에서 스팟 인스턴스가 중단되는 경우 Spark에서 재처리해야 하는 데이터의 양을 줄이려면 다량의 셔플을 방지해야 합니다.
GroupBy 및 일부 조인 유형처럼 종속성이 넓은 작업에서는 방대한 양의 중간 데이터가 생성될 수 있습니다. 중간 데이터는 로컬 디스크에 저장된 후 클러스터의 다른 실행기로 전송(셔플)됩니다.
항상 가능한 것은 아니지만 셔플 작업을 방지하거나 셔플 데이터의 양을 최소화하는 방향으로 작업을 진행하는 것이 좋습니다. 그 이유는 두 가지입니다.
- 일반적인 Spark 모범 사례인 이유는 셔플 작업이 많은 비용을 야기하는 작업이기 때문입니다.
- 스팟 인스턴스의 맥락에서 셔플을 수행하면 작업의 내결함성이 저하됩니다. 셔플 데이터가 포함되거나 셔플된 데이터를 계산에 사용하는 노드(일반적으로 둘 다 해당)가 중단되면 셔플 프로세스의 일부를 다시 실행해야 하기 때문입니다.
필요 이상의 셔플 데이터를 생성하는 몇 가지 패턴은 다음과 같습니다.
그룹으로 익스플로드 패턴
개발자 관점에서는 복합 데이터 유형에서 익스플로드를 사용하여 일부 사용 사례를 빠르게 해결할 수 있습니다(배열을 여러 행으로 익스플로드). 그러면 행 수가 배로 늘어나는데 나중에 작업에서 이러한 행을 다시 조인할 수 있습니다.
예를 들어 사용자 ID와, 웹 사이트 방문을 설명하는 날짜 배열이 포함되는 데이터가 있다고 가정합시다.
A | B | |
1 | user_id | visit_dates_array |
2 | 0 | [ “28/01/2018”29/01/2018”, “01/01/2019”] |
3 | 100000 | [ “01/11/2017”, “01/12/2017”] |
4 | 999999 | [ “01/01/2017”, “02/01/2017”, “03/01/2017”, “04/01/2017”, “05/01/2017”, “06/01/2017”] |
웹 사이트에서 사용자 방문 수의 합계를 계산하는 Spark 애플리케이션을 실행한다고 합시다. 이 경우 간단한 솔루션은 다음과 같이 익스플로드를 사용한 다음 데이터를 집계하는 것입니다.
데이터를 익스플로드합니다.
데이터를 다시 집계합니다.
이 방법은 빠르고 쉽지만 데이터의 양이 원래 데이터보다 3배 더 커집니다. 또한 각 user_id의 방문 수를 정확히 합산하려면 네트워크 전체에서 다른 실행기로 데이터를 전송해야 합니다.
익스플로드 및 그룹화 대신 사용할 수 있는 방법은 무엇일까요?
한 가지 옵션은 현재 위치에서 계산을 수행하는 UDF를 생성하여 셔플을 방지하거나 최소화하는 것입니다. 다음은 Scala에 있는 예제입니다.
다른 옵션은 최근 Spark 2.4에 도입된 집계 함수를 사용하는 것입니다. 이 함수를 사용하면 셔플 데이터의 양을 user_id와 방문 수의 최소한으로 줄일 수 있습니다.
대규모 데이터 조인(버킷팅)
조인 작업을 수행할 때 Spark에서는 데이터가 조인 키로 재분할(셔플)됩니다.
동일한 테이블에서 동일한 키를 사용하여 여러 조인을 수행하는 경우 버킷팅을 사용하여 데이터를 한 번만 셔플할 수 있습니다. 데이터를 유지하는 경우에는 Amazon S3에서 데이터가 “미리 셔플”되어 있으므로 동일한 키를 사용한 후속 조인에서 셔플이 필요하지 않습니다.
데이터를 버킷팅하려면 데이터를 분할할 버킷과 버킷팅을 수행할 열 수를 결정해야 합니다.
5. 데이터 불균형 작업을 피하기 위한 고려하기
일부 경우에는 파티션 간 데이터 분포가 균일하지 않습니다. 데이터 불균형은 여러 이유로 문제가 됩니다.
- 일반적으로 대부분의 실행기는 정시에 완료됩니다. 그러나 다량의 이상값을 처리하는 실행기는 더 오래 실행됩니다. 그러면 스팟 인스턴스 중단이 발생하고 전체 작업을 다시 계산해야 하는 위험이 증가합니다. 또한 전체 성능에 부정적인 영향을 미치며 작업 시간이 길어지거나 리소스가 제대로 활용되지 않는 결과를 야기합니다.
- 데이터 불균형은 다량의 데이터 셔플이 원인이 되어 앞서 설명한 문제를 야기할 수도 있습니다.
데이터 불균형을 처리하려면 실행기에서 로컬로 계산을 수행하는 것이 좋습니다. 그런 다음 결과를 다시 계산합니다. 이 접근 방식을 결합 작업이라고도 합니다.
데이터 불균형을 처리하는 일반적인 기술은 키를 재배치(Sort)하는 것입니다.
6. 대규모 Spark 작업을 세분화 하여 복원력 개선하기
발생 가능한 안티패턴 중 하나는 완료하는 데 몇 시간 또는 며칠이 걸릴 수 있는 수많은 작업을 수행하는 대규모 애플리케이션입니다.
이 종류의 작업에서는 전부 아니면 전무의 상황이 발생합니다. 여기서는 오류 하나가 작업 실행 시간 전체에 적용되는 문제로 발전하여 많은 시간과 비용을 초래할 수 있습니다.
당연한 말이지만, 작업을 작은 작업의 체인으로 분리하면 오류 및 스팟 중단을 처리할 수 있는 복원력이 개선됩니다. 또한 작업을 분리하면 작업의 성공적인 완료를 방해하는 모든 문제를 해결할 수 있습니다. 게다가 이미 프로세스에 투입한 수고가 무용지물이 될 가능성도 낮아집니다.
7. EMR 인스턴스 플릿 작업 최대한 활용하기
Amazon EMR 인스턴스 플릿을 몇 가지 기술과 함께 사용하면 Spark 작업을 효율적으로 수행할 수 있습니다.
클러스터 내 EC2 인스턴스 유형의 다변화
Amazon EMR 인스턴스 플릿을 구성하면 각 Amazon EMR 노드 유형(마스터, 코어, 작업)에 대해 최대 5개의 EC2 인스턴스 유형 플릿을 설정할 수 있습니다. 앞서 설명한 대로 Amazon EMR 클러스터에 대한 스팟 용량을 시작하고 유지하려면 인스턴스 유연성을 확보하는 것이 중요합니다.
마스터 노드 그룹의 경우 Amazon EMR은 사용자가 선택한 인스턴스 중 하나를 선택합니다. 코어 및 작업 노드 그룹의 경우 Amazon EMR은 용량 가용성 및 낮은 요금을 기준으로 클러스터에 사용하기에 가장 적합한 인스턴스 유형을 선택합니다. 사용자는 서로 다른 가용 영역의 여러 서브넷을 지정할 수도 있습니다. 이 경우 Amazon EMR은 대상 용량에 가장 적합한 AZ를 선택하여 전체 클러스터를 시작합니다.
작업의 하드웨어 요구 사항에 따라 EMR 인스턴스 플릿의 크기 조정
Amazon EMR 인스턴스 플릿을 사용하는 경우 애플리케이션에 적합한 인스턴스 유형을 지정하여 리소스 풀을 정의할 수 있습니다. 또한 풀 내에서 대상 용량에 대한 각 인스턴스 유형의 가중치를 지정할 수 있습니다.
기본적으로 인스턴스에는 인스턴스의 vCPU 수에 상응하는 가중치가 지정됩니다. 그러나 다른 인스턴스 특성(예: 메모리)에 따라 가중치를 지정할 수도 있습니다. 이 섹션에서는 메모리를 기준으로 가중치를 지정하는 방법을 보여드리겠습니다.
CPU로 크기 조정:
예를 들어 실행기당 코어 4개와 코어당 1GB RAM이 필요한 작업이 있는 경우 Spark 구성은 다음과 같습니다.
실행기 20개로 작업을 실행할 것이므로 80개 코어(20*4)가 필요합니다.
스크린샷에는 작업을 실행하는 데 필요한 코어 80개를 나타내는 80개의 스팟 단위가 나와 있습니다. 하드웨어 요구 사항에 적합한 다수의 인스턴스 유형에 대한 선택도 나와 있습니다.
Amazon EMR은 이러한 인스턴스 유형의 모든 조합을 선택하여 80개 스팟 단위라는 대상 용량을 충족합니다. 크기가 큰 일부 인스턴스 유형에서는 2개 이상의 실행기가 실행될 수 있습니다.
메모리로 크기 조정
메모리 집약적인 일부 Spark 애플리케이션에는 다른 가중치 전략이 필요합니다.
예를 들어 코어 4개와 코어당 6GB가 필요한 작업을 실행하는 경우(--executor-cores 4 --executor-memory 24G) 먼저, 최소 28GB 이상의 RAM이 있는 인스턴스를 선택합니다.
스크린샷에 나와 있듯이 이 구성에서 인스턴스 유형 선택은 메모리 요구 사항을 수용하도록 설정됩니다. 그러면 약 15~20%의 메모리를 인스턴스 운영 체제 내에서 실행되는 다른 프로세스에 사용할 수 있습니다.
다음으로, 가장 작은 적격 인스턴스의 단위 수를 원하는 실행기 수에 곱해 총 단위 수를 계산합니다(25*100).
CPU 집약적인 작업과 마찬가지로 일부 인스턴스 유형에서는 1개의 실행기만 실행되고 다른 인스턴스 유형에서는 여러 개의 실행기가 실행됩니다.
인스턴스 세대 간 성능 차이 보완
일부 워크로드의 경우 최신 인스턴스 유형을 실행하는 것으로 최대 50%의 성능 개선을 확인할 수 있습니다. 이 효과는 AWS Nitro 기술, 빠른 CPU 클록 속도 또는 다양한 CPU 아키텍처(Haswell/Broadwell에서 Skylake로 이동) 또는 이러한 기술의 조합에서 기인합니다.
애플리케이션 실행 시간을 줄이는 것이 중요한 요구 사항 중 하나라면 이전 인스턴스 세대에 지정하는 가중치를 줄여 인스턴스 유형 세대 간의 성능 차이를 상쇄할 수 있습니다.
예를 들어 10 r5.2xlarge 인스턴스에서 1시간 동안 작업을 실행하고 10 r4.2xlarge 인스턴스에서 2시간 동안 작업을 실행하는 경우 인스턴스 플릿을 다음과 같이 정의하는 것이 좋을 수 있습니다.
각 노드 유형에 적합한 구매 옵션 선택
스팟 블록은 기간이 정의된 스팟 인스턴스입니다. 중단 없이 최대 6시간까지 실행할 수 있고 스팟 인스턴스에 비해 할인 비율이 작습니다. 그러나 클러스터 실행 시간이 6시간 미만으로 예측된다면 스팟 중단이 허용되지 않는 작업에도 스팟 블록을 사용할 수 있습니다.
- 마스터 노드: 클러스터 실행 시간이 매우 짧고 실행 시 비용이 중요한 것이 아니라면 마스터 노드를 스팟 인스턴스에서 실행하지 마십시오. 마스터 노드에서 스팟 중단이 발생하면 전체 클러스터가 종료되기 때문입니다. 온디맨드의 대안으로, 마스터 노드에서 스팟 블록을 설정할 수 있습니다. 기간이 정의된 노드를 설정하고 스팟 블록 용량을 사용할 수 없는 경우 온디맨드로 장애 조치하면 됩니다.
- 코어 노드: 클러스터의 작업에 HDFS가 사용되는 경우 코어 노드에 스팟 인스턴스를 사용하지 마십시오. 그러면 스팟 중단으로 인해 인스턴스의 HDFS 볼륨에 기록되는 데이터가 손실되는 상황이 방지됩니다.
- 작업 노드: 하드웨어 요구 사항에 일치하는 최대 5개의 인스턴스 유형을 선택하여 스팟 인스턴스를 작업 노드에 사용합니다. Amazon EMR은 요금 및 용량 가용성을 기준으로 가장 적합한 용량을 제공합니다.
8. EC2 스팟 중단 알림 사용하기
EC2에서 스팟 인스턴스를 중단해야 하는 경우 중단될 각 인스턴스에 대해 2분 전 경고가 생성됩니다. 이 경고에는 인스턴스 안에서 인스턴스의 메타데이터 서비스를 폴링하고 Amazon CloudWatch Events를 사용하는 두 가지 프로그래밍 방식으로 대응할 수 있습니다. 설명서에서 구체적인 내용을 확인할 수 있습니다.
이 경고의 사용은 워크로드 유형에 따라 다릅니다. 예를 들어 곧 중단될 인스턴스를 Elastic Load Balancer에서 분리하여 인스턴스가 종료되기 전에 실행 중인 연결을 드레이닝할 수 있습니다. 또는 로그를 중앙 위치로 복사하거나 애플리케이션을 정상적으로 종료할 수 있습니다.
EMR에서 EC2 스팟 중단을 처리하는 방법에 대한 자세한 내용은 AWS 빅 데이터 블로그 게시물을 참조하십시오. Amazon EMR의 탄력성 및 복원성을 위한 Spark 강화
Amazon EMR 작업 실패와 스팟 중단 또는 작업 기간 간의 연관성을 파악하기 위해 스팟 중단을 추적하는 것이 필요할 수 있습니다. 이 경우 CloudWatch 이벤트를 설정하여 중단에 대한 피드를 데이터 스토어에 제공하는 AWS Lambda 함수를 트리거할 수 있습니다. 이 접근 방식을 사용하면 계정의 중단 기록을 쿼리할 수 있습니다. 작은 규모 또는 초기 테스트에서는 Amazon SNS를 이메일 대상과 함께 사용하여 중단 알림을 이메일로 받을 수 있습니다.
9. EMR 클러스터 태그 지정 및 비용 추적
가장 기본적인 모범 사례 중 하나는 AWS 클라우드의 리소스에 태그를 지정하는 것입니다. 태그 지정 전략에 대한 자세한 내용은 AWS Answers 페이지를 참조하십시오. Amazon EMR에서 클러스터에 태그를 지정하면 기반 EC2 인스턴스와 클러스터에서 생성된 Amazon EBS 볼륨으로 태그가 전파됩니다. 태그를 사용하면 Amazon EMR 클러스터의 실행 비용을 전체적으로 파악하고 AWS Cost Explorer를 사용하여 손쉽게 시각화할 수 있습니다.
10. 다양한 고객 사례 참고하기
Amazon EMR에서 스팟 인스턴스를 활용하여 비용 효율적인 분석 플랫폼을 구축한 고객들이 많이 있습니다. 아래 사례들을 참고해 보시기 바랍니다.
그 밖에도 아래 사례도 직접 확인해 보시기 바랍니다.
마무리
이 글에서는 Amazon EMR에서 스팟 인스턴스를 사용하여 Spark 애플리케이션의 비용을 최적화하기 위한 모범 사례에 대해 알아봤습니다. 유용한 정보를 얻으셨기를 바라며 이러한 모범 사례를 Spark 애플리케이션에서 테스트하여 워크로드 비용을 최적화할 수 있기를 바랍니다. 더 자세한 것은 기술 문서 및 고객 사례를 참고하세요.
이 글은 AWS Bigdata 블로그의 Best practices for running Apache Spark applications using Amazon EC2 Spot Instances with Amazon EMR의 한국어 편집본으로 마지막 고객 사례 일부를 편집 추가하였습니다.
Source: Amazon EC2 스팟 인스턴스를 통한 EMR 기반 Apache Spark 활용 10가지 모범 사례