자기소개페이지만들기

5. 자기소개 백엔드에 nGrinder로 부하 발생시켜 보기

nGrinder는 서버에 대한 부하 테스트를 하는 것으로 서버의 성능을 측정할 수 있습니다.

nGrinder 아키텍처

Controller

  • 퍼포먼스 테스팅(부하테스트)를 위해 웹 인터페이스를 제공
  • 테스트 프로세스를 체계화
  • 테스트 결과를 수집해 통계로 보여줌

Agent: Controller의 명령을 받아 실행.

  • agent 모드가 실행될 때 target이 된 머신에 프로세스와 스레드를 발생시켜 부하를 발생.
  • moniter 모드가 실행되면 대상 시스템의 cpu와 memory를 모니터링.

Target: 부하테스트를 받는 머신.

 

이러한 ngrinder를 직접 설치하는 방식이 있지만 이방식보다 도커를 통해서 이미지를 풀받고 컨테이너로 실행하는 방식이 간편해서 도커로 진행하려고 합니다. (도커 짱!)

 

이번 실습은 도커가 설치되어 있다는 가정하에 진행됩니다.

 

1. nGrinder-controller 이미지를 풀받아서 실행까지 진행

docker run -d -v ~/ngrinder-controller:/opt/ngrinder-controller -p 80:80 -p 16001:16001 -p 12000-12009:12000-12009 ngrinder/controller:3.4

-v 볼륨 옵션 : pc와 컨테이너 간의 볼륨을 설정

-p 포트 설정 : 80포트는 접속 포트, 16001포트 : 12000~12009포트

 

 

 

2. nGrinder-agent 이미지를 풀받아서 실행까지 진행

docker run -v ~/ngrinder-agent:/opt/ngrinder-agent -d ngrinder/agent:3.4 controller_ip:controller_web_port

controller_ip: controller_web_port 부분을 위에서 설정한 controller의 ip와 port로 적어서 실행시킨다. 본인의 경우 2개의 agent를 생성하였습니다.

 

3. nGrinder 접속

초기 계정은 admin/admin

한국어로 변경후 로그인

4. agent 확인

에이전트 관리로 이동

가면 앞서 만들었던 에이전트가 2개 있으면 정상적으로 연결된겁니다.

 

5 nGrinder로 간단한 부하 테스트 하기

본인이 부하를 테스트 하고 싶은 주소를 입력해서 Quick Start를 진행해 봅시다.

메인페이지에 주소를 입력후 테스트 시작 버튼을 클릭해줍니다.

 

시작 버튼 클릭시 이러한 화면으로 이동하는데 저는 에이전트 2개를 모두 사용하고 가상사용자를 각 약 300명 총 600명 수준의 접속에 대한 부하 테스트를 1분간 진행 해보겠습니다. 본인들이 테스트하고 싶은 수준을 설정한 뒤 상단에 저장 후 시작을 누르시면 테스트가 실행됩니다.

실행 결과는 아래와 같습니다.

vuser : virtual user로 동시에 접속하는 유저의 수를 의미. (vuesr = agent * process * thread)

TPS : 초당 트랜잭션의 수 - 초당 처리 수

트랜잭션 : HTTP Request가 성공할 때마다, 트랜잭션 수가 1씩 증가.

최고 TPS : 초당 처리 수의 최대치.

평균 테시트 시간 : 사용자가 request한 시점에서 시스템이 response할 때까지 걸린 시간.

총 실행 테스트 : 테스트 시간동안 실행한 테스트의 수

쉽게 생각하면 tps는 높을수록 테스트시간과 에러는 적을수록 좋습니다.

 

6. 테스트 스크립트 작성해보기

위에 테스트는 주소를 입력해서 테슽트 했다면 이번에는 직접 테스트 코드를 작성해서 진행하여 봅시다.

상단의 스크립트를 클릭해줍니다.

 

스크립트 만들기를 클릭해줍니다.

 

스크립트 명을 정해주시고 테스트할 url과 해당 url이 post인지 get인지 선택해주세요.

본인의 경우 get 테스트를 진행하기때문에 get을 선택하였습니다.

입력이 완료되면 만들기를 눌러주세요.

 

그러면 아래와 같이 스크립트를 작성해주게 됩니다.

import static net.grinder.script.Grinder.grinder
import static org.junit.Assert.*
import static org.hamcrest.Matchers.*
import net.grinder.plugin.http.HTTPRequest
import net.grinder.plugin.http.HTTPPluginControl
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 java.util.Date
import java.util.List
import java.util.ArrayList

