들어가며
Application을 개발한 뒤 성능을 테스트할 필요가 있다. 예상되는 실제 사용량 또는 부하를 시뮬레이션하여 만들어진 Application의 한계를 확인하고, 개선을 통해 안정적으로 서비스를 제공할 수 있기 때문이다. 부하 테스트를 수행하면 Application이 실제 사용 시나리오에서 어떤 성능을 보이는지, 동시에 사용자 수가 증가할 때 시스템이 어떻게 반응하는지 등을 확인할 수 있다. 이를 통해 문제를 개선할 수 있는 지점을 찾아낼 수 있게 된다.
이번 포스팅에서는 Springboot를 기반으로 개발한 WAS를 Apache Software Foundation에서 개발한 Java 기반의 오픈 소스 부하테스트 도구인 JMeter를 이용하여 테스트하는 법에 대해 알아보도록 한다.
Apache JMeter : 링크
도커로 Postgres DB 설치하기
먼저 Application의 DB를 설치하기 위해 Docker로 Postgres DB를 설치한다.
# 도커 이미지 가져오기
docker pull postgres
# 볼륨을 빼내고 도커 설치
docker run --name o2o-postgres \
-e POSTGRES_PASSWORD=passwd \
-p 25432:5432 \
-v o2o-postgres-data:/var/lib/postgresql/data \
-d postgres
# 도커를 이용하여 설치한 Postgres에 o2ouser라는 사용자를 만들고, 이 사용자가 소유한 o2o-db를 생성
docker exec -it o2o-postgres psql -U postgres -c "CREATE USER o2ouser WITH PASSWORD 'passwd';"
docker exec -it o2o-postgres psql -U postgres -c 'CREATE DATABASE "o2o-db" WITH OWNER o2ouser;'
Kafka 설치하기
Application의 이벤트가 Kafka를 통해 전달 되므로, 간단하게 Kafka를 싱글 노드 형태로 설치한다.
# 설치의 편의를 위해 Docker-compose형태로 만들어 둔 kafka를 사용
git clone https://github.com/devlos0322/devlos-kafka-cluster
# docker-compose를 통해 카프카를 설치
cd devlos-kafka-cluster
docker-compose -f docker-compose-single.yml up
Springboot App 실행하기
Springboot App의 코드는 회사 내부 코드라 공개하지 못한다.. (추후 필요한 분들이 있으시면 샘플코드를 작성해서 공유해 드릴게요!)
다음과 같이 위에서 설치한 Postgres DB와 Kafka와 연결하는 application.properties를 공유한다.
server.port=8092
spring.datasource.url=jdbc:postgresql://localhost:25432/o2o-db
spring.datasource.username=o2ouser
spring.datasource.password=passwd
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
spring.jpa.properties.hibernate.format_sql=true
spring.kafka.bootstrap-servers= localhost:9092
logging.level.org.hibernate.SQL=INFO
JMeter 설치하기
JMeter 다운로드
https://jmeter.apache.org/download_jmeter.cgi 바이너리 다운로드
윈도우 환경의 경우 디렉터리의 ApacheJMeter.jar 파일을 실행하면 바로 사용할 수 있다.
Mac의 경우 파일을 다운로드한 후 경로에서 bin 폴더 안에서./jmeter를 실행하면 된다.
JMeter Test Plan 작성하기
처음 JMeter를 실행시키면 다음과 같이 비어 있는 Test Plan을 볼 수 있다. Test Plan은 부하 테스트를 위한 전체 계획 및 구성을 나타내는 파일로써 시뮬레이션하려는 부하테스트의 목표, 대상 시스템의 세부 정보, 시뮬레이션할 사용자 수, 부하 테스트 실행 방법 등 다양한 설정을 할 수 있다.
테스트를 진행하기 위해 Thread Group을 생성한다. Thread Group은 특정 시나리오에 대한 세부사항을 정의할 수 있다.
Thread Group을 생성하면 동시에 실행되는 가상 사용자의 수, 램프업 기간 및 테스트 지속시간 등을 정의할 수 있다.
- Number of Threads: 동시에 실행되는 가상 사용자의 수를 지정한다. 이 수치가 높을수록 시스템에 높은 부하를 가할 수 있다. 웹 애플리케이션에 대한 부하 테스트를 수행할 때 사용자 수를 의미한다.
- Ramp-up Period: 가상 사용자가 전체 시간 동안 동시에 시작되지 않고, 일정한 시간 동안 차례로 시작되는 기간을 지정한다. 예를 들어, 10개의 스레드와 10초의 Ramp-up Period가 설정되어 있다면, 1초마다 1개의 스레드가 실행되며, 10초 후에는 모든 쓰레드가 실행된다.
- Duration: 테스트가 실행될 총시간을 지정한다. 테스트가 지속되는 동안 JMeter는 Thread Group에서 지정된 수의 스레드를 계속 실행하며, 이를 통해 시스템에 대한 일정한 부하를 유지한다.
HTTP Request Default 설정하기
HTTP Request Default를 설정하여 HTTP 요청을 보낼 때 기본적으로 적용되는 설정을 지정할 수 있다. 이를 통해 사용자가 HTTP 요청을 보낼 때마다 설정을 반복해서 지정할 필요가 없어진다.
HTTP Request Sampler 설정
테스트 페이지 목록에 해당하는 Sampler를 추가한다.
HTTP Request Sampler를 설정하여 사용자 서비스의 로그인 정보를 호출한 것이다. HTTP Request Default를 적용했기 때문에 Server 연결 정보는 생략이 가능하다. 만약 여기 정보를 기입하게 되면 HTTP Request에 기입된 정보가 우선권을 가지고 적용된다.
결과 조회 구성
결과 조회를 하기 위해 다양한 리스너를 이용할 수 있다.
- View Results Tree
모든 응답 데이터를 트리 형태로 표시하여 HTTP 요청 및 응답을 상세하게 확인할 수 있는 리스너다.
설정: Add → Listener → View Results Tree - Summary Report
테스트 결과를 요약하여 간략한 통계 정보를 제공하는 리스너로써 요청 건수, 평균 응답시간, 에러 비율 등의 정보를 확인할 수 있다.
설정: Add → Listener → Summary Report - Graph Result
테스트 결과를 그래프로 시각화하여 표시하는 리스너입다. 응답 시간 그래프, TPS(Total Processing Time) 그래프 등을 통해 성능 문제를 파악할 수 있다.
설정: Add → Listener → Graph Result
부하테스트 실행하기
Ctrl + R 또는 플레이 버튼을 누르면 부하테스트가 실행된다.
200명이 동시접속하는 환경을 구성해 봤을 때 다음과 같은 결과를 얻을 수 있다. 에러는 발생하지 않았고, 10000건의 요청에 대해 평균적으로 1.8초 이내로 응답을 하는 것을 확인할 수 있다. Throughput은 분당 약 4900건으로 확인된다. 대규모 서비스의 경우 초당 수십만 건 이상의 트래픽을 처리하는 것이 일반적이라고 한다. 따라서, 이러한 대규모 서비스에서 4900건의 throughput은 상대적으로 낮은 수치로 평가될 수 있다. 하지만 소규모 서비스의 경우 4900건의 throughput은 비교적 높은 수치로 생각된다.
JMeter의 Graph Results 리스너에서 제공되는 그래프에서 "Data", "Average", "Median", "Deviation", "Throughput"은 다음과 같은 의미를 가진다.
- Data : 샘플 결과의 값들을 나타낸다. 예를 들어, 응답 시간 그래프에서 Data는 각 샘플의 응답 시간 값들을 의미한다.
- Average : 샘플 결과의 평균 값을 나타낸다. 예를 들어, 응답 시간 그래프에서 "Average"는 모든 샘플의 응답 시간 값의 평균을 의미한다.
- Median : 샘플 결과 값의 중앙값을 나타낸다. 중앙값은 모든 샘플 값들을 크기 순으로 정렬했을 때, 가운데 위치한 값이다. 예를 들어, 응답 시간 그래프에서 모든 샘플의 응답 시간 값 중 중앙에 위치한 값이다.
- Deviation : 샘플 결과 값의 편차를 나타낸다. 편차는 샘플 값과 평균 값 사이의 차이를 나타낸다. 예를 들어, 응답 시간 그래프에서 모든 샘플의 응답 시간 값과 그 값들의 평균 값 사이의 차이를 나타낸다.
- Throughput : 단위 시간당 처리량을 나타낸다. 예를 들어, 초당 요청 수 그래프에서 "Throughput"은 초당 처리되는 요청 수를 나타낸다. 이것은 시스템이 얼마나 많은 요청을 처리할 수 있는지를 나타내며, 시스템 성능을 평가하는 데 중요한 지표 중 하나다.
마치며
이번 포스팅에서는 JMeter를 활용하여 Springboot App의 부하 테스트하는 방법에 대해서 설명했다. 사실 포스팅에 올리지 못했지만 500 Thread를 통해 테스트 할 시 평균 응답시간이 4.8초로 측정되어서 열심히 원인을 파악하고 있다. 이 내용에 대해서는 해결 후 다시 후속 포스팅으로 공유할 것이다. 해결.. 해결 ㅎㅎ;