본문 바로가기

프로그래밍(TA, AA)/개발방법론

[테스트] JMeter와 성능 테스트

1.1 JMeter란


Apache JMeter는 웹 애플리케이션처럼 클라이언트-서버 구조로 된 소프트웨어의 성능 테스트를 위해서 만들어진 100% 순수 자바 프로그램입니다. 스테파노 마조끼가 개발했으며, 이는 현재 톰캣(Tomcat)으로 이름이 바뀐 Apache JServ의 테스트를 위한 코드에서 시작됐습니다. 이후 이 코드에 GUI와 기능을 추가하여 JMeter가 만들어졌습니다.


JMeter는 단위/성능/스트레스 테스트 등 많은 곳에서 활용할 수 있습니다. 프로토콜(Protocol)도 계속 추가되어 TCP, HTTP(S), FTP, JDBC, LDAP, SMTP, SAP/XML, RPC 등 현재 범용으로 사용되는 프로토콜 대부분을 지원합니다.


JMeter는 통신 프로토콜 단계에서만 동작하고 웹 브라우저에서는 동작하지 않습니다. 즉, 통신규약에 맞도록 클라이언트와 서버 간 메시지만 송수신할 뿐이고 클라이언트 자체에서 행해지는 연산 동작은 하지 않습니다. 가장 대표적인 예가 ActiveX를 이용하여 암호화나 연산 작업을 하는 사이트입니다. 이러한 사이트는 ActiveX 로직을 모두 이해하고 자바를 이용하여 별도로 JMeter 내부 모듈을 구현하지 않는 이상 테스트가 불가능합니다.


JMeter는 2001년에 1.0을 발표한 후 10여년 동안 꾸준히 기능과 성능을 향상하여 2011년에는 Apache Software Foundation에서 Top Level Apache Project에 선정되기도 하였습니다. 또한, 자바 가상 머신(JVM, Java Virtual Machine)과 H/W의 성능이 향상되면서 초기에 문제가 되던 성능이나 기능 면에서 부족함이 많이 해소되어 현재는 웬만한 성능 테스트에서 핵심으로 활약하기에 부족함이 없는 상태에 도달한 것으로 보입니다.


기능이 다양하고 성능이 좋음에도 JMeter는 오픈소스라는 이유로 성능 테스트 현장에서 많이 활용되지 못하고 있는 것이 현실입니다. LoadRunner와 같은 외산 상용 솔루션이 가장 많이 사용되지만 라이선스 비용 문제로 현장에서 충분히 활용되지 못하며, 국내 몇몇 솔루션은 엔지니어 층이 얇거나 제대로 검증되지 않아서 신뢰성이 떨어지는 경우가 많습니다.


필자가 JMeter를 이용해서 많은 사이트의 성능 테스트를 진행하면서 도달한 결론은 불과 몇년 전만 해도 다소 부족했지만, 현재는 JMeter로도 대부분 사이트에서 원하는 테스트를 수행할 수 있으며 성능이나 기능 면에서 부족함을 느끼기 어렵다는 것입니다.


JMeter는 IT 업계에서 종사하는 엔지니어가 사용하기에 그리 복잡하지 않은 프로그램입니다. 하지만 이 프로그램이 테스트 환경과 결합하면 많은 변수를 고려해야 하는 상황이 발생합니다. 그 변수가 JMeter 자체 문제인지 네트워크 환경 문제인지 그리고 애플리케이션 서버 구성 또는 애플리케이션 자체 문제인지를 적절하게 구별하고 JMeter가 보여주는 결과 수치로 얼마나 의미 있는 값을 찾아내는가가 중요합니다.


이 책에서는 JMeter를 사용하는 기초적인 방법부터 실제 성능 테스트 과정에서 일어날 수 있는 문제점에 대한 해결 방안과 JMeter로 대용량 테스트 환경을 구축하기 위한 최적의 방법까지 설명합니다. 



1.2. 성능 테스트


JMeter를 시작하기 전에 성능 테스트에 대한 기본적인 지식을 알고 있는 것이 좋습니다. 이는 테스트를 계획하고 결과를 분석하는데 중요한 역할을 합니다.


이 책에서 말하는 '성능 테스트'란 서비스 및 서비스 시스템의 성능을 확인하기 위해서 실제 사용환경과 비슷한 환경에서 테스트를 진행하는 것을 말합니다. 이를 통해서 응답시간(Response Time)과 처리량(Throughput), 병목구간 등을 확인할 수 있고, 성능 테스트로 얻은 정보로 서비스나 서비스 시스템의 문제점을 확인하고 이를 개선(Tuning)하여 보완할 수 있습니다.