import HTTPClient.Cookie
import HTTPClient.CookieModule
import HTTPClient.HTTPResponse
import HTTPClient.NVPair

/**
 * 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 NVPair[] headers = []
	public static NVPair[] params = []
	public static Cookie[] cookies = []

	@BeforeProcess
	public static void beforeProcess() {
		HTTPPluginControl.getConnectionDefaults().timeout = 6000
		test = new GTest(1, "ec2-13-125-104-210.ap-northeast-2.compute.amazonaws.com")
		request = new HTTPRequest()
		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)
		cookies.each { CookieModule.addCookie(it, HTTPPluginControl.getThreadHTTPClientContext()) }
		grinder.logger.info("before thread. init headers and cookies");
	}

	@Test
	public void test(){
		HTTPResponse result = request.GET("http://ec2-13-125-104-210.ap-northeast-2.compute.amazonaws.com/api/member", params)

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

 

 

저의 자기소개 페이지의 대민 메인 페이지는 특정 멤버를 조회 하고 해당 멤버의 projects와 skills를 조회하여 뿌려주게 되어있습니다. 그래서 저는 member 조회하고 projects와 skills 까지 테스트 해볼려고합니다.

그래서 test 메서드 밑에 아래의 코드를 추가하였습니다.

 

@Test
	public void testSkill(){
		HTTPResponse result = request.GET("http://ec2-13-125-104-210.ap-northeast-2.compute.amazonaws.com/api/skill?memberId=16&size=300", params)

		if (result.statusCode == 301 || result.statusCode == 302) {
			grinder.logger.warn("Warning. The response may not be correct. The response code was {}.", result.statusCode); 
		} else {
			assertThat(result.statusCode, is(200));
		}
	}
	
	@Test
	public void testProject(){
		HTTPResponse result = request.GET("http://ec2-13-125-104-210.ap-northeast-2.compute.amazonaws.com/api/project?memberId=16}&size=300&sort=level,asc", params)

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

스크립트 작성이 완료 되면 저장 후 검증을 눌러봅시다.

스크립트 하단에 테스트가 실행되고 요청에 관련된 시간 등 검증이 정상적이라면 여러분이 작성한 코드가 적절하게 작성되었음을 의미합니다.

 

 

 

7. 직접짠 스크립트로 테스트 진행

상단의 성능테스트 버튼을 눌러 이동하고 테스트 생성을 클릭해줍니다.

 

이전에 테스트와 동일한 화면을 확인할수있는데 내용이 비어 있습니다. 적절하게 채워 줍시다.

 

스크립트 부분 이전에 직접 작성한 스크립트로 설정해줍니다.

 

 

작성이 끝나면 저장후 시작 버튼을 클릭해주세요.

 

vuser가 약 200명 수준일때

 

vuser가 약 400명 수준일때

 

vuser가 약 600명 수준일때

\

vuser가 약 800명 수준일때

사용자가 200명 수준을때는 에러도 발생하지않고 200ms대의 테스트 시간이 사용자가 증가하면서 에러가 발생하고 테스트시간도 증가하는 추세를 보이게 됩니다.

물론 1분 동안의 테스트이기때문에 보다더 긴 시간의 테스트를 진행하는 등 추가적인 설정 등이 필요하지만 일단 부하를 발생시켜볼수 있었습니다.

 

보다 더 자세한 성능 측정, 병목지점을 찾는 등을 위해서는 모니터링 도구(scouter, pinpointer 등)을 통해서 서버의 상태를 확인해가면서 테스트를 진행해야합니다.

 

그래서 다음글에서는 모니터링 도구를 사용해보도록 하겠습니다. 감사합니다.

 

ps

6000명 수준이 되니 오류가 30%가 넘어가면서 테스트가 중단되는 모습

 

참조:

jmlim.github.io/ngrinder/2019/07/01/ngrinder-docker-setup/

 

docker를 통한 ngrinder 설치 및 사용 · 기억하기 위한 개발노트

docker를 통한 ngrinder 설치 및 사용 01 Jul 2019 | ngrinder Docker 엔그라인더 부하테스트 nGrinder 란? 네이버에서 성능 측정 목적으로 개발된 오픈소스 프로젝트이며, The Grinder라는 오픈소스 기반으로 개발

jmlim.github.io