티스토리 뷰

nGrinder는 네이버에서 만든 오픈소스로, 성능 테스트를 쉽게할 수 있게 도와준다. nGrinder로 성능 테스트를 하기 위해선 Controller, Agent, Target Server가 각각 별도로 실행되어야 한다. 

 

  • Controller: 테스트 스크립트를 작성하고, Agent에 명령을 해서 테스트를 시작할 수 있도록 하는 웹서버다. 실행중인 테스트를 모니터링하거나, 테스트 결과를 시각화한 UI를 제공한다.
  • Agent: 실질적으로 부하를 발생시키는 역할이다. Controller에서 작성된 스크립트에 따라 Target Server에 부하를 발생시킨다.
  • TargetServer: 말 그대로 테스트를 진행할 서버를 말한다.

그럼 Controller와 Agent를 설치하고 실행해보자. 먼저 nGrinder에서 원하는 버전을 다운로드 하면 되는데, ngrinder-3.6.5 버전의 war파일을 설치했다.

 

설치한 후 war파일이 있는 경로로 이동해서 실행시키는 명령어를 입력한다.

java -jar ngrinder-controller-3.5.6.war --port=8300

이렇게 실행되면 성공

 

실행되고 localhost:8300으로 접속하면 로그인페이지가 나온다. User ID와 Password 모두 admin을 입력하면 로그인이 된다. 로그인 했다면 아래 사진처럼 메인 화면 상단에 admin을 누르고 Download Agent를 눌러 agent를 설치하자.

 

그럼 압축된 상태로 다운로드가 된다. 압축을 풀면 ngrinder-agent이름의 폴더가 생기는데, 폴더에 접근한 후 안에 있는 run_agent.sh 파일을 실행해준다.

cd ngrinder-agent
./run_agent.sh

역시 이렇게 로그가 찍히면 성공!

 

그리고 다시 localhost:8300에 접속한다. Target Server에 부하 테스트를 진행하기 전에 전체적으로 테스트가 잘 실행되는지 확인해보자. 먼저 메인화면에서 테스트할 URL을 입력하고 Start Test를 누른다.

google.com을 테스트해보자

 

그럼 아래와 같이 테스트 구성 화면이 나오는데, R HEAD를 누르면 어떤 스크립트가 테스트에 사용되고 있는지 알 수 있다. 지금은 간단하게 주어진 URL을 호출하고 상태 코드가 200인지 확인한다.

 

Agent를 0에서 1로 변경하고 Save and Start버튼을 누르면 아래 사진처럼 테스트를 예약하거나 바로 실행하는 것을 선택할 수 있는 팝업 창이 뜬다.

 

지금은 Run Now 버튼을 눌러 바로 실행해보자. 실행을 했는데 공이 빨간색으로 변하면 실패한 것이다. agent를 실행하고 있는 터미널의 로그를 보면 오류가 난 것을 알 수 있는데,

Unsupported class file major version 61

 

이런 오류가 적혀있다면 Java 버전 문제다. nGrinder는 아직 17이상의 Java 버전은 지원하지 않는다. 그래서 17 이상이라면 11로 변경한 후 컴퓨터 재부팅 후 다 시작해야 한다. (만약 재부팅 후에도 같은 오류가 뜬다면, 아래 명령어를 홈 경로에서 입력 후 다시 설치하고 실행하면 된다.)

sudo rm -r .ngrinder
sudo rm -r .ngrinder_ex
sudo rm -r .ngrinder_agent

 

성공했다면 그래프가 찍히면서 Summary쪽에 정보가 표시된다.

 

Summmary에 어떤 정보가 표시되는지 알아보자.

 

  • Total Vusers: 테스트한 유저 수
  • TPS: 초당 처리 가능한 요청 수
  • Peak TPS: 가장 TPS가 높을 때
  • Mean Test Time: 지연 시간
  • Executed Tests: 실행한 테스트 수
  • Successful Tests: 성공한 테스트 수
  • Errors: 에러 발생 개수
  • Run time: 실행 시간

이제 테스트도 끝났으니, Target Server에다가 부하 테스트를 진행해보자. 아래 사진처럼 Script를 생성해보자.

 

그럼 팝업 창이 나오는데, 이름은 아무거나 상관없고 URL은 Target Server에서 테스트할 API의 URL을 적어야 한다.

 

예시로 아래 코드가 테스트할 API라면

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/product")
public class ProductController {
    private final ProductService productService;

    @GetMapping
    public ResponseEntity getAll(@PageableDefault Pageable pageable) {
        var response = productService.getAll(pageable);
        return ResponseEntity.ok(response);
    }
}

 

URL에 http://ip:port/api/v1/product로 적어주면 된다. (ip는 검색하거나 와이파이 정보를 확인하면 알 수 있다.)

 

만들어주면 Groovy로 테스트 스크립트를 작성하는 화면으로 넘어가는데, 구조에 대한 설명은 Github Wiki에 잘 설명되어있다. 코드를 하나하나 짚어 설명하기에는 내용이 방대해서 넘어가고, 당장 다뤄야 할 @Test 메서드 부분을 수정해보자.

