티스토리 뷰

성능 테스트 도구 비교

 

Gatling
  • 스칼라를 통해 테스트 스크립트를 생성하는 부하 테스트 도구
  • 비동기식 아키텍처로 가상 사용자를 스레드가 아닌 메시지로 생성해 수천 명의 동시 사용자 재현가능한 성능 좋은 테스트 도구
  • 분산 테스트 지원하지 않아 다 수의 컴퓨터를 통해 테스트 할 수 없음..
JMeter
  • GUI를 제공해 쉽게 사용해 볼 수 있다.
  • 한 명의 가상 사용자를 하나의 스레드로 생성하여 동시성제한 있음.
  • 분산 테스트를 지원한다. 즉, 여러대의 컴퓨터를 통해 테스트하고 그 테스트 결과를 종합할 수 있다.
nGrinder
  • Jython, Groovy 스크립트를 활용해 테스트 시나리오 작성가능
  • 한 명의 가상 사용자를 하나의 스레드로 생성하여 동시성제한 있음.
  • 분산 테스트를 지원한다. 즉, 여러대의 컴퓨터를 통해 테스트하고 그 테스트 결과를 종합할 수 있다.

 

특징 비교

  Gatling  nGrinder JMeter
요청 처리 방법 비동기 지원 비동기 지원하지 않음 비동기 지원하지 않음
분산 테스트 지원 분산테스트 지원하지 않음 분산테스트 지원 분산테스트 지원

 

도구 선택

nGrinder , Gatling 학습을 목적으로 둔 성능 테스트다 보니 특징이 서로 다른 두 도구 모두 사용해보고자 함.

다만 우선적으로는 nGinder 를 선택하고자 함. F-Lab 멘토링을 같이 받고있는 동료분이 Gatling 을 사용하기로 하셔서 서로 다른 도구를 사용해 공유하는 것이 좋아보이기 때문인데. 추후 관련 내용을 공유받고 직접 한 번 시도해볼 예정.

 

 

nGrinder

nGrider 구조

Controller
  • 컨트롤러는 Ngrinder의 GUI 를 제공해주는 부분을 말한다.
  • 스크립트 생성 및 테스트 명령을 Agent 에 전달하는 역할
Agent
  • Controller 로 부터 요청을 받아 Target 에게 요청을 보내는 역할을 한다.
Target
  • Agent로 부터 요청을 받아 스트레스 테스트를 해야하는 대상

 

작업 과정

우선 Ngrinder 를 통한 스트레스 테스트를 하기 위해서는 요청을 위한 스크립트 생성및 요청을 에이전트로 전달해주는 컨트롤러와 전달 받은 요청에 따라 스트레스 테스트 타겟 서버에 스트레스 테스트를 실행해줄 에이전트가 필요하다.

Controller 다운로드 및 실행

다운로드

ngrinder-controller-{version}.war 를 위 링크에서 다운로드 받는다.

위에서 다운받은 파일이 있는 폴더에서 해당 명령어를 통해 실행한다.

java -XX:MaxPermSize=200m -jar ngrinder-controller-3.5.3.war -p {port}

⛔️ 주의

  • 자바 8 or 11 로 실행하는 것을 추천함. 자바 17에서는 불안정하다.

 

Controller 접속

브라우저에서 주소창에 'https://localhost:{port}' 를 입력하여 nGrinder Controller에 접속후

위 화면에서 아이디 : admin , 패스워드 : admin 을 입력하고 지원하는 언어를 한국어로 하여 로그인한다.

 

Agent 다운로드 및 실행

 

Controller에 로그인하고 나면 우측 상단에 에이전트 다운로드를 찾아서 다운받을 수 있다.

해당파일의 압축은 tar -xvf {agent-file} 을 통해 풀 수 있다. 압축을 풀고나면 ngrinder-agent 폴더로 들어가 run_agent.sh 쉘 파일을 실해해주면 에이전트가 실행된다.

./run_agent.sh

💡 만약 환경이 Local 환경이 아니라면 agent_conifg 파일을 수정해주어야 한다.

 

스크립트 만들기

nGrinder는 스크립트를 통해 테스트 시나리오를 만들 수 있다. nGrinder의 Controller 에는 스크립트를 만드는 기능을 제공한다.

스크립트 탭에서 스크립트 만들기를 선택하면 아래와 같은 화면이 나온다. 해당 화면에서

URL, 헤더, Body 등을 입력하여 만들어줄 수 있다.

 

 

⛔️ 주의

  • Local 환경의 테스트를 진행할 때 URL에 localhost 를 추가하면 적절한 형식이 아니라는 문구가 나온다. 이 때는 127.0.0.1 로 대신하면 생성이 가능해진다.
