Amazon ECS 서비스 Auto Scaling 최적화
Amazon ECS 서비스는 관리형 작업 모음입니다. 각 서비스에는 관련 작업 정의, 원하는 작업 수 및 선택적 배치 전략이 있습니다. Amazon ECS 서비스 Auto Scaling은 Application Auto Scaling 서비스를 통해 구현됩니다. Application Auto Scaling은 CloudWatch 지표를 지표 조정 소스로 사용합니다. 또한 CloudWatch 경보를 사용하여 서비스를 스케일 인 또는 스케일 아웃할 시기에 대한 임곗값을 설정합니다. 지표 목표(대상 추적 조정이라고 함)를 설정하거나 임계값(단계 조정이라고 함)을 지정하여 조정을 위한 임계값을 제공합니다. Application Auto Scaling을 구성한 후에는 서비스에 적절한 원하는 작업 수를 지속적으로 계산합니다. 또한 스케일 인 또는 스케일 아웃하여 원하는 작업 수가 변경될 경우 이를 Amazon ECS에 알립니다.
서비스 Auto Scaling을 효과적으로 사용하려면 적절한 조정 지표를 선택해야 합니다.
수요가 현재 용량보다 클 것으로 예측되면 애플리케이션을 스케일 아웃해야 합니다. 반대로, 리소스가 수요를 초과할 경우 비용을 절약하기 위해 애플리케이션을 스케일 인할 수 있습니다.
지표 식별
효과적으로 조정하려면 사용률 또는 포화도를 나타내는 지표를 식별하는 것이 중요합니다. 이 지표는 조정에 유용하도록 다음 속성을 보여주어야 합니다.
-
지표는 수요와 상관되어야 합니다. 리소스가 일정하게 유지되지만 수요가 변하면 지표 값도 변경되어야 합니다. 수요가 증가하거나 감소하면 지표가 증가하거나 감소해야 합니다.
-
지표 값은 용량에 비례하여 스케일 인되어야 합니다. 수요가 일정할 때 리소스를 더 추가하면 지표 값이 비례적으로 변해야 합니다. 따라서 작업 수를 두 배로 늘리면 지표가 50% 감소해야 합니다.
사용률 지표를 식별하는 가장 좋은 방법은 스테이징 환경과 같은 사전 프로덕션 환경에서 부하 테스트를 수행하는 것입니다. 상용 및 오픈 소스 부하 테스트 솔루션이 널리 사용됩니다. 이러한 솔루션은 일반적으로 합성 부하를 생성하거나 실제 사용자 트래픽을 시뮬레이션할 수 있습니다.
부하 테스트 프로세스를 시작하려면 애플리케이션의 사용률 지표에 대한 대시보드를 구축합니다. 이러한 지표로, CPU 사용률, 메모리 사용률, I/O 작업, I/O 대기열 길이, 네트워크 처리량이 포함됩니다. Container Insights와 같은 서비스를 통해 이러한 지표를 수집할 수 있습니다. 자세한 내용은 관찰성이 향상된 Container Insights를 사용하여 Amazon ECS 컨테이너 모니터링 섹션을 참조하세요. 이 프로세스 중에 애플리케이션의 응답 시간이나 작업 완료율에 대한 지표를 수집하고 도표를 작성해야 합니다.
작은 요청이나 작업 삽입률로 시작합니다. 애플리케이션이 워밍업될 수 있도록 몇 분 동안 이 속도를 일정하게 유지합니다. 그런 다음, 속도를 천천히 올리고 몇 분 동안 일정하게 유지합니다. 이 주기를 반복하고 애플리케이션의 응답 또는 완료 시간이 너무 느려 서비스 수준 목표(SLO)를 충족하지 못하면 매번 비율을 높입니다.
부하 테스트 중에 각 사용률 지표를 검사합니다. 부하와 함께 증가하는 지표는 가장 적합한 사용률 지표로 사용할 수 있는 가장 좋은 후보입니다.
다음으로, 포화 상태에 도달한 리소스를 식별합니다. 동시에 사용률 지표를 검사하여 어떤 지표가 높은 수준에서 먼저 평준화되는지 또는 피크에 도달한 후 애플리케이션과 먼저 충돌하는지 확인합니다. 예를 들어 부하를 추가할 때 CPU 사용률이 0%에서 70~80%로 증가하는 경우 부하를 더 추가한 후에도 이 수준을 유지한다면 CPU는 포화 상태일 수 있습니다. CPU 아키텍처에 따라 100%에 도달하지 못할 수도 있습니다. 예를 들어 부하를 추가할 때 메모리 사용률이 증가하다가 애플리케이션이 작업 또는 Amazon EC2 인스턴스 메모리 제한에 도달했을 때 갑자기 애플리케이션 충돌이 발생한다고 가정합니다. 이 상황에서는 메모리가 완전히 소모되었을 가능성이 큽니다. 애플리케이션에서 여러 리소스를 사용할 수 있습니다. 따라서 가장 먼저 고갈되는 리소스를 나타내는 지표를 선택합니다.
마지막으로, 작업 또는 Amazon EC2 인스턴스 수를 두 배로 늘린 후 부하 테스트를 다시 시도합니다. 주요 지표가 이전보다 절반 정도 증가하거나 감소한다고 가정합니다. 이 경우 지표는 용량에 비례합니다. 이는 Auto Scaling에 적합한 사용률 지표입니다.
이제 이 가상 시나리오를 고려합니다. 애플리케이션의 부하 테스트를 수행한 결과, 초당 요청 100개에서 CPU 사용률이 결국 80%에 도달한다고 가정합니다. 부하를 더 추가해도 CPU 사용률은 더 이상 증가하지 않습니다. 하지만 이렇게 하면 애플리케이션 응답 속도가 느려집니다. 그런 다음, 부하 테스트를 다시 실행하여 작업 수를 두 배로 늘리되 속도를 이전 피크 값으로 유지합니다. 평균 CPU 사용률이 약 40%로 떨어지면 평균 CPU 사용률은 조정 지표로 사용하기에 적합합니다. 반면, 작업 수를 늘린 후에도 CPU 사용률이 80%로 유지되면 평균 CPU 사용률은 적절한 조정 지표가 아닙니다. 이 경우 적절한 지표를 찾으려면 더 많은 연구가 필요합니다.
공통 애플리케이션 모델 및 조정 속성
모든 종류의 소프트웨어가 AWS에서 실행됩니다. 자체 개발되는 워크로드도 많지만, 널리 사용되는 오픈 소스 소프트웨어에 기반하는 워크로드도 있습니다. 어디에서 생성되었든 서비스의 몇 가지 일반적인 디자인 패턴을 확인할 수 있습니다. 효과적인 조정 방법은 대부분 패턴에 따라 달라집니다.
효율적인 CPU 의존 서버
효율적인 CPU 의존 서버는 CPU 및 네트워크 처리량 이외의 리소스를 거의 사용하지 않습니다. 각 요청은 애플리케이션에서만 처리할 수 있습니다. 요청은 데이터베이스와 같은 다른 서비스에 의존하지 않습니다. 애플리케이션은 수십만 개의 동시 요청을 처리할 수 있으며, 이를 위해 여러 CPU를 효율적으로 활용할 수 있습니다. 각 요청은 메모리 오버헤드가 적은 전용 스레드에서 처리되거나 각 CPU에서 요청을 지원하는 비동기 이벤트 루프가 실행되기도 합니다. 애플리케이션의 각 복제본은 요청을 균등하게 처리할 수 있습니다. CPU 이전에 고갈될 수 있는 유일한 리소스는 네트워크 대역폭입니다. CPU 의존 서비스에서는 피크 처리량에서도 메모리 사용률이 사용 가능한 리소스의 일부에 불과합니다.
이 유형의 애플리케이션은 CPU 기반 Auto Scaling에 적합합니다. 애플리케이션은 조정 측면에서 최대한의 유연성을 제공합니다. 여기에 더 큰 Amazon EC2 인스턴스 또는 Fargate vCPU를 제공하여 수직으로 규모를 조정할 수 있습니다. 또한 복제본을 더 추가하여 수평적으로 조정할 수도 있습니다. 복제본을 더 추가하거나 인스턴스 크기를 두 배로 늘리면 용량 대비 평균 CPU 사용률이 절반으로 줄어듭니다.
이 애플리케이션에 Amazon EC2 용량을 사용하는 경우 c5
또는 c6g
패밀리와 같은 컴퓨팅 최적화 인스턴스에 배치하는 방법을 고려합니다.
효율적인 메모리 의존 서버
효율적인 메모리 의존 서버는 요청당 상당한 양의 메모리를 할당합니다. 최대 동시성에서(처리량이 반드시 필요하지 않음) CPU 리소스가 고갈되기 전에 메모리가 고갈됩니다. 요청이 종료되면 요청에 연결된 메모리를 비웁니다. 사용 가능한 메모리가 있는 한, 추가 요청을 수락할 수 있습니다.
이 유형의 애플리케이션은 메모리 기반 Auto Scaling에 적합합니다. 애플리케이션은 조정 측면에서 최대한의 유연성을 제공합니다. 여기에 더 큰 Amazon EC2 또는 Fargate 메모리를 제공하여 수직으로 규모를 조정할 수 있습니다. 또한 복제본을 더 추가하여 수평적으로 조정할 수도 있습니다. 복제본을 더 추가하거나 인스턴스 크기를 두 배로 늘리면 용량 대비 평균 메모리 사용률이 절반으로 줄어들 수 있습니다.
이 애플리케이션에 Amazon EC2 용량을 사용하는 경우 r5
또는 r6g
패밀리와 같은 메모리 최적화 인스턴스에 배치하는 방법을 고려합니다.
일부 메모리 의존 애플리케이션은 요청이 종료될 때 요청에 연결된 메모리를 비우지 않으므로 동시성이 줄어도 사용되는 메모리가 줄지 않습니다. 이 경우 메모리 기반 규모 조정을 사용하지 않는 것이 좋습니다.
작업자 기반 서버
작업자 기반 서버는 각 개별 작업자 스레드에 대해 하나의 요청을 차례로 처리합니다. 작업자 스레드는 POSIX 스레드와 같은 경량 스레드일 수 있습니다. UNIX 프로세스처럼 가중치가 더 큰 스레드일 수도 있습니다. 스레드가 무엇이든 애플리케이션이 지원할 수 있는 최대 동시성은 항상 존재합니다. 일반적으로 동시성 제한은 사용 가능한 메모리 리소스에 비례하여 설정됩니다. 동시성 제한에 도달하면 추가 요청이 백로그 대기열에 배치됩니다. 백로그 대기열에서 오버플로가 발생하면 추가 수신 요청은 즉시 거부됩니다. 이 패턴에 맞는 일반적인 애플리케이션으로, Apache 웹 서버와 Gunicorn이 있습니다.
일반적으로 요청 동시성은 이 애플리케이션 규모를 조정하는 데 가장 적합한 지표입니다. 각 복제본에는 동시성 제한이 있으므로 평균 제한에 도달하기 전에 스케일 아웃하는 것이 중요합니다.
요청 동시성 지표를 확보하는 가장 좋은 방법은 애플리케이션에서 해당 지표를 CloudWatch에 보고하도록 하는 것입니다. 애플리케이션의 각 복제본은 동시 요청 수를 사용자 지정 지표로 매우 자주 게시할 수 있습니다. 빈도는 최소 1분에 한 번으로 설정하는 것이 좋습니다. 여러 보고서가 수집된 후 평균 동시성을 조정 지표로 사용할 수 있습니다. 이 지표는 전체 동시성을 계산하고 이 값을 복제본 수로 나누어 계산됩니다. 예를 들어, 총 동시성이 1,000이고 복제본 수가 10개인 경우 평균 동시 실행성은 100입니다.
애플리케이션이 Application Load Balancer 뒤에 있는 경우 로드 밸런서의 ActiveConnectionCount
지표를 조정 지표 요소로 사용할 수도 있습니다. 평균값을 구하려면 ActiveConnectionCount
지표를 복제본 수로 나눠야 합니다. 원시 개수 값과는 반대로 조정에 평균값을 사용해야 합니다.
이 설계가 가장 잘 작동하려면 낮은 요청 빈도에서 응답 지연 시간의 표준 편차가 작아야 합니다. 수요가 적은 기간에는 대부분의 요청에 짧은 시간으로 응답하고 평균 응답 시간보다 훨씬 오래 걸리는 요청은 많지 않은 것이 좋습니다. 평균 응답 시간은 95 백분위수 응답 시간에 가까워야 합니다. 그렇지 않으면 결과적으로 대기열 오버플로가 발생할 수 있습니다. 이로 인해 오류가 발생합니다. 오버플로 위험을 줄이려면 필요한 경우 추가 복제본을 제공하는 것이 좋습니다.
대기 중인 서버
대기 중인 서버는 각 요청에 대해 일부 처리를 수행하지만 작동을 위해 하나 이상의 다운스트림 서비스에 크게 의존합니다. 컨테이너 애플리케이션은 종종 데이터베이스 및 기타 API 서비스와 같은 다운스트림 서비스를 많이 사용합니다. 특히 용량이 크거나 동시성이 높은 시나리오에서는 이러한 서비스가 응답하는 데 다소 시간이 걸릴 수 있습니다. 이러한 애플리케이션은 CPU 리소스를 거의 사용하지 않고 가용 메모리 측면에서 최대 동시성을 활용하는 경향이 있기 때문입니다.
대기 중인 서비스는 애플리케이션의 설계 방식에 따라 메모리 의존 서버 패턴 또는 작업자 의존 서버 패턴 중 하나에 적합합니다. 애플리케이션의 동시성이 메모리로만 제한되는 경우 평균 메모리 사용률을 조정 지표로 사용해야 합니다. 애플리케이션의 동시성이 작업자 제한을 기반으로 하는 경우 평균 동시성을 조정 지표로 사용해야 합니다.
Java 기반 서버
Java 기반 서버가 CPU에 의존하고 CPU 리소스에 비례하여 조정되는 경우 효율적인 CPU 의존 서버 패턴에 적합할 수 있습니다. 이 경우 평균 CPU 사용률이 조정 지표로 적절할 수 있습니다. 하지만 많은 Java 애플리케이션은 CPU에 의존하지 않으므로 조정하기 어렵습니다.
최고의 성능을 위해 Java Virtual Machine(JVM) 힙에 메모리를 최대한 많이 할당하는 것이 좋습니다. Java 8 업데이트 191 이상을 포함한 최신 버전의 JVM에서는 컨테이너에 맞도록 힙 크기를 최대한 크게 자동으로 설정합니다. 즉, Java에서 메모리 사용률이 애플리케이션 사용률에 비례하는 경우는 거의 없습니다. 요청 빈도와 동시성이 증가해도 메모리 사용률은 일정하게 유지됩니다. 따라서 메모리 사용률에 따라 Java 기반 서버를 확장하지 않는 것이 좋습니다. 대신 일반적으로 CPU 사용률을 기준으로 조정하는 것이 좋습니다.
Java 기반 서버에서 CPU를 모두 소모하기 전에 힙이 고갈되는 경우도 있습니다. 애플리케이션이 동시성이 높아 힙이 고갈되기 쉬운 경우 평균 연결이 가장 좋은 조정 지표입니다. 애플리케이션이 높은 처리량에서 힙이 고갈되기 쉬운 경우 평균 요청 속도가 가장 좋은 조정 지표입니다.
기타 가비지 수집 런타임을 사용하는 서버
많은 서버 애플리케이션은 .NET 및 Ruby와 같은 가비지 수집을 수행하는 런타임을 기반으로 합니다. 이러한 서버 애플리케이션은 앞서 설명한 패턴 중 하나에 적합할 수 있습니다. 그러나 Java와 마찬가지로 메모리를 기반으로 이러한 애플리케이션은 조정하지 않는 것이 좋습니다. 관찰된 평균 메모리 사용률이 처리량이나 동시성과 관련되지 않은 경우가 많기 때문입니다.
이러한 애플리케이션의 경우 애플리케이션이 CPU에 의존하는 경우 CPU 사용률을 높이는 것이 좋습니다. 그렇지 않으면 부하 테스트 결과에 따라 평균 처리량이나 평균 동시성을 기준으로 조정하는 것이 좋습니다.
작업 프로세서
많은 워크로드에는 비동기 작업 처리가 포함됩니다. 여기에는 요청을 실시간으로 수신하지 않고 대신 작업 대기열을 구독하여 작업을 수신하는 애플리케이션이 포함됩니다. 이러한 유형의 애플리케이션에서 적절한 조정 지표는 거의 항상 대기열 깊이입니다. 대기열 증가는 보류 중인 작업이 처리 용량을 초과한다는 의미이고, 빈 대기열은 수행할 작업보다 용량이 더 많다는 의미입니다.
Amazon SQS 및 Amazon Kinesis Data Streams와 같은 AWS 메시징 서비스에서는 조정에 사용할 수 있는 CloudWatch 지표를 제공합니다. Amazon SQS의 경우 ApproximateNumberOfMessagesVisible
이 가장 좋은 지표입니다. Kinesis Data Streams의 경우 Kinesis Client Library(KCL)에서 게시한 MillisBehindLatest
지표를 사용하는 방법을 고려합니다. 이 지표를 조정에 사용하기 전에 모든 소비자를 대상으로 이 지표의 평균을 구해야 합니다.