JMeter 다운로드 링크
터미널 명령어로 다운로드된 폴더에 bin 경로로 들어가서 jmeter.sh 파일을 실행
cd ~/apache-jmeter-5.6.3/bin # 경로로 들어가기
./jmeter.sh # jmeter 실행
테스트 계획 우클릭 -> 추가 -> 쓰레드들(사용자들) -> 쓰레드 그룹
위에 사진의 설정에서는 100명의 사용자가 각 10번씩 요청하여 1000번의 요청이 이루어지는 테스트 시나리오이다.
Gatling 다운로드 링크 :
https://docs.gatling.io/reference/install/oss/
현재 내 프로젝트는 gradle이므로 Download Gatling for Gradle-Java 선택
다운로드된 파일의 압축을 풀고 내 MSA 프로젝트의 경로 안에 넣는다.
ForTickets
├── application
│ ├── eureka
│ ├── gateway-service
│ ├── user-service
│ └── ...
├── build.gradle
├── component
├── gradle
├── gradlew
├── gradlew.bat
├── gatling <-- 여기
├── README.md
└── settings.gradle
gatling을 서브프로젝트로 인식시키기 위해 최상위 루트에 있는 settings.gradle에 추가한다.
// ...
include 'gatling'
// ...
이제 /gatling/src/gatling/java/computerdatabase 경로 안에 들어가서 테스트 시나리오 작성을 위한 자바 클래스를 생성한다.
package computerdatabase;
import static io.gatling.javaapi.core.CoreDsl.*;
import static io.gatling.javaapi.http.HttpDsl.*;
import io.gatling.javaapi.core.*;
import io.gatling.javaapi.http.*;
public class UserSimulation extends Simulation {
// HTTP 프로토콜 설정
HttpProtocolBuilder httpProtocol = http
.baseUrl("http://localhost:8080") // user-service의 base URL
.acceptHeader("application/json")
.userAgentHeader("Gatling");
// 시나리오 정의: GET /user/1 API 호출
ScenarioBuilder scn = scenario("Get User Scenario")
.exec(
http("Get User") // 요청 이름
.get("/user/1") // 경로
.check(status().is(200)) // 응답 상태 코드 체크
);
{
// 시뮬레이션 설정: 한 번에 10명의 사용자가 시나리오 실행
setUp(scn.injectOpen(atOnceUsers(10))).protocols(httpProtocol);
}
}
작성을 완료했다면 테스트를 실행하기 위해 터미널에서 명령어를 입력한다.
# Mac
./gradlew gatlingRun
테스트가 진행되고 결과를 build/reports/gatling 디렉토리에 HTML 형태로 저장한다.
근데 내가 요청하려는 대부분의 api는 로그인된 jwt정보가 필요하다.
때문에 테스트를 하기 위해선 테스트 요청에는 jwt 인증을 하지 않거나 테스트용 jwt 인증 과정을 따로 설정해주어야한다.
나는 처음에 jwt 인증을 하지 않도록 하는 방법을 고민해보았으나 설정을 하려면 security 등 광역으로 수정해야할 부분들이 많아질거같아 테스트 안에서 로그인하여 jwt를 헤더로 반환하여 사용하는 방법을 선택하였다.
package computerdatabase;
import static io.gatling.javaapi.core.CoreDsl.*;
import static io.gatling.javaapi.http.HttpDsl.*;
import io.gatling.javaapi.core.*;
import io.gatling.javaapi.http.*;
public class UserSimulation extends Simulation {
// HTTP 프로토콜 설정
HttpProtocolBuilder httpProtocol = http
.baseUrl("http://localhost:12011") // user-service의 base URL
.acceptHeader("application/json")
.userAgentHeader("Gatling");
// 시나리오 정의
ScenarioBuilder scn = scenario("유저 정보 조회")
// 로그인 요청
.exec(http("로그인")
.post("/user-service/auth/login")
.header("Content-Type", "application/json")
.body(StringBody("{ \"email\": \"user1@email.com\", \"password\": \"Abcd1234!\" }")) // 적절한 사용자 정보로 변경
.check(status().is(200))
.check(header("Authorization").saveAs("jwtToken")) // JWT 토큰을 추출하여 "jwtToken" 변수에 저장
)
// 정보 조회 요청
.exec(http("유저 정보 조회")
.get("/user-service/users") // 유저 정보 조회 API 경로
.header("Authorization", "#{jwtToken}") // 세션에서 jwtToken 가져오기
.check(status().is(200)) // 응답 상태 코드 체크
.check(bodyString().saveAs("responseBody")) // 응답 본문을 변수에 저장
)
// 토큰 확인
// .exec(session -> {
// String jwtToken = session.getString("jwtToken");
// System.out.println("JWT Token: " + jwtToken); // JWT 토큰 출력
// String responseBody = session.getString("responseBody");
// System.out.println("Response Body: " + responseBody);
// return session;
// })
;
{
// 시뮬레이션 설정: 한 번에 10명의 사용자가 시나리오 실행
setUp(scn.injectOpen(atOnceUsers(5000))).protocols(httpProtocol);
}
}
이렇게 5000번을 설정하고 테스트를 해보았더니
무려 75%가 실패로 떴다.
cpu 사용량도 확인해보니 어마어마하게 잡아먹는게 확인됐다.
곰곰히 생각해보니 유정 정보를 요청하는 api 뿐만 아니라 로그인하는 api도 함께 테스트가 되다보니 외부 요인이 작용한다는 생각이 들었다.
그래서 로그인 api는 제외하도록 로그인 요청 api는 진행하지 않고, 직접 post man 등의 방법으로 로그인하여 반환된 jwt토큰을 하드코딩으로 직접 입력해주어 동일하게 5000번 실행하였더니
실패율이 확 줄었고 cpu 사용량도
최대 60%로 확실하게 줄어드는 것을 확인할 수 있었다.