성능 테스트는 쓰임에 따라 다음과 같이 나뉩니다.


Load 테스트: 시스템의 성능을 벤치 마크하기 위한 테스트를 의미합니다. 이 테스트는 부하(Load)를 순차적으로 증가시키면서 응답시간이 급격히 증가하거나 더는 처리량이 증가하지 않거나 시스템의 CPU와 Memory 등이 기준값 이상으로 증가하는 등 비정상 상태가 발생하는 임계점을 찾아내고 이를 바탕으로 성능 이슈에 대한 튜닝과 테스트를 반복합니다.

Stress 테스트: 임계값 이상의 요청이나 비정상적인 요청을 보내 비정상적인 상황의 처리 상태를 확인하고 시스템의 최고 성능 한계를 측정하기 위한 테스트를 의미합니다.

Spike 테스트: 이 테스트는 예를 들어 빌딩에 화재 경보가 발생했을 때 빌딩에 있는 직원들이 동시에 안전한 장소를 향해서 이동할 경우 시간이 얼마나 걸리며 어떤 문제가 발생하는지를 테스트하는 것과 같습니다. 즉, 갑자기 사용자가 몰렸을 때 요청이 정상적으로 처리되는지 그리고 그 업무 부하(Workload)가 줄어들때 정상적으로 반응하지는지를 확인하기 위한 테스트를 의미합니다.