Groovy 로 생성한 스크립트
import static net.grinder.script.Grinder.grinder
import static org.junit.Assert.*
import static org.hamcrest.Matchers.*
import net.grinder.script.GTest
import net.grinder.script.Grinder
import net.grinder.scriptengine.groovy.junit.GrinderRunner
import net.grinder.scriptengine.groovy.junit.annotation.BeforeProcess
import net.grinder.scriptengine.groovy.junit.annotation.BeforeThread
// import static net.grinder.util.GrinderUtils.* // You can use this if you're using nGrinder after 3.2.3
import org.junit.Before
import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith

import org.ngrinder.http.HTTPRequest
import org.ngrinder.http.HTTPRequestControl
import org.ngrinder.http.HTTPResponse
import org.ngrinder.http.cookie.Cookie
import org.ngrinder.http.cookie.CookieManager

/**
* A simple example using the HTTP plugin that shows the retrieval of a single page via HTTP.
*
* This script is automatically generated by ngrinder.
*
* @author admin
*/
@RunWith(GrinderRunner)
class TestRunner {

	public static GTest test
	public static HTTPRequest request
	public static Map<String, String> headers = [:]
	public static String body = "{\\n    \\"groupOrderId\\":null,\\n    \\"itemId\\":null,\\n    \\"quantity\\":4,\\n    \\"hours\\":24,\\n    \\"sendInfo\\":{\\n        \\"senderName\\": \\"손현호\\",\\n        \\"senderPhoneNumber\\":\\"01076181227\\"\\n    },\\n    \\"recipientInfo\\":{\\n        \\"recipientName\\":\\"고영찬\\",\\n        \\"firstAddress\\":\\"인천시\\",\\n        \\"secondAddress\\":\\"주월동\\",\\n        \\"zipCode\\":\\"322-4\\",\\n        \\"recipientPhoneNumber\\":\\"010-xxxx-xxxx\\"\\n    }\\n}"
	public static List<Cookie> cookies = []

	@BeforeProcess
	public static void beforeProcess() {
		HTTPRequestControl.setConnectionTimeout(300000)
		test = new GTest(1, "127.0.0.1") //IP
		request = new HTTPRequest()

		// Set header data
		headers.put("Content-Type", "application/json")
		grinder.logger.info("before process.")
	}

	@BeforeThread
	public void beforeThread() {
		test.record(this, "test")
		grinder.statistics.delayReports = true
		grinder.logger.info("before thread.")
	}

	@Before
	public void before() {
		request.setHeaders(headers)
		CookieManager.addCookies(cookies)
		grinder.logger.info("before. init headers and cookies")
	}

	@Test
	public void test() {
		HTTPResponse response = request.POST("<http://127.0.0.1:8072/orders>", body.getBytes())

		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(201)) 
			// 예상하는 Status Code 정확히 맞춰야함
			// Create에 대해 200번으로 해서 검증 실패 나왔었음.**
		}
	}
}

 

테스트 생성

상단에 성능테스트 탭을 통해 테스트 생성이 가능하다. 테스트명및 기본 설정을 하고 스크립트를 선택하여 테스트를 시작할 수 있다. 실행중인 에이전트가 없다면 테스트 생성이 불가능하다.

 

테스트 결과

 

 

Test 정보

Total Vuser(Virtual User) : 가상 유저수

TPS : 초당 트랜잭션 수 즉, 초당 요청 개수

평균 테스트 시간 : 테스트 한 건이 응답을 주는 시간

 

🤔 테스트 과정의 이슈

  • 기본적으로 개인 PC에 기본 자바 버전이 17 버전이었다. 17 버전으로 nGrinder 를 시도했을 때 Agent 실행과정에서 아래와 같은 에러가 발생했다
    • JNA는 (Java Native Access) JNI를 통하지 않고 원시 라이브러리에 액세스 하기 위한 라이브러리
    • 로드할 수 없는 위치에 가보았을 때 jna 로 시작하는 다른 이름의 파일이 있었던 것으로 보아 17버전에 포함되지 않았거나, 위치가 바뀌었거나 이름이 바뀌었을 것으로 예상된다.
