이제, prometheus를 사용하는 grafana 그리고, (제대로 될 진 모르곘지만) pinpoint가 준비되었으니 nGrinder를 이용해서 부하 테스트를 수행할 준비를 해보자.
1. nGrinder설치
여기 에서 war를 다운해주자. (난 3.5.8을 사용했다.)
release note에
- Shows error message when running without tmpdir property
란 항목이 적혀있다.
그냥 받은 war를 실행하게 되면
이런 오류가 뜨며 실행이 되지 않는다.
에러 로그에서 처럼 로그를 기록할 디렉토리를 명시해줘야 실행이 된다는 뜻이다.
java -Djava.io.tmpdir={로그를 기록할 디렉토리/파일명} -jar ngrinder-controller-3.5.8.war --port=8300
그렇기에, 이런식으로 디렉토리를 jvm옵션으로 적어주고 실행해야 한다.
이제 http://localhost:8300/login 로 이동하여 로그인 후, agent를 다운받자. (초기 id,pw는 admin,admin이다)
다운 받은 압축 파일을 풀어주고
tar -xvzf ngrinder-agent-3.5.8-localhost.tar
해당 폴더에서 run_agent.sh을 실행해주자.
./run_agent.sh
그 후, 에이전트 관리 탭으로 이동하면 이렇게 잘 잡혀있는 걸 볼 수 있다.
2. 테스트 스크립트 작성
이제 상단의 Script탭을 눌러 ->Create->Create a script로 스크립트를 생성해보자.
원하는 이름을 작성해주고, 테스트할 URL을 입력해준다.
여기서 URL에 localhost,127.0.0.1 이런식으로 내부 IP를 사용하면 안된다. (agent를 통해서 뭐 외부에서 쏘는 듯 하다..??)
localhost는 안되는데, 127.0.0.1 혹은 192~ 이런 내부 IP는 사용이 가능하다. (물론, agent또한 로컬에서 실행한다는 가정 하에)
따라서, 외부 IP 주소를 작성한 후 포트포워딩을 해주자
네이버에 내 아이피 쳐서 외부 IP를 확인한 후, 자신의 공유기 설정에 들어가 테스트 대상 서버의 포트를 열어주면 된다.
그 후, 스크립트를 작성한다.
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 Map<String, Object> params = [:]
public static List<Cookie> cookies = []
public static int testCount
@BeforeProcess
public static void beforeProcess() {
HTTPRequestControl.setConnectionTimeout(3000)
test = new GTest(1, "{설정한 외부 IP or 도메인}")
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() {
def id = UUID.randomUUID().toString()
def email=id+"@uos.ac.kr"
params.put("email",email)
params.put("password","123")
params.put("classOf","111")
params.put("name","nGrinderTest")
params.put("nickname","nGrinderUser")
HTTPResponse response = request.POST("http://{설정한 외부 IP or 도메인}:{포트(도메인 이라면 x)}/auth/signup", params)
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))
}
Map<String, Object> loginParams = ["email":email,"password":"123","fcmToken":"djDBQUAQTcy-Q7yn5Y_uZG:APA91bHrdu3OC_7EK_XS-UnepZs7H0Z29wcphC2JRqrwG-XHWNOwAIPXJoSOUpGc9RbeCDshPryJJXG8Mry_YA2WyXYh06epNUaJkGBeLQcHXK9wU7pEfhtdTuEnaVAL6cSJ60p5Y29v"]
HTTPResponse loginResponse = request.POST("http://{설정한 외부 IP or 도메인}:{포트(도메인 이라면 x)}/auth/login", loginParams)
if (loginResponse.statusCode == 301 || loginResponse.statusCode == 302) {
grinder.logger.warn("Warning. The response may not be correct. The response code was {}.", response.statusCode)
} else {
assertThat(loginResponse.statusCode, is(200))
}
}
}
자바와 비슷하기도 하고, 자바 클래스를 import도 할 수 있는 듯 하니 자세한 스크립트 설정은 직접 해보는 것을 추천한다
3. 테스트 수행
이제 상단의 Performance Test 탭으로 이동하자
Create Test를 누르면
이런 설정 화면이 나온다.
각 항목은 아래의 기능을 담당한다. ( 여기에 정리된 항목 내용을 퍼왔습니다 !)
- Agent : Controller와 연결되어 있는 에이전트의 수 만큼 설정할 수 있습니다.
- Vuser per agent : 실질적으로 부하를 발생시키는 주체로 프로세스와 스레드 수를 조정하여 vUser(가상 사용자)를 생성합니다. 통상 vUser 수 = 프로세스 수 * 스레드 수 로 계산합니다.
vUser는 Controller에서 실행한 테스트 스크립트에 따라 동작하여 Target Server에 부하를 생성합니다. - Script : 사용자가 해당 주소로 부하를 걸 스크립트를 보여줍니다.
- Duration, Run Count : 해당 테스트를 얼마만큼 실행할 지 설정합니다. 테스트 기간과 실행 횟수 중 하나만 선택할 수 있습니다.
- Enable Ramp-Up : 점차 부하를 걸 수 있는 기능입니다. 점차 부하를 가할 때, vUser를 늘리는 것이 아닌 process나 thread를 늘립니다.
- Initial Count : 처음 시작시 vUser의 수를 설정합니다.
- Initial Sleep Time : 테스트를 언제부터 실행시킬 지 설정합니다.
- Incremental Step : 해당 process/thread를 몇 개씩 증가시킬지 설정합니다.
- Interval : 설정한 것의 상승 시간을 설정합니다.
우선, 간단하게 기본 설정 그대로 테스트를 진행해봤다. (agent는 당연히 있어야 테스트가 가능하기에 1로 설정)
이런식으로 테스트가 설정한 시간 동안 진행되고, 테스트가 끝나게 되면
이렇게 결과 화면이 나온다.
결과에서, TPS라는 항목이 주로 표현되는데, TPS란 (Test Per Second) 초당 테스트 처리 수를 의미한다.
즉, 이 값이 높을 수록 더 많은 테스트를 수행한다는 뜻이고, 성능이 더 좋다는 뜻이 된다.
이제 nGrinder를 이용해서 테스트를 수행하고 모니터링하는 것 까지 모두 완료했으니
본격적으로 프로젝트에 대해 테스트를 수행하고 병목지점을 찾고, 개선 작업을 해보자.
참고
https://leezzangmin.tistory.com/42
'Spring' 카테고리의 다른 글
부하 테스트 하기 (6) - 성능 개선 with Cache (0) | 2023.07.16 |
---|---|
부하 테스트 하기 (5) - 사용 시나리오별 테스트 하기 (0) | 2023.07.15 |
부하 테스트 하기(3) -핀포인트 오류 잡기 (1) | 2023.07.13 |
부하 테스트 하기 (2) (0) | 2023.07.12 |
부하 테스트 하기 (1) (1) | 2023.07.08 |