Stability 테스트 / Soak 테스트: 긴 시간 동안 테스트를 진행해서 테스트 시간에 따른 시스템의 메모리 증가, 성능 정보의 변화 등을 확인하는 테스트를 의미합니다. 짧게는 한두 시간부터 길게는 며칠동안 진행하기도 합니다.


 단계

 프로세스

 내용

 1

 요구사항 분석

 - 테스트 목적과 범위를 정하는 단계로, 효율적인 테스트를 위해서는 목적을 정확히 설정해야 합니다.

 - 구 시스템과 신규 시스템의 비교 테스트, 신규 시스템 오픈 전 사전 임계치 테스트, 장애 발생을 대비한 Failover-Failback 테스트 등 테스트 범위와 우선순위를 결정해야 합니다. 모든 서비스를 테스트하면 좋겠지만, 보통 서비스 개발이나 유지 보수 때는 테스트를 위한 시간이 그다지 충분하지 않습니다. 그러므로 중요도와 테스트 목적에 맞는 우선순위와 그 범위를 정합니다.

 - 범위가 정해지면 해당 시스템의 소프트웨어적인 구조와 하드웨어적인 구조를 분석합니다.

 2

 테스트 계획

 - 언제, 누가, 어떤 방법으로, 어디서 테스트할 것인지 정하는 단계입니다.

 - 테스트 수행에는 많은 내/외부 인력이 필요하며 많은 준비사항이 있으므로 테스트 계획이 필수입니다.

 - 테스트에 필요한 인력과 역할도 존재합니다.

 3

 테스트환경 구축

 - 테스트 단계 내에서 테스트 환경 구축을 언제 수행할지는 그리 중요하지 않을 수 있습니다. 자주 테스트를 수행하는 곳에서는 테스트 전용 서버팜(Serverfarm)이 이미 구성되어 있기 때문입니다. 요즘은 클아우드 환경의 테스트 팜을 구성하는 경우도 있습니다.

 - 테스트 환경을 구축할 때 가장 중요한 것은 부하발생기와 테스트 대상 서버 사이의 네트워크가 최단 구간 안에 존재하게 하는 것입니다. 중간에 많은 보안 장비와 스위치/라우터(Switch/Router) 등을 거치면 예상하지 못한 결과가 발생할 수 있습니다.

 4

 테스트 설계

 - 테스트 절차 및 테스트 시나리오를 작성하고 테스트 케이스 작성 및 스크립트를 구현하며 테스트에 필요한 데이터 셋(Dataset)을 준비하는 단계입니다.

 - 테스트에 필요한 데이터 셋을 준비하는 과정은 상당히 중요합니다. 테스트에 필요한 충분히 많은 데이터가 준비되지 않는다면 의도하지 않은 결과가 나올 가능성이 높기 때문입니다. 예를 들어, 어떤 시스템에서 실제로는 DB의 I/O에 의해서 성능 저하가 발생한다고 가정했을 때, DB의 테스트 데이터가 충분히 입력되지 않고 접근 데이터가 고르지 않으면 실제 서비스 때보다 성능이 좋게 나올 가능성이 높습니다. 즉, 실제 환경과 비슷한 수준의 많은 데이터를 준비할수록 테스트 결과가 좀 더 실제 값과 비슷해집니다.

 5

 테스트 수행 및 결과 수집 

 - 작성된 스크립트로 실제 테스트를 수행하는 단계입니다. 테스트 수행은 크게 두 부분으로 나누어집니다.

 1) Pre-Test: Main-Test 전에 스크립트가 제대로 작성되었는지, 테스트 환경(서버/네트워크/보안 시스템/외부 연동 등)과 준비된 데이터 셋에 문제가 없는지 확인하기 위한 테스트입니다. Main-Test에는 많은 인력이 투입되므로 Pre-Test가 정상적으로 이루어지지 않으면 많은 인력이 불필요하게 대기하는 상황이 발생할 수 있으니 사전에 꼭 수행해야 합니다.

 2) Main-Test: 실제 테스트를 수행하는 단계로, 테스트 분석에 필요한 시스템 성능 자료를 수집합니다. 통합 SMS 솔루션이 있으면 OS의 CPU, Memory, I/O 등의 정보는 쉽게 수집할 수 있습니다. 그렇지 않다면 별도의 시스템 정보 수집 스크립트를 이용해서 수집해야 합니다. AP(Application Server)는 APM(Application Performance Management)과 같은 전용 모니터링 도구를 이용하면 많은 정보를 편리하게 수집할 수 있습니다.

 6

 테스트 분석

 테스트 결과 자료와 시스템 성능 자료를 모아서 테스트 결과를 분석합니다. 분석된 자료를 통해서 성능에 영향을 미치는 문제점을 찾습니다.

 7

 문제점 수정 및 재테스트

 테스트 분석에서 발견된 문제점을 개발팀(Development Team)이나 시스템 운영팀(System Engineering Team)에 전달하여 문제점을 수정하고 다시 한 번 테스트를 수행합니다.

 8

 결과 리포트 작성

 테스트 리포트는 테스트 목적에 따라 해당 목적을 가장 잘 표현할 수 있는 방식으로 작성하는 것이 좋습니다. 요약 리포트와 상세 리포트를 분리해서 상세 경과를 필요로 하는 부서와 요약 결과만 필요로 하는 부서에 별도로 리포트를 제출하는 것도 좋은 방법입니다.


 테스트 인력

 역할

 Test Leader(PM)

 전체적인 테스트 계획, 목적 수립, 시나리오 작성, 일정 관리와 인력 배치를 담당합니다.

 Test Scripter(Designer)

 정의된 테스트 목적 및 범위에 따라 작성된 시나리오로 사이트(서비스)를 분석하고 이를 바탕으로 상세 케이스를 작성합니다.

 Team Operator

 작성된 테스트 스크립트를 이용해서 실제 테스트를 수행합니다.

 Development Team

 테스트에 필요한 데이터를 준비하고 애플리케이션을 모니터링하며 발견된 문제점과 개선점을 찾아냅니다.

 System Engineer(SE) Team

 테스트 환경을 구축하고 시스템(OS, 네트워크, 스토리지 등)을 모니터링하여 발견된 문제점과 개선점을 찾아냅니다.



1.3. 대용량 성능 테스트


이 책에서 의미하는 '대용량 성능 테스트'란 매우 많은 가상 사용자(Virtual User, Thread)가 필요한 테스트나 매우 높은 웹 트랜잭션 처리량을 테스트하는 것을 의미합니다. 즉, 대규모 장비가 필요한 테스트입니다. 대용량 성능 테스트를 진행하다 보면 결과에 많은 영향을 주는 요소들이 발생합니다. 이것은 현재 수행한 테스트 결과가 믿을만한지, 어떤 요소가 한계점에 다다라서 결과가 왜곡되지 않았는지에 대한 고민에 빠지게 합니다. 예를 들어, 여러 대의 부하발생기가 연결되면 부하발생기의 네트워크 구성에 따라 결과가 달라질 수 있으며, 애플리케이션 서버의 능력보다 네트워크 스위치의 성능이나 OS 설정값에 의해 결과가 매우 달라질 수 있습니다.


