Kubernetes를 사용하여 분산 부하 테스트

부하 테스트는 시스템이 실제 상황에서 얼마나 잘 작동하는지를 보여주므로 백엔드 인프라 개발에서 빠져서는 안 될 핵심 단계입니다. 부하 테스트에서 중요한 점은, 애플리케이션을 프로덕션 환경으로 배포하기 전에 사용자 및 기기의 동작을 적절히 시뮬레이션하여 발생 가능한 시스템 병목현상을 모두 발견하고 이해하는 것입니다.

그러나 전용 테스트 인프라는 지속적으로 필요한 인프라가 아니므로 유지보수가 어렵고 비용이 많이 들 수 있습니다. 뿐만 아니라 전용 테스트 인프라는 고정 용량을 갖는 1회성 자본 지출인 경우가 많아서 초기 투자의 규모를 초월하는 부하 테스트를 감당하기 어려우며 실험의 범위에 한계가 있을 수 있습니다. 이로 인해 개발팀의 생산성이 저하되고 애플리케이션을 적절히 테스트하지 못한 채 프로덕션 배포가 진행될 수 있습니다.

솔루션 개요

클라우드 컴퓨팅을 사용한 분산형 부하 테스트는 다양한 테스트 시나리오에서 매력적인 옵션입니다. 클라우드 플랫폼은 높은 수준의 인프라 탄력성을 제공하므로, 사용자 또는 기기를 각각 모방한 트래픽을 생성하도록 다수의 클라이언트를 시뮬레이션하여 애플리케이션 및 서비스를 손쉽게 테스트할 수 있습니다. 또한 클라우드 컴퓨팅의 가격 모델은 부하 테스트의 탄력적인 특성에 매우 잘 부합합니다.

애플리케이션용으로 완전한 가상 머신 인스턴스를 실행하는 것보다 가벼운 대안을 제공하는 컨테이너는 시뮬레이션된 클라이언트의 수를 빠르게 늘리는 데 적합합니다. 컨테이너는 가볍고, 배포가 간편하고, 즉시 사용 가능하고, 단일 작업에 적합하므로 테스트 클라이언트를 실행하는 데 유용한 추상화를 제공합니다.

Google Cloud Platform은 컨테이너를 사용한 분산 부하 테스트에 매우 적합한 환경입니다. 이 플랫폼은 오픈소스 컨테이너 클러스터 관리자인 Kubernetes를 활용한 Google Kubernetes Engine을 통해 컨테이너를 최우선적으로 지원합니다. Kubernetes Engine은 컨테이너 인프라를 빠르게 프로비저닝할 수 있으며 배포된 애플리케이션과 리소스를 관리하는 각종 도구를 제공합니다.

이 솔루션에서는 Kubernetes Engine을 사용하여 분산 부하 테스트 프레임워크를 배포하는 방법을 보여줍니다. 이 프레임워크에서는 여러 컨테이너를 사용하여 간단한 REST 기반 API에 대한 부하 테스트 트래픽을 생성합니다. 이 솔루션은 간단한 웹 애플리케이션을 테스트하지만, 동일한 패턴을 사용하여 게임이나 사물 인터넷(IoT) 애플리케이션과 같은 더욱 복잡한 부하 테스트 시나리오를 작성할 수 있습니다. 이 솔루션에서는 컨테이너 기반 부하 테스트 프레임워크의 일반적인 아키텍처를 설명합니다. 샘플 프레임워크를 설정하는 단계별 안내가 포함된 가이드는 이 문서 마지막의 가이드 섹션을 참조하세요.

이 솔루션은 Kubernetes Engine을 사용하여 부하 테스트 트래픽을 생성하는 데 중점을 둡니다. 테스트 대상 시스템은 REST API를 사용하는 간단한 웹 애플리케이션입니다. 이 솔루션은 기존 부하 테스트 프레임워크를 활용하여 API 상호작용을 모델링하며, 다음 섹션에서 여기에 대해 자세히 설명합니다. 이 솔루션은 테스트 대상 시스템을 배포한 후 Kubernetes Engine을 사용하여 분산 부하 테스트 작업을 배포합니다.

테스트 대상 시스템

