JMeter 사용 방법
Apache JMeter 5.6.3 : Source - zip 파일 다운로드
테스트 전 유의사항
- 테스트하는 웹 어플리케이션 서버와 테스트를 진행하는 서버는 서로 달라야 한다.
- 같은 서버를 사용하면 같은 메모리를 점유하기 때문에 정확한 값을 측정할 수 없다.
JMeter 실행
util\\apache-jmeter-5.6.3\\apache-jmeter-5.6.3\\bin> ./jmeter
JMeter 구성요소
Thread Group : 테스트에 사용될 스레드 개수, 스레드 1개당 사용자 1명
Sampler : 사용자의 액션 (예: 사용자 로그인, 게시물 작성, 게시글 조회 등)
Listener : 응답을 받아 리포팅, 검증, 그래프 등 다양한 처리
Configuration Elements: Sampler 또는 Listener가 사용할 설정 값 (쿠키, JDBC 커넥션 등)
Assertion : 응답 확인 방법 (응답 코드, 본문 내용 비교 등)
View Results Tree
하나의 리퀘스트의 테스트 시작 시간, 응답 속도 등 다양한 정보 제공
View Results in Table
Tree를 테이블 형식으로 보여줌. 데이터는 동일
Summary Report
- Label : Sampler 명
- Samples : 샘플 실행 수 (Number of Threads X Ramp-up period)
- Average : 평균 걸린 시간 (ms)
- Min : 최소
- Max : 최대
- Std. Dev. : 표준편차
- Error % : 에러율
- Throughput : 분당 처리량
- Received KB/sec : 초당 받은 데이터량
- Sent KB/sec : 초당 보낸 데이터량
- Avg. Bytes : 서버로부터 받은 데이터 평균
데이터베이스 성능 최적화(인덱스 활용)
인덱스를 생성하는 이유?
인덱스를 사용하면 테이블 전체를 스캔하지 않고도 필요한 데이터를 빠르게 찾을 수 있습니다. 인덱스가 없는 경우의 예를 살펴보겠습니다. users테이블에서 해당 쿼리는 테이블의 모든 행을 검색해야 합니다. 하지만 인덱스가 있다면 어떻게 될까요 ?
SELECT * FROM users WHERE username = 'kim';
인덱스가 있는 경우, 인덱스를 사용하여 ‘kim’이 위치한 행을 빠르게 찾을 수 있는 장점이 있습니다. 이처럼 인덱스는 빠른 검색, 범위 검색, 조인 성능 향상, 정렬 성능 향상 등 데이터베이스의 성능을 크게 향상시킵니다.
우리 프로젝트에서는 PREACTIVITY, ACTIVITY, DONE 세 가지 Progress 조건과 Keyword(=Title) 챌린지의 제목에 따라 검색하고, 해당 챌린지들을 제공해야 합니다. 두 개 이상의 컬럼에 대해 다중 열 인덱스를 생성하기로 하였습니다.
다중 열 인덱스(Composite Index)
그전에 먼저 Instance 테이블의 카디널리티 값을 먼저 확인하겠습니다.
카디널리티(Cardinality)는 특정 컬럼에 존재하는 고유한 값들의 수를 의미합니다. 성능 최적화와 인덱스 설계에 중요한 개념입니다. 높은 카디널리티를 가질수록 컬럼에 고유한 값들이 많이 존재한다고 볼 수 있습니다. 즉, 고유한 값이 많을수록 인덱스의 효율성이 증가하는 경향이 있습니다. 그렇다면 각 컬럼별 카디널리티를 확인해보겠습니다.
select
concat(round(count(DISTINCT instance_id) / count(*) * 100, 2), '%') as instanceId_cadinality,
concat(round(count(DISTINCT participant_count) / count(*) * 100, 2), '%') as participant_count_cadinality,
concat(round(count(DISTINCT point_per_person) / count(*) * 100, 2), '%') as point_per_person_cadinality,
concat(round(count(DISTINCT certification_method) / count(*) * 100, 2), '%') as certification_method_cadinality,
concat(round(count(DISTINCT description) / count(*) * 100, 2), '%') as description_cadinality,
concat(round(count(DISTINCT notice) / count(*) * 100, 2), '%') as notice_cadinality,
concat(round(count(DISTINCT tags) / count(*) * 100, 2), '%') as tags_cadinality,
concat(round(count(DISTINCT title) / count(*) * 100, 2), '%') as title_cadinality,
concat(round(count(DISTINCT progress) / count(*) * 100, 2), '%') as progress_cadinality
from `instance`
아래의 결과로 볼 수 있듯이, Id(PK)를 제외한 값들 중에서 Title(=Keyword)의 카디널리티가 가장 높은 것을 볼 수 있습니다. Title과 Progress 컬럼에 인덱스를 생성해도 될 것 같습니다.
Http Header
JWT 토큰 정보와 Content-Type의 application/json 을 입력
성능 테스트 결과
목적: 챌린지 조회 API의 성능을 평가하기 위해 JMeter를 사용하여 1차적으로 데이터베이스 최적화를 진행하고 부하 테스트를 수행
환경: 노트북 (CPU: Intel i5, RAM: 8GB), JMeter 5.6.3, 로컬 네트워크
- 테스트 설정
- Threads (users) : 100
- Ramp-up period (seconds) : 30
- Loop Count : INF
- Duration (seconds) : 120
- 테스트 시나리오
- Http Request: /api/challenge/search
- Parameters: keyword, progress
- Method: POST
인덱스 적용 전
JMeter를 사용해서 동일한 조건으로 인덱스 적용 전/후 테스트를 해보겠습니다. (PC 사양에 따라 다를 수 있습니다.)
실행된 요청의 총 수 (Sample Data): 5687
평균 응답 시간 (Average): 522
최소 응답 시간 (Min): 24
최대 응답 시간 (Max): 2906
응답 시간의 표준 편차 (Std. Dev.): 333.59
단위 시간당 처리된 요청의 수 (Throughput): 47.2/sec
오류 비율 (Error): 0%
인덱스 적용 후
실행된 요청의 총 수 (Sample Data) : 7213
평균 응답 시간 (Average): 363
최소 응답 시간 (Min): 21
최대 응답 시간 (Max): 1526
응답 시간의 표준 편차 (Std. Dev.): 197.47
단위 시간당 처리된 요청의 수 (Throughput): 60.7/sec
오류 비율 (Error): 0%
다음과 같은 명령어로 인덱스를 생성할 수 있습니다.
CREATE INDEX idx_title_progress ON instance(title, progress);
Instance 테이블에 생성된 index를 조회합니다.
show index from instance;
주요 성능 지표 비교
평균 응답 시간 (Average)
- 성능 개선 전: 522 ms
- 성능 개선 후: 363 ms
- 성능 개선: 522 - 363 = 159 ms 감소
- 성능 개선 비율: (159 / 522) * 100 ≈ 30.46%
최대 응답 시간 (Max)
- 성능 개선 전: 2906 ms
- 성능 개선 후: 1526 ms
- 성능 개선: 2906 - 1526 = 1380 ms 감소
- 성능 개선 비율: (1380 / 2906) * 100 ≈ 47.49%
응답 시간의 표준 편차 (Std. Dev.)
- 성능 개선 전: 333.59 ms
- 성능 개선 후: 197.47 ms
- 성능 개선: 333.59 - 197.47 = 136.12 ms 감소
- 성능 개선 비율: (136.12 / 333.59) * 100 ≈ 40.81%
단위 시간당 처리된 요청의 수 (Throughput)
- 성능 개선 전: 47.2 requests/sec
- 성능 개선 후: 60.7 requests/sec
- 성능 개선: 60.7 - 47.2 = 13.5 requests/sec 증가
- 성능 개선 비율: (13.5 / 47.2) * 100 ≈ 28.60%
요약
- 평균 응답 시간: 약 30% 개선
- 최대 응답 시간: 약 47% 개선
- 응답 시간의 표준 편차: 약 40% 개선
- 단위 시간당 처리된 요청의 수: 약 28% 개선
결론
성능 개선 후 시스템의 응답 시간이 전반적으로 감소하고, 처리 능력(Throughput)이 증가했습니다. 이는 시스템의 효율성이 크게 향상되었음을 나타냅니다. 각 지표에서 상당한 개선이 이루어졌으며, 특히 최대 응답 시간에서 약 47.49%의 큰 개선이 있었습니다. Throughput 역시 약 28.60% 증가하여 단위 시간당 더 많은 요청을 처리할 수 있게 되었습니다.
참고 자료