nGrinder를 활용한 부하 테스트

문정현·2024년 2월 1일
0

필자는 nGrinder를 로컬에서 구동하였으나 nGrinder Docker 이미지나 JDK 설정 등 호환 문제가 없다면 Docker로 하는것을 추천한다..

https://github.com/naver/ngrinder
공식 github에서 controller와 agent를 다운로드 받는다

기본 ID/PW(admin, admin) 입력 후 어드민 메뉴에서 Download Agent 선택하면 ngrinder-agent-{version}-localhost.tar 다운로드 가능하다

// .war 실행
java -Djava.io.tmpdir={HOME}/.ngrinder/lib -jar ngrinder-controller-{version}.war -p {port}

다운 받은 war파일을 실행한다 지금은 포트 7070 으로 설정

java -jar ngrinder-controller-{version}.war --port=7070

http://localhost:7070 으로 접속

ID : admin PW : admin 기본 설정값으로 로그인한다

아직 Agent를 다운받지 않았다면 다운받도록한다

다운받은 디렉토리로 이동하여

// 압축 해제
tar -xvf ngrinder-agent-{version}-localhost.tar
// 폴더로 이동
cd ngrinder-agent
// 쉘파일 실행
./run_agent.sh



Agent Management로 들어가서 초록 사과가 보인다면 세팅 완료.


스크립트를 작성해보자

import 생략

@RunWith(GrinderRunner)
class TestRunner {

	public static GTest test1

	public static HTTPRequest request
	public static Map<String, String> headers = [:]
	public static Map<String, Object> params = [:]
	public static List<Cookie> cookies = []

	//request에 담을 토큰 값 설정
	private static String token

	@BeforeProcess
	public static void beforeProcess() {
		HTTPRequestControl.setConnectionTimeout(300000)

		test1 = new GTest(1, "POST localhost:8080/api/members/login")

		request = new HTTPRequest()

		grinder.logger.info("before process.")
	}

	@BeforeThread
	public void beforeThread() {
		test1.record(this, "test1")

		grinder.statistics.delayReports = true
		grinder.logger.info("before thread.")
	}

	// 로그인
	@Test
	public void test1() {

		// 스레드별로 고유한 사용자 정보를 생성
		int threadIndex = grinder.getThreadNumber()
		String userEmail = "ngrinder" + (threadIndex + 1) + "@sparta.com"
		String userPassword = "Ngrinder123!"

		// 로그인 API에 요청을 보내서 JWT 토큰을 받아옴
		HTTPResponse response = request.POST("http://localhost:8080/api/members/login", [email: userEmail, password: userPassword])

		//토큰 앞에 붙는 쓸데없는 String 제거
		token = response.getHeader("Authorization").toString().substring(15);

		//헤더에 넣어줌
		headers.put("Authorization", token)

		//헤더 가져옴

		if (response.statusCode == 301 || response.statusCode == 302) {
			grinder.logger.warn("Warning. The response may not be correct. The response code was {}.", response.statusCode)
		} else {
			assertThat(response.statusCode, is(200))
		}
	}
}

핫딜 구매의 일부인 로그인 부분을 가져왔다.
login API 호출이 성공적으로 수행되었을 때 트랜잭션을 기록하여 TPS(초당 트랜잭션 처리), Executed Tests(시행 횟수), Successful Tests(성공 횟수), Errors(에러 발생 건수), Run time(시행 시간) 등을 기록한다.


하나의 쓰레드로 단순하게 핫딜 구매를 10분 돌려본 결과이다
TPS가 안정적이며 평균적으로 높은 처리량을 보여주고 있다고 생각한다. 이는 한 사용자만 시스템을 사용하고 있으므로 예상되는 결과인 것...


쓰레드를 1000개로 늘리니 확연한 차이를 보이기 시작한다. 쓰레드가 증가함에 따라 처리해야 할 트랜잭션도 상승하여 TPS가 크게 증가하고 있지만, 피크 시에는 급격한 변동이 관찰된다. 이는 시스템이 많은 수의 동시 요청을 처리하려고 할 때 비관적 락 설정으로 인해 발생하는 병목 현상으로 예상하고 있다.


마지막으로 3000개의 쓰레드
TPS가 더욱 불안정해지며, 평균 처리 시간이 상당히 증가한 것을 볼 수 있다. 이는 시스템이 과부하 상태에 접근하고 있음을 나타낼 수 있으며, 처리 실패(에러)의 수도 증가하고 있다... 불안불안한 상태..

profile
기록 == 성장

0개의 댓글