소프트웨어 테스트와 관련하여 테스트 대상 시스템이란 테스트에서 평가하도록 설계된 대상 시스템을 가리키는 용어입니다. 이 솔루션의 테스트 대상 시스템은 Google App Engine에 배포된 소형 웹 애플리케이션입니다. 애플리케이션은 기본적인 REST 스타일 엔드포인트를 노출하여 수신되는 HTTP POST 요청을 캡처합니다. 수신 데이터는 유지되지 않습니다. 실제 시나리오에서는 웹 애플리케이션이 더 복잡하여 캐싱, 메시징, 데이터 유지 등의 수많은 구성요소와 서비스를 포함할 수 있습니다. 이러한 복잡성은 이 솔루션의 범위에 포함되지 않습니다. Google Cloud Platform에서 확장 가능한 웹 애플리케이션을 개발하는 방법에 대한 자세한 내용은 확장 가능하고 탄력적인 웹 애플리케이션 빌드 솔루션을 참조하세요.

샘플 애플리케이션의 소스 코드는 이 문서 마지막의 가이드에서 제공합니다.

예제 작업 부하

예제 애플리케이션은 다양한 사물 인터넷(IoT) 배포 환경에서 나타나는 백엔드 서비스 구성요소에 따라 모델링되었습니다. 기기는 우선 서비스에 등록한 후 측정항목 또는 센서 입력값을 보고하기 시작하며, 주기적으로 서비스에 다시 등록하기도 합니다.

아래 다이어그램은 일반적인 백엔드 서비스 구성요소의 상호작용을 보여줍니다.

일반적인 백엔드 서비스 구성요소 상호작용을 보여주는 다이어그램

Python을 기반으로 하는 분산 부하 테스트 도구인 Locust를 사용하여 이 상호작용을 모델링할 수 있습니다. 이 도구는 여러 대상 경로로 요청을 분산할 수 있습니다. 예를 들어 Locust는 /login/metrics 대상 경로로 요청을 분산할 수 있습니다. JMeter, Gatling, Tsung 등의 다양한 부하 생성 소프트웨어 패키지를 사용할 수 있으며, 프로젝트의 요구사항에 따라 적절히 선택하면 됩니다.

작업 부하는 위에 설명된 상호작용을 기반으로 하며 Locust에서 일련의 작업으로 모델링됩니다. 실제 클라이언트를 모방하기 위해 각 Locust 작업에 가중치가 부여됩니다. 예를 들어 등록은 총 클라이언트 요청 1,000회당 한 번 발생합니다.

컨테이너 기반 컴퓨팅

아키텍처의 관점에서 이 분산 부하 테스트 솔루션을 배포하는 데 관련되는 구성요소는 크게 두 가지로서, 하나는 Locust 컨테이너 이미지이고 다른 하나는 컨테이너 조정 및 관리 메커니즘입니다.

Locust 컨테이너 이미지는 Locust 소프트웨어를 포함하는 Docker 이미지입니다. Dockerfile은 해당 GitHub 저장소(아래 가이드 참조)에 있습니다. Dockerfile은 기본 Python 이미지를 사용하며, Locust 서비스를 실행하고 작업을 실행하는 스크립트를 포함합니다.

이 솔루션은 Google Kubernetes Engine을 컨테이너 조정 및 관리 메커니즘으로 사용합니다. 오픈소스 프레임워크인 Kubernetes를 기반으로 하는 Kubernetes Engine은 Google 전반의 컨테이너 배포를 다년간 실행, 조정, 관리해 온 제품입니다. 컨테이너 기반 컴퓨팅을 활용하면 개발자가 호스팅 환경의 배포 및 통합에 신경쓰지 않고 애플리케이션에만 집중할 수 있습니다. 또한 컨테이너는 부하 테스트에 이식성을 부여하므로 컨테이너화된 애플리케이션을 여러 클라우드 환경에서 실행할 수 있습니다. Kubernetes Engine과 Kubernetes는 컨테이너 조정 및 관리와 관련된 몇 가지 개념을 도입합니다.

컨테이너 클러스터

컨테이너 클러스터는 전체 애플리케이션의 토대가 되는 Compute Engine 인스턴스의 그룹입니다. Kubernetes Engine 및 Kubernetes 문서에서는 이러한 인스턴스를 노드라고 지칭합니다. 클러스터는 하나의 마스터 노드와 하나 이상의 작업자 노드로 구성됩니다. 마스터와 작업자가 모두 Kubernetes에서 실행되므로 컨테이너 클러스터를 Kubernetes 클러스터라고도 합니다. 클러스터에 대한 자세한 내용은 Kubernetes Engine 문서를 참조하세요.