2022-10-04 22:20:31,642 INFO  agent config: NGRINDER_AGENT_HOME : /Path/.ngrinder_agent
2022-10-04 22:20:31,643 INFO  agent config: Overwrite the existing agent.conf with __agent.conf
Exception in thread "main" java.lang.UnsatisfiedLinkError: Can't load library: /Path/Library/Caches/JNA/temp/jna14880329978073017781.tmp
	at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2393)
	at java.base/java.lang.Runtime.load0(Runtime.java:755)
	at java.base/java.lang.System.load(System.java:1953)
	at com.sun.jna.Native.loadNativeDispatchLibraryFromClasspath(Native.java:1018)
	at com.sun.jna.Native.loadNativeDispatchLibrary(Native.java:988)
	at com.sun.jna.Native.<clinit>(Native.java:195)
	at com.sun.jna.Structure.setAlignType(Structure.java:280)
	at com.sun.jna.Structure.<init>(Structure.java:197)
	at com.sun.jna.Structure.<init>(Structure.java:193)
	at com.sun.jna.Structure.<init>(Structure.java:180)
	at com.sun.jna.Structure.<init>(Structure.java:172)
	at com.sun.jna.platform.mac.SystemB$Timeval.<init>(SystemB.java:511)
	at oshi.software.os.mac.MacOperatingSystem.<clinit>(MacOperatingSystem.java:84)
	at oshi.SystemInfo.createOperatingSystem(SystemInfo.java:111)
	at oshi.util.Memoizer$1.get(Memoizer.java:87)
	at oshi.SystemInfo.getOperatingSystem(SystemInfo.java:100)
	at org.ngrinder.common.util.SystemInfoUtils.<clinit>(SystemInfoUtils.java:59)
	at org.ngrinder.NGrinderAgentStarter.checkDuplicatedRun(NGrinderAgentStarter.java:280)
	at org.ngrinder.NGrinderAgentStarter.main(NGrinderAgentStarter.java:208)
  • Mac M1 (ARM) 의 경우 Ngrinder Docker Image가 존재하지 않는다.

작업 과정에서 느낀점

nGrinder를 활용한 스트레스 테스트 과정에서 테스트 시도까지는 어렵지 않았다. 다만 해당 과정에서 테스트의 목적과 전략 그리고 각 지표를 통해 어떤 가설을 세울 수 있을지 가 더 중요해보인다.

추후 확인해 봐야할 목록은 아래와 같다고 생각이 든다.

  • TPS와 total vuser 를 통해 어떤 가설을 세울 수 있는가
  • ramp-up 테스트가 의미하는 바가 무엇인가?
  • 테스트 시간을 길었을 때 혹은 짧았을 때 각각은 어떤 의미를 갖는가.
  • 바이트 도달 시간 혹은 평균 테스트 시간이 주는 의미는 무엇인가?
  • 어떤 테스트 전략이 있고 각 테스트 전략에 따라 각 지표는 어떤 의미를 가지는가?

상황에 맞는 테스트 전략 세우기와 그 결과를 통해 가설을 만들어 낼 수 있도록 컴퓨터 사이언스 기초 지식학습이 중요해 보인다.

추가로 GET 요청에는 JSON BODY 를 넣을 수 없음. 물론 GET 요청에 바디를 추가하는 것이 정상적인 것은 아니지만, 종종 그런 방식으로 API를 작성한 경험이 있다. 하지만 이런 경우 외부 라이브러리 사용에 제약이 생길 수 있다는 점을 명심해야할 것으로 보인다.

  • 외에도 안드로이드의 경우 GET에 Body를 넣는 경우 요청이 불가능한 경험이 있음

 

참조

성능테스트 도구 비교(오픈소스)

 

성능테스트 도구 비교(오픈소스) · 기술블로그

SW 기능 특징 비고 JMeter * java 기반 오픈소스. * GUI/non-GUI Mode 지원. * 분산테스트 지원(URL) * bamboo 지원 (연동방법) * Thread 기반으로 동시성에 제한이 있음. * 여러 프로토콜/플러그인 지원 * 로드러너

atyou73.github.io

nGrinder 스크립트(Groovy) 작성법

 

nGrinder 스크립트(Groovy) 작성법

nGrinder 스크립트(Groovy) 작성법 테스트를 실행할 수 있는 스크립트는 Groovy, Jython, Groovy Mav...

blog.naver.com

[Docker] nGrinder 사용법

 

[Docker] nGrinder 사용법

nGrinder란, 네이버에서 서버의 부하 테스트를 위해 오픈 소스 프로젝트로 진행한 도구로, 애플리케이션을 서비스하기 전에 서버가 얼마나 많은 사용자를 수용 가능한 지 요청함으로써 서버의 성

a-half-human-half-developer.tistory.com

nGrinder 스크립트(Groovy) 작성법

 

nGrinder 스크립트(Groovy) 작성법

nGrinder 스크립트(Groovy) 작성법 테스트를 실행할 수 있는 스크립트는 Groovy, Jython, Groovy Mav...

blog.naver.com

 

댓글