그러므로 좀 더 신뢰성 높은 결과값을 얻기 위해서는 결과에 영향을 미치는 요소들을 최대한 제거해야만 합니다. 이책에서는 기본적은 JMeter의 사용법과 함께 대용량 성능 테스트를 수행할 때 발생할 수 있느 문제점과 그에 대한 해결 방법을 실무에서 겪은 다양항 경험과 시행착오를 바탕으로 테스트 담당자들이 이런 시행착오를 겪지 않도록 하기 위한 팁과 노하우를 다룹니다. 또한, 이를 바탕으로 테스트의 신뢰성을 높이고 테스트 결과값에서 의미있는 내용을 찾는 방법을 설명합니다.



1.4. 주요 용어 및 개념


성능 테스트와 관련하여 자주 사용되는 용어와 그 개념을 간략하게 정리해 보겠습니다.


Active User: 실제 서버에 연결된 상태로 요청을 처리 중인 사용자를 말합니다.

InActive User: 웹브라우저에 결과 화면이 출력된 상태에서 화면의 내용을 읽거나 정보를 입력하고 있는 사용자입니다. 서버와의 세션(Session) 정보를 가지고 있지만 직접 접속하여 요청을 주고받는 상태가 아닌 사용자를 의미합니다.

Concurrent User(Active User + InActive User): 보통 '동시 접속 사용자수'라고 표현합니다. 일반적으로 사용자 수의 많고 적음을 표현하는 값으로, 성능 테스트에서 가상 사용자 수를 결정하는 기준이 됩니다. 서비스 유형과 시간에 따라 그 비율이 달라지긴 하지만, 일반적으로 Active User와 InActive User 비율이 1:10 정도입니다.

Virtual User: 가상 사용자 수로, JMeter에서는 Thread 수로 표현하기도 합니다.

Ramp-Up Period: Thread(Virtual User) 생성에 걸리는 시간을 의미합니다. Ramp-Up Period를 이해하기 쉽도록 작성한 그래프입니다.



이 그래프는 '10개의 Thread를 50초 동안 차례대로 생성하라'는 의미입니다. 즉, 5초(50초/10개)마다 Thread를 하나씩 생성하는 것과 같은 의미입니다.

Throughput: 단위 시간당 대상 서버(웹서버, WAS, DB 등)에서 처리되는 요청의 수를 말합니다. JMeter에서는 시간 단위를 보통 TPS(Transaction Per Second)로 표현합니다.

Response Time/Load Time: 응답시간 또는 처리시간이라고 표현합니다. 요청을 보낸 후 응답이 완료되어 사용자 화면에 출력될때까지의 시간을 나타냅니다. 시스템의 성능을 평가하는 지표로 주로 사용됩니다.

Latency: 요청을 보낸 후 데이터를 받기 시작할 때까지 시간입니다.

Think Time: 하나의 요청에 응답을 수신하고 다음 요청을 보낼 때까지 시간을 의미합니다. 테스트에서 실제 사용자의 사용패턴과 유사한 패턴을 구현하기 위해서는 이 Think Time을 적절히 적용해야 합니다.

Request Interval Time: 요청을 보낸 후 다음 요청을 보낼때까지 시간을 의미합니다.

Load Time vs Latency: 아래 그림은 Load Time/Latency/Think Time/Request Interval Time의 관계를 이해하기 쉽도록 그림으로 나타낸 것입니다.



위를 보면 한상 Load Time >= Latency가 성립됩니다. 두 개를 왜 나눠놓았을 까요? 이것은 Latency와 Load Time을 구분함으로써 성능을 분석할 때 요긴하게 사용할 수 있습니다.



A와 B 사이트에 동일한 크기(10MB 정도)의 파일을 올려놓고 다운로드 테스트를 진행한다고 가정해보겠습니다. A 사이트와 B 사이트의 결과를 비교해 보니 B 사이트의 Load Time이 2배 이상 컸습니다. 하지만 Latency는 거의 비슷했습니다. 이렇게 차이가 나는 이유가 무엇일까요?

Load Time에서 Latency를 빼면 데이터를 전송받는데 걸리는 시간을 나타냅니다. 즉, B 사이트가 A 사이트보다 데이터를 내려받는 속도가 느리다고 볼 수 있습니다. 따라서 B 사이트는 처리량을 늘리기 위해 웹서버를 튜닝하기보다는 네트워크의 대역폭(Bandwidth)을 늘리는 것을 고려해야 합니다.