포드

포드는 서로 긴밀하게 연결되며 함께 배포되어야 하는 컨테이너 그룹입니다. 포드에 컨테이너가 하나만 포함되기도 합니다. 예를 들어 이 솔루션에서는 각 Locust 컨테이너가 자체 포드에서 실행됩니다. 그러나 포드는 특정한 방식으로 서로 연동하는 여러 컨테이너를 포함하는 경우가 많습니다. 예를 들어 이 솔루션에서 Kubernetes는 컨테이너 3개가 포함된 포드를 사용하여 DNS 서비스를 제공합니다. 컨테이너 중 하나에서 SkyDNS가 DNS 서버 기능을 제공합니다. SkyDNS는 etcd라는 키-값 저장소에 의존하는데, 이 저장소는 다른 컨테이너에 상주합니다. 포드의 세 번째 컨테이너인 kube2sky는 Kubernetes와 SkyDNS 사이에서 다리 역할을 합니다.

복제 컨트롤러

복제 컨트롤러는 포드 '복제본'이 특정 시점에 지정된 개수만큼 항상 실행되도록 조치합니다. 포드가 너무 많으면 복제 컨트롤러가 일부 포드를 종료합니다. 포드가 너무 적으면 포드를 더 시작합니다. 이 솔루션에는 복제 컨트롤러 3개가 있습니다. 하나는 DNS 서버 포드가 1개 존재하도록 조치하고, 다른 하나는 Locust 마스터 포드를 하나로 유지하며, 세 번째는 실행 중인 Locust 작업자 포드를 정확히 10개로 유지합니다.

서비스

특정 포드는 노드 장애, 업데이트 또는 유지보수를 위한 의도적 노드 중단 등 여러 가지 이유로 소멸할 수 있습니다. 따라서 포드의 IP 주소는 해당 포드에 안정적인 인터페이스를 제공하지 못합니다. 더 안정적인 방식은 해당 인터페이스의 변하지 않는 추상적 표현을 사용하는 것입니다. 이러한 표현은 내부적으로는 포드가 소멸하여 IP 주소가 다른 새 포드로 대체되더라도 변하지 않습니다. Kubernetes Engine 서비스는 논리적 포드 집합 및 액세스 정책을 정의하여 이러한 유형의 추상적 인터페이스를 제공합니다. 이 솔루션에는 포드 또는 포드 집합을 나타내는 여러 서비스가 있습니다. 예를 들면 DNS 서버 포드용 서비스, Locust 마스터 포드용 서비스, Locust 작업자 포드 10개 전체를 나타내는 서비스가 있습니다.

아래 다이어그램에서는 마스터 노드와 작업자 노드의 내용을 보여줍니다.

마스터 및 작업자 노드의 내용을 보여주는 다이어그램

테스트 대상 시스템 배포

이 솔루션에서는 Google App Engine을 사용하여 테스트 대상 시스템을 실행합니다. 테스트 대상 시스템을 배포하려면 활성 상태인 Google Cloud Platform 계정이 있어야 Google Cloud Platform SDK를 설치하고 실행할 수 있습니다. SDK가 설치되었으면 명령어 하나만으로 샘플 웹 애플리케이션을 배포할 수 있습니다. 웹 애플리케이션의 소스 코드는 이 문서 마지막의 가이드에서 제공합니다.

부하 테스트 작업 배포

부하 테스트 작업을 배포하려면 우선 부하 테스트 마스터를 배포한 후 부하 테스트 작업자 10개가 포함된 그룹을 배포합니다. 부하 테스트 작업자가 이렇게 많으므로 테스트용으로 상당한 양의 트래픽을 생성할 수 있습니다. 그러나 외부 시스템을 향해 과도한 양의 트래픽을 생성하면 서비스 거부 공격과 구분하기 어려워질 수 있습니다. Google Cloud Platform 서비스 약관Google Cloud Platform 서비스이용 정책을 자세히 검토하시기 바랍니다.

부하 테스트 마스터

처음으로 배포할 구성요소는 위에서 설명한 부하 테스트 작업을 실행하는 진입점 역할을 하는 Locust 마스터입니다. Locust 마스터는 하나만 필요하므로 단일 복제본을 갖는 복제 컨트롤러 형태로 배포됩니다. 복제 컨트롤러는 고가용성을 보장하므로 단일 포드를 배포하는 경우에도 유용합니다.

복제 컨트롤러를 구성할 때는 컨트롤러 이름(locust-master), 조직의 라벨(name: locust, role: master), 컨테이너가 노출해야 하는 포트(웹 인터페이스의 경우 8089, 작업자 통신의 경우 55575558) 등의 몇 가지 요소를 지정합니다. 이 정보는 이후에 Locust 작업자 컨트롤러를 구성하는 데 사용됩니다. 다음 스니펫은 포트 구성을 포함합니다.

...
ports:
  - name: locust-master-web
    containerPort: 8089
    protocol: TCP
  - name: locust-master-port-1
    containerPort: 5557
    protocol: TCP
  - name: locust-master-port-2
    containerPort: 5558
    protocol: TCP

다음으로, 클러스터에 속하는 다른 포드가 노출된 포트에 hostname:port를 통해 액세스할 수 있고 설명적 포트 이름을 통해 해당 포트를 참조할 수 있도록 조치하는 서비스를 배포합니다. 이 서비스를 사용하면 마스터가 장애를 일으켜 복제 컨트롤러에 의해 새 포드로 교체되더라도 Locust 작업자가 마스터를 쉽게 탐색하여 안정적으로 통신할 수 있습니다. 또한 Locust 마스터 서비스에는 외부 트래픽을 통해 클러스터 리소스에 액세스할 수 있도록 클러스터 수준의 외부 전달 규칙을 만드는 지시문이 포함되어 있습니다. 단, 대상 인스턴스에 대해 완벽한 액세스를 제공하려면 여전히 방화벽 규칙을 만들어야 합니다.

Locust 마스터가 배포되었으면 외부 전달 규칙의 공개 IP 주소를 사용하여 웹 인터페이스에 액세스할 수 있습니다. Locust 작업자가 배포되었으면 시뮬레이션을 시작하고 Locust 웹 인터페이스를 통해 종합 통계를 볼 수 있습니다.

부하 테스트 작업자

다음으로 배포할 구성요소는 위에서 설명한 부하 테스트 작업을 실행하는 Locust 작업자를 포함합니다. Locust 작업자는 포드 10개를 생성하는 단일 복제 컨트롤러에 의해 배포됩니다. 포드는 Kubernetes 클러스터 전체에 분산됩니다. 각 포드는 환경 변수를 사용하여 테스트 대상 시스템의 호스트 이름, Locust 마스터의 호스트 이름과 같은 중요한 구성 정보를 관리합니다. 작업자의 복제 컨트롤러 구성은 아래 가이드에서 확인할 수 있습니다. 이 구성에는 컨트롤러 이름(locust-worker), 조직의 라벨(name: locust, role: worker), 앞에서 설명한 환경 변수가 포함됩니다. 다음 스니펫은 이름, 라벨, 복제본 개수에 대한 구성을 포함합니다.

kind: ReplicationController
  apiVersion: v1
  metadata:
    name: locust-worker
    labels:
      name: locust
      role: worker
  spec:
    replicas: 10
    selector:
      name: locust
      role: worker
...

작업자 포드 자체는 인바운드 통신을 지원할 필요가 없으며 Locust 마스터 포드에 직접 연결되므로 Locust 작업자에 대한 서비스를 추가로 배포할 필요는 없습니다.

아래 다이어그램은 Locust 마스터와 Locust 작업자 사이의 관계를 보여줍니다.

Locust 마스터 및 작업자 노드가 포함된 Kubernetes 포드를 보여주는 다이어그램

복제 컨트롤러가 Locust 작업자를 배포했으면 Locust 마스터 웹 인터페이스로 돌아가서 슬레이브 개수가 배포된 작업자 수와 일치하는지 확인합니다.

부하 테스트 작업 실행

부하 테스트 시작

다음 이미지와 같이 Locust 마스터 웹 인터페이스에서 테스트 대상 시스템에 대한 부하 테스트 작업을 실행할 수 있습니다.

초기 Locust 웹 인터페이스의 스크린샷

우선 시뮬레이션할 총 사용자 수 및 각 사용자를 생성할 속도를 지정합니다. 그런 다음 Start swarming(생성 시작)을 클릭하여 시뮬레이션을 시작합니다. 시간이 지나면서 사용자가 생성됨에 따라 다음 이미지와 같이 요청 수, 초당 요청 등의 시뮬레이션 측정항목 통계가 집계되기 시작합니다.

스워밍이 진행 중인 Locust 웹 인터페이스의 스크린샷

시뮬레이션을 중지하려는 경우 Stop(중지)을 클릭하면 테스트가 종료됩니다. 전체 결과를 스프레드시트로 다운로드할 수 있습니다.

클라이언트 확장

시뮬레이션할 사용자 수를 늘리려면 Locust 작업자 포드의 수를 늘려야 합니다. 복제 컨트롤러는 Locust 작업자 컨트롤러에 지정된 것처럼 Locust 작업자 포드를 10개 배포합니다. 복제 컨트롤러가 배포하는 포드 수를 늘리려는 경우를 위해 Kubernetes는 컨트롤러를 다시 배포하지 않고 크기를 조절하는 기능을 제공합니다. 예를 들어 kubectl 명령줄 도구를 사용하여 작업자 포드 수를 변경할 수 있습니다. 다음 명령어는 Locust 작업자 포드 풀의 크기를 20으로 조정합니다.

$ kubectl scale --replicas=20 replicationcontrollers locust-worker

scale 명령어를 실행한 후 모든 포드가 배포 및 시작될 때까지 몇 분 정도 기다립니다. 모든 포드가 시작되었으면 Locust 마스터 웹 인터페이스로 돌아가서 부하 테스트를 다시 시작합니다.

리소스 및 비용

이 솔루션은 Kubernetes Engine 노드 4개를 사용하며, 각 노드는 n1-standard-1 유형의 Compute Engine VM 표준 인스턴스를 활용합니다. Google Cloud Platform 가격 계산기를 사용하여 이 컨테이너 클러스터를 실행하는 월별 비용을 추산할 수 있습니다. 앞에서 설명한 것처럼, 필요에 따라 컨테이너 클러스터의 크기를 맞춤설정할 수 있습니다. 가격 계산기에서 클러스터 특성을 맞춤설정하여 규모 확장 또는 축소 시 예상되는 비용을 알아볼 수 있습니다.

다음 단계

지금까지 Kubernetes Engine을 사용하여 간단한 웹 애플리케이션에 대한 부하 테스트 프레임워크를 만드는 방법을 알아보았습니다. Kubernetes Engine을 사용하면 부하 테스트 프레임워크의 토대가 되는 컨테이너 노드의 개수를 지정할 수 있습니다. 또한 부하 테스트 작업자를 포드로 구성할 수 있고, Kubernetes Engine에서 실행을 유지할 포드 개수를 선언할 수 있습니다.

동일한 패턴을 사용하여 다양한 시나리오 및 애플리케이션에 대한 부하 테스트 프레임워크를 만들 수 있습니다. 예를 들어 이 패턴으로 메시징 시스템, 데이터 스트림 관리 시스템, 데이터베이스 시스템에 대한 부하 테스트 프레임워크를 만들 수 있습니다. 새 Locust 작업을 만들 수도 있고, 다른 부하 테스트 프레임워크로 전환할 수도 있습니다.

이 솔루션에서 제시하는 프레임워크를 확장하는 또 다른 방법은 수집되는 측정항목을 맞춤설정하는 것입니다. 예를 들어 초당 요청을 측정하거나, 부하 증가에 따른 응답 지연 시간을 모니터링하거나, 응답 실패율 및 오류 유형을 확인할 수 있습니다. Google Cloud Monitoring을 비롯하여 여러 가지 모니터링 옵션을 사용할 수 있습니다.

가이드

안내 및 소스 코드를 포함한 가이드의 전체 내용은 GitHub(https://github.com/GoogleCloudPlatform/distributed-load-testing-using-kubernetes)에서 확인할 수 있습니다.

이 페이지가 도움이 되었나요? 평가를 부탁드립니다.

다음에 대한 의견 보내기...