6 min to read
성능 테스트 #1 / TIL
가용성과 확장성 / 부하 테스트
가용성과 확장성
가용성
시스템이 정상적으로 사용 가능한 정도. 정상적인 사용시간을 전체 사용 시간(정상사용 시간-Uptime + 사용불가 시간-Downtime)으로 나눈 값을 표현한다. 서비스 사용 불가 시간을 최소로 만들어야 가용성이 올라간다.
ex > 가용성 99.95%는 약 1년에 4시간 22분의 Downtime이 된다.
가용성의 핵심은 단일 장애점 (Single Point of Failure)을 없애는 것이어야 한다. 즉, 어떤 한 노드가 장애가 발생해도, 동일한 처리 능력을 가진 다른 노드로 대체될 수 있어야 한다. 이를 위해 시스템 확장이 필요하다.
확장성
확장 가능한 시스템 : 요구되는 시스템의 성능에 따라 동적으로 서버 구성이 변경되고, 시스템 처리 능력을 최적화할 수 있는 시스템
- 시스템의 처리 능력 확장 : 하나의 머신에서 메모리나 CPU를 늘리는 수직 확장(Scale Up), 머신의 인스턴스 수를 늘리는 수평 확장(Scale Out)
- 수직 확장은 한계가 있으므로, 수평 확장이 가능할 때 확장성이 좋다고 평가할 수 있다.
- AWS와 같은 클라우드 사업자가 확장성을 보증하는 경우도 존재한다. 기본적으로 AWS 등에서 제공하는 서버리스 서비스들은 확장성이 좋다.
수직 확장을 고려할 경우 Downtime이 발생하여 가용성이 떨어지며, 성능 제한이 있으므로 반드시 한계를 이해해야 한다.
부하 테스트
부하 테스트의 목적
- 시스템 확장성을 가졌는지 확인하기 위해
- 성능을 개선하기 위해 확장해야 하는 시스템이 무엇인지 파악하기 위해
- 부하가 많이 발생할 때 문제 상황을 개선하기 위해
- 각 시스템의 병목 지점을 예측하고 진단 및 개선하기 위해
시스템을 확장할 때는 어떤 부분을 확장할 것인지, 확장성에 대한 특징을 파악하는 것이 중요하다. 하지만 어떤 부분을 확장해야 성능이 높아질지 고민하기 앞서 Throughput과 관련한 지표를 먼저 이해해야 한다.
Throughput
시간당 처리량으로, 데이터 전송량에 포커스를 맞춘 성능 지표이다. 시스템의 성능 지표는 RPS(Request Per Second), TPS(Transaction Per Second)와 같은 단위로 표현된다.
볼륨 성능을 측정할 경우 IOPS(Input/Output Per Second)라는 단위를 사용한다. 성능을 측정할 때는, 인프라 내의 구성요소(티어)로 구분된 각 요소를 구분하기 않고 통합해서, 특정 작업의 얼마만큼의 Throughput을 갖는지를 측정한다.
Throughput의 예
- 1초에 처리하는 HTTP 요청 수 (rps)
- 네트워크로 정송되는 데이터 전송 속도 (동영상 스트리밍 서비스 같이 대역폭이 중요한 경우)
그렇다면, 다음과 같은 질문을 던질 수 있다.
-
Q1. 1000rps에서 2000rps로 성능을 두 배 개선하기 위해서는, 웹서버를 확장해야 할까? DB 서버를 확장해야 할까?
A. 1000rps(초당 요청)에서 2000rps로 성능을 두 배로 늘리려면 두 구성 요소가 요청을 처리하고 처리하는 데 중요한 역할을 하기 때문에 일반적으로 웹 서버와 데이터베이스 서버를 모두 확장해야 한다.
-
Q2. 시스템 구성 변경 시 다운타임은 얼마나 허용되는가? 서비스 정지 없이 가능한가?
A. 시스템 구성 변경에 허용되는 중단 시간은 응용 프로그램의 특성, 특정 변경 사항, 사용자 또는 고객의 허용 범위, 중단 시간이 비즈니스에 미치는 전반적인 영향을 비롯한 여러 요인에 따라 달라진다. 일반적으로 가동 중지 시간을 최소화하거나 제거하는 것이 중단 없는 서비스를 보장하는 데 바람직하다.
-
Q3. 현재 시스템에서 낼 수 있는 최대 성능(limit)은 어디까지인가?
A. 시스템의 최대 성능 제한을 결정하는 것은 하드웨어 사양, 소프트웨어 아키텍처, 네트워크 인프라 및 제공되는 특정 워크로드 또는 애플리케이션을 비롯한 다양한 요인에 따라 달라진다.
사용자의 요청이 많아 부하가 많이 발생하는 경우, 실제로 시스템이 일으키는 문제와 발생할 수 있는 요소는 다음과 같다.
- 응답 속도(Latency) 저하
- 시스템 잠금(Lock) 경합
- 부하 발생 시 애플리케이션 또는 서버 에러 발생
- 데이터 일관성 문제와 손실
이러한 문제 상황을 해결할 수 있을 만큼의 부하의 수용 범위를 파악해야 한다.
Latency(처리 시간)
사용자가 어떤 웹 페이지를 보려고 할 때 페이지가 로드되고 표시되는 데 걸리는 시간에 영향을 줄 수 있는 다양한 요소(사용자의 인터넷 환경, 브라우저 등)가 있다. 또한 데이터가 네트워크를 통해 앞 뒤로 이동하는 데 걸리는 시간(네트워크를 통한 데이터 왕복 시간)도 전체 대기 시간에 영향을 준다. 그러나 성능 테스트를 진행할 때에는, 사용자 환경과 관련된 특정 변수는 제어되거나 전혀 고려되지 않고 테스트를 진행한다. 이를 통해 통제된 상황에서 시스템 성능을 일관되게 테스트하고 비교할 수 있다.
이후 언급하는 Latency는 네트워크 상황을 고려하지 않은 시스템 요청을 받고 응답을 줄 때까지의 시간만을 의미한다.
▲ 하위 시스템으로 구성된 경우에서의 Throughput과 Latency
위 사진에서 하위 시스템은 서울/대구/부산 각각 도시를 의미하며, 각 도시 간에는 서로 다른 Throughput과 Latency를 가진 고속도로 두 개가 존재한다고 가정하자.
- Latency는 대기 시간을 포함한, 각 하위 시스템 처리 시간의 총 합으로 계산한다.
- 반면 Throughput은 하위 시스템 Throughput 중 최소값은 전체 시스템의 Throughput으로 계산한다.
- 서울-부산 간 Latency : 각 구간의 소요 시간 합계인 5시간
- 서울-부산 간 Throughput : 각 구간에 도달하는 차량 대수 중 최소값인 800대/시간
시스템 성능 지표인 Throughput과 Latency를 바탕으로 개선할 경우, 어떤 부분을 먼저 개성해야 할까?
Throughput 개선
세 도시를 연결하는 두 개의 고속도로 중 대구-부산 간 고속도로가 병목을 일으키고 있다고 가정할 때, 서울-부산 사이의 Throughput은 최소값인 200대/시간에 불과하다.
이 경우 도로 확장 공사를 통해 병목을 해결한다. 확장 공사를 마친 대구-부산 간 고속도로의 Throughput이 800대/시간으로 개선되었다.
병목이 아닌 구간(서울-대구)을 개선하는 것은, 전체의 Throughput을 개선하는 데에 전혀 도움이 되지 않는다. 도리어 대구-부산 간의 정체가 늘어나 Throughput이 감소할 수도 있다. 따라서, Throughput 개선을 위해서는 병목 구간이 어디인가를 먼저 파악하는 것이 가장 중요하다.
Latency 개선
Latency의 개선은 개발된 애플리케이션을 개선하는 것으로 시작한다. 애플리케이션 성능 최적화는 현상을 파악(APM, Application Performance Monitoring)하는 것으로 시작하며, 알고리즘 개선, I/O 최소화 등의 개선 방안이 뒤따른다. DevOps가 이를 모니터링할 수는 있으나, 결국 개발자가 APM 도구와 프로파일러 등을 이용해 이를 개선해야 한다.
한편 앞서 고속도로의 예를 살펴보면, Throughput의 개선이 Latency의 개선으로 이어진 것을 확인할 수 있다. 이는 곧 Latency(대기시간)에 문제가 있다는 의미이다. 만일 애플리케이션이 실행 환경(하위 시스템)의 성능을 최대한 활용할 수 있다면, 하위 시스템의 확장에 따라 Throughput도 개선되며, 대기 시간도 줄어든다. 즉 많은 경우 Throughput이 개선되면 Latency도 개선된다.
서비스를 시작한 후 발생할 수 있는 문제 시나리오 응답 성능의 병목을 가져다준다. 아래 시나리오는 매우 일반적이며, 부하 테스트를 통해 응답 성능을 예측할 수 있다. 애플리케이션 수준에서의 대책을 온전히 이해하기는 어렵지만, 주요 키워드를 학습하여 개발자에게 솔루션을 제공할 수는 있어야 한다.
- 많은 사용자의 서비스 등록
- 많은 데이터 저장 - DB에 데이터가 증가한다. secondary 복제본 등을 이용해 읽기/쓰기를 분리하거나, 검색에 최적화된 인덱스 사용을 고려할 수 있다.
- 단기간 동안의 사용자 요청 증가 (peak traffic) - Auto Scaling이 해결책이 될 수 있다. (버스트 성능에 대한 이해 필요)
- 배치 작업을 진행하는 데이터베이스 - DB가 주기적으로 스냅샷을 만들거나, 데이터 일관성을 위해 레플리카와의 sync 과정을 진행하는 등의 배치 작업이 이루어질 경우, primary DB는 성능 저하가 발생할 수 있다. 이때 사용자들의 요청과 맞물려 서비스 수준을 맞추기 어려울 수 있다.
- 많은 양의 로그 수집 처리 - 애플리케이션이 잘 작동할 때에는 로그를 많이 남기지 않지만, 애플리케이션에 문제가 발생하면 추적을 위해 많은 로그를 남긴다. 다만 이러한 상황이 반복적으로 진행될 경우, 에러 로그 수집 그 자체가 애플리케이션 병목을 일으킬 수 있다.
- 시스템 재시작 후의 캐시 초기화 - 큰 문제를 발생시키는 것은 아니지만, 캐시가 초기화되면서 시스템으로 직접적인 요청 횟수가 증가할 수 있다.
병목 구간을 확인하는 것은 부하 테스트의 주요 목적이면서, 또한 좋은 부하 테스트를 만드는 기본이다. 시스템에서 문제가 발생할 수 있는 부부을 다이어그램으로 표현하면 다음과 같다.
-
Q. AWS에서는 인스턴스나 볼륨에 대해서 버스트 기능을 제공한다. 이는 평소에 사용하지 않을 때의 성능을 모아두고, 부하가 발생할 경우 일시적으로 성능을 올리는 기능이다. 이것이 어떤 메커니즘으로 작동하는지 연구해보자.
A. AWS는 Amazon EC2 Burstable Instances 및 Amazon EBS Balance와 같은 기능을 통해 인스턴스 및 볼륨에 버스팅 기능을 제공한다. 이러한 기능을 통해 사용자는 인스턴스 또는 볼륨이 더 낮은 기본 성능으로 프로비저닝된 경우에도 워크로드에 필요할 때 추가 성능 리소스를 활용할 수 있다.
AWS에서 제공하는 버스팅 기능은 수요가 간헐적이거나 급증하는 워크로드에 유용하다. 이를 통해 사용자는 기본 성능이 낮은 인스턴스와 볼륨을 프로비저닝하여 비용을 최적화하고 버스트 크레딧을 활용하여 필요할 때 동적으로 확장할 수 있다.