@Test
public void test() {
        //기존코드
	// HTTPResponse response = request.GET("http://10.150.15048:8080/api/v1/product", params)

        //변경된 코드 (params 제거)
        HTTPResponse response = request.GET("http://10.150.150.48:8080api/v1/product")

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

 

다 작성했다면 Target Server를 실행하고 테스트 스크립트에서 validate버튼을 눌러보자. 그럼 실제로 Target Server에서 조회쿼리가 나가는 것을 볼 수 있다.

Hibernate:
    select
        p1_0.product_id,
        p1_0.back_path,
        p1_0.back_url,
        p1_0.banner_path,
        p1_0.banner_url,
        p1_0.mobile_banner_path,
        p1_0.mobile_banner_url,
        p1_0.bio,
        p1_0.created_at,
        p1_0.front_path,
        p1_0.front_url,
        p1_0.title,
        p1_0.updated_at
    from
        tbl_product p1_0
    order by
        p1_0.created_at asc limit ?,
        ?

 

그리고 아까 봤던 Summary의 정보들이 로그로 찍히는 것을 볼 수 있다.

 

이대로 계속 테스트를 진행할 수 있으나, 더 편리하고 쉽게 테스트할 수 있는 방법이 있다. 상단에 Performance Test를 누르고 Create Test를 누르면 테스트 구성 화면으로 이동한다. 이동했다면 TestName은 아무거나 정하고 Script 부분에서 아까 만들었던 Script를 선택한다. (R HEAD로 맞는지 확인할 수 있다.)

 

이제 중요한 점이 얼마만큼의 시간동안 몇명이 조회할건지를 정해야 한다. 일단 시간은 기본값이 1분이니까 넘어가고, Vuser의 수를 1000명으로 늘렸다.

 

실행해보면? 잘 실행되는 것을 볼 수 있다. 

 

Target Server 로그 역시 어마어마한 조회쿼리가 찍힌 것을 볼 수 있다.

끝이 안보이는 스크롤바

 

이제 Summary 정보를 보면서 분석해보자. 서비스의 성능을 파악할 수 있는 지표는 2가지가 있다.

 

  • Throughput: TPS, RPS등으로 불리며, 1초에 처리하는 작업의 수를 의미한다.
  • Latency: 서버가 클라이언트로부터 요청을 받아서 응답을 보내주기까지 걸리는 시간을 의미한다.

그래서 Summary의 데이터 중 Throughtput에 해당하는 TPS와 Latency에 해당하는 Mean Test Time의 값을 보겠다. 아까 돌렸던 테스트의 TPS는 94.6이다.

 

이 말은 초당 약 94.6번의 API 요청을 처리할 수 있다는 얘기다. TPS는 높을수록 좋다. 예를 들어 A 서비스는 1초에 1000개의 작업을 처리하고 B 서비스는 1초에 2000개의 작업을 처리한다면 B 서비스가 성능면에서 더 좋은 것을 알 수 있다.

 

다음으로 Mean Test Time(지연시간)을 보면, 1,476.02ms로 약 1.4초다.

심각한 지연시간

 

지연시간은 서버가 클라이언트로부터 요청을 받아서 응답을 보내주기까지 걸리는 시간을 의미한다. 지연시간은 낮은게 좋다.

서비스가 작업을 얼마나 빠르게 처리할 수 있는지를 나타내는 지표이기 때문이다.

 

예를 들어, A 서비스는 웹서버가 클라이언트로부터 요청을 받고 응답을 보내는데 걸리는 시간이 200ms이고, B 서비스는 동일한 작업을 처리하는데 100ms가 걸렸다면 B 서비스가 성능면에서 더 좋은 것을 알 수 있다.

 

그럼 단순히 API를 최적화시켜서 TPS를 올리거나 지연시간을 낮춘다고 성능 개선이 될까? 물론 약간의 개선이 되겠지만, 서비스 전체적인 성능은 개선시킬 수 없다. 웹 서비스는 여러 시스템으로 구성되어 있다. 간단하게 생각해도 웹 애플리케이션 서버와 데이터베이스가 있다. 만약 데이터베이스에서 값을 가져올 때가 가장 낮은 처리량을 가지고 있는데, 엉뚱하게 다른 부분에서 최적화를 시킨다면 결국 전체적인 성능은 개선되지 않을 것이다.

 

전체적인 성능을 개선시키려면 병목구간을 찾아야 한다. 병목구간은 서브 시스템들 중 가장 낮은 처리량을 가진 시스템을 말하는데, 병목구간을 찾아서 성능을 개선시키거나 확장, 변경을 하게 되면 초당 처리량이 높아지게 되고 병목구간이 이동되도록 만들어야 한다. 이동된다는 말은 병목구간(처리량이 가장 낮음)을 개선시키면 처리량이 올라가고, 결국 병목구간 다음으로 처리량이 높았던 시스템이 병목구간이 되는 것을 말한다.

 

 

참고

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday