Jmeter란?
아파치에서 제공하는 어플리케이션으로, java로 이루어진 오픈소스의 성능테스트 도구
다른 테스트 도구들 보다 좀 더 웹서버 성능테스트에 특화 되어져 있다.
테스트케이스를 스크립트화하는 기능이 따로 있진 않지만, 레코딩 기능을 지원해주고, ui기능을 통해 다양한 부하테스트를 시도하는 것이 가능
Jmeter의 장점
- 복잡하고 디테일한 부하테스트가 가능하고, 다양한 프로토콜을 혼용해서 사용이 가능하다
- 기능적으로 스크립트 레코딩(script recording)이 가능하다
- UI를 통한 테스트 프로그램의 작성이 가능하기 때문에, locust보다 언어의 요구사항이 낮다(하지만 사용성은 다양한 기능을 제공해 주는 만큼 더 어렵다)
환경
- mac m1
- Java 11
설치
1. 자바 설치 후(자바 8 이후여야함) brew로 jmeter 설치
brew install jmeter
2. jmeter 실행
open /opt/homebrew/bin/Jmeter
터미널에서 open /usr/local/bin/jmeter을 하였지만 The file /usr/local/bin/jmeter does not exist. 에러가 났다. 인텔칩은 되지만 m1은 다른 방법을 쓴다.
기본 개념
Thread Group :
쓰레드 다발의 묶음 단위를 나타냄. 각각의 쓰레드는 하나의 유저 혹은 클라이언트레벨의 활동을 담당하는 역할
Samplers : 쓰레드가 request하는 쓰레드의 요청 단위 였다면, sampler는 jmeter에서 제공하는 다양한 프로토콜 중 어떤 프로토콜을 통하여 request를 할지 결정하는 역할
- FTP sampler : 파일 업로드 / 다운로드 등에 대한 요청 테스트 가능
- HTTP sampler : 일반적인 http프로토콜 통신에 대한 요청 테스트 가능
- JDBC sampler : JDBC(Java Database Connectivity) 자바레벨의 디비커넥션 API를 뜻하며 해당 API레벨의 요청 테스트 가능
- SMTP sampler : 이메일 송신에 대한 요청 테스트 가능
Listeners : 위 두가지 요소를 조합하여 실행한 결과물에 대해서 모니터링 혹은 수치화되어진 데이터를 보여주는 역할
Configuration : 요청시에 기본 세팅 환경을 맞춰 놓을 수 있다. (http 요청시 기본 인증 쿠키 값 세팅, 다양한 파라미터들로 요청을 하기 위한 csv파일 세팅)
시나리오 (로컬에서 테스트)
user_seq=51인 유저가 1초에 100개 threads로 5번씩 GET api/v1/user-challenges url로 요청
상황1. 유저 챌린지 전체 조회 join before
→Join을 사용하지 않은 경우(N+1문제 발생)
@Override
public List<UserChallenge> findAllByUserSeq(
Long userSeq,
Integer pageSize,
Long prevLastUserChallengeSeq
){
return from(qUserChallenge)
.innerJoin(qUserChallenge.challenge, qChallenge)
.fetchJoin()
.orderBy(qUserChallenge.startDate.asc())
.where(predicates)
.limit(pageSize)
.fetch()
.stream()
.distinct()
.collect(Collectors.toList());
}
상황2. 유저 챌린지 전체 조회 join after
→Join을 사용한 경우(N+1문제 해결)
@Override
public List<UserChallenge> findAllByUserSeq(
Long userSeq,
Integer pageSize,
Long prevLastUserChallengeSeq
){
return from(qUserChallenge)
.leftJoin(qUserChallenge.challenge, qChallenge).fetchJoin()
.leftJoin(qChallenge.challengeRecord, qChallengeRecord).fetchJoin()
.orderBy(qUserChallenge.startDate.asc())
.where(predicates)
.limit(pageSize)
.fetch()
.stream()
.distinct()
.collect(Collectors.toList());
}
1. Thread Group 만들기
Test Plan→Add→Treads→Threads Group
- Number of Threads: 몇 개의 쓰레드(유저 수)로 테스트할 지
- Ramp-up period: Number of Thread가 전부 실행되는데까지 걸리는 시간
- Loop Count: Thread가 몇번씩 실행을 할 것인지, infinite는 무한루프
Number of Threads:100
Ramp-up period:1
Loop Count:5
1초에 100명의 유저가 5번씩 요청하게 설정(총 500번 요청)
2. Samplers 만들기
Threads Group→add→Sampler→HTTP Request
- Server Name or IP : 도메인명 또는 IP 입력
- Port Number : 포트 입력
- HTTP Request : 호출할 전체 URL에서 IP 또는 도메인명과 Port를 제외한 나머지 URL을 입력
- Send Parameters With the Request: 호출할 URL에 넘겨줄 parameter를 설정
Server Name or IP : localhost
Port Number : 8080
HTTP Request : GET api/v1/user-challenges
3. Listeners 만들기
Threads Group→add→Listeners→Summary Report
4. 로그인을 한 유저에 대한 요청이기 때문에 Cookie 설정
Test Plan→Add→Config Elemet→HTTP Cookie Manager
swagger에서 로그인할 유저로 Login api요청한 후 Cookie확인(로그인된 사용자에게만 허가되었으므로)
Chrome→검사(왼쪽마우스클릭)→Network→Name→Cookies
5. 상단의 초록생 ▷ 버튼 눌러서 동작
6. Summary Report로 결과 확인
- 평균, 최소, 최대는 ms단위
- 오류 0%는 HTTP 응답 코드로 판단합니다. 예외에 해당하는 400번대 또는 500번대 응답이 없었음을 예상할 수 있습니다.
- 처리량은 Throughput으로 Transaction Per Second를 의미하는 TPS라고도 합니다.
분석
상황1. 유저 챌린지 전체 조회 join before
Average : 8545 ms
Throughput : 10.3/sec
→요청 500개의 평균 응답시간은 8545 ms이며 10.3TPS
상황2. 유저 챌린지 전체 조회 join after
Average : 4788 ms
Throughput : 17.0/sec
→요청 500개의 평균 응답시간은 4788 ms이며 17.TPS
평가
SQL튜닝후(ChallengeRecord에 대한 join) Throughput이 10에서 17로 향상됨을 확인할 수 있었다.
< 더 공부하고 싶은 내용 >
성능 테스트시 가급적이면 원격으로 운영되고 있는 서버와 같은 네트워크 내에서 테스트하는 것이 좋다고 하기 때문에 로컬 테스트로 했지만 원격 테스트로 하면 더 좋을 듯 싶다.
k6:https://k6.io/blog/k6-vs-jmeter/
loop와 Thread의 상관관계(차이점) : https://m.blog.naver.com/tommybee/222071838955
참고:
https://www.blazemeter.com/blog/jmeter-cookie-manager
https://cloud-oky.tistory.com/351
https://jmeter.apache.org/usermanual/component_reference.html#HTTP_Cookie_Manager
'Backend' 카테고리의 다른 글
낙관적 잠금과 비관적 잠금으로 알아보는 동시성 처리 (1) | 2024.05.02 |
---|---|
[N+1 문제 , 연관관계] 일대일 관계에서의 N+1문제 (0) | 2023.03.28 |
[Error] No matching variant of org.springframework.boot:spring-boot-gradle-plugin:3.0.1 was found. (0) | 2023.01.18 |
[개념]DAO, DTO, VO, CRUD (0) | 2020.04.20 |