개발끄적

nGrinder로 시작하는 부하 테스트 가이드

누구세연 2025. 10. 20. 23:20

JMeter는 다양한 부하 테스트를 수행할 수 있는 강력한 도구지만, 팀 단위 운영이나 리포트 공유 측면에서는 한계가 있습니다.

이런 불편함을 해소하기 위해 등장한 도구가 바로 nGrinder입니다. nGrinder는 분산 부하 테스트, 웹 기반 시나리오 관리, 자동 리포트 생성 등 팀 단위 테스트 환경에 필요한 기능을 기본으로 제공합니다.

특히 JMeter에서 직접 설정해야 했던 분산 실행이나 리포팅 작업을 nGrinder에서는 웹 UI에서 클릭 몇 번으로 간단히 처리할 수 있죠. 🤔이번 글에서는 JMeter에서는 다소 번거로웠던 부분들을 nGrinder에서는 어떻게 더 쉽게 해결할 수 있는지 함께 살펴보겠습니다.

 

nGrinder란?

nGrinder는 네이버에서 진행한 오픈 소스 프로젝트로 서버의 부하 테스트를 위한 도구입니다.
쉽게 말해, 여러 대의 컴퓨터(Agent)를 동시에 이용해서 대규모 트래픽을 한꺼번에 발생시켜 서버의 성능을 테스트할 수 있는 도구예요. ⚒️

JMeter가 개인용 테스트 툴이라면, nGrinder는 팀이나 조직이 함께 사용하는 부하 테스트 플랫폼이라고 볼 수 있습니다.

 

 

nGrinder 구조

nGrinder는 크게 두 가지 역할로 나뉩니다.

  • Controller: 테스트를 관리하는 중앙 서버예요.
    웹 UI를 통해 테스트를 만들고, 실행하고, 결과를 확인할 수 있습니다.
  • Agent: 실제로 요청을 보내 부하를 발생시키는 역할이에요.
    Controller의 지시에 따라 동시에 트래픽을 발생시키고, 결과 데이터를 다시 전달합니다.

Controller가 언제, 몇 명이, 어떤 요청을 보낼지를 정하면 Agent들이 동시에 실행해 서버를 몰아붙입니다.

 

아래 그림은 이런 구조를 시각적으로 보여주는 nGrinder 시스템 아키텍처입니다 👇

1️⃣ 사용자가 Controller에 테스트 실행을 요청
2️⃣ Controller가 테스트 환경을 세팅하고 Agent들을 연결
3️⃣ Agent들이 실제로 타깃 서버(Target Server)에 트래픽을 발생
(이때 각 Agent는 Controller와 통신하며 상태를 유지하고)
4️⃣ 실행 결과와 서버의 모니터링 데이터를 다시 Controller로 보내 리포트가 생성

 

 

설치 및 환경 구성

이제 nGrinder의 개념과 구조를 이해했으니, 직접 설치해서 Controller와 Agent가 어떻게 동작하는지 확인해 보겠습니다! 🧐

1️⃣ 사전 준비

설치를 시작하기 전에 아래 환경을 준비해 주세요.

구분 요구사항
Java JDK 8 이상 (JDK 17 권장)
OS Windows, macOS, Linux 모두 가능
메모리 Controller 최소 2GB, Agent는 부하 크기에 따라 4GB 이상 권장
네트워크 Controller ↔ Agent 간 통신 가능해야 함 (기본 포트 16001, 16002)
💡
Controller와 Agent는 같은 서버에 설치해도 되지만,
실제 대규모 테스트를 위해서는 별도의 서버(혹은 VM, Docker 컨테이너)에 분리하는 게 좋습니다.

 

2️⃣ Controller 설치

nGrinder Controller는 웹 UI를 제공하는 중앙 서버입니다.
여기서 테스트를 만들고, Agent를 등록하며, 실행 결과를 확인할 수 있습니다.

 

방법 1. WAR 파일로 직접 실행

https://github.com/naver/ngrinder/releases

 

Releases · naver/ngrinder

enterprise level performance testing solution. Contribute to naver/ngrinder development by creating an account on GitHub.

github.com

위의 공식 릴리즈 페이지에서 최신 버전을 다운로드합니다.

 

다운로드한 후에 아래 명령어로 실행합니다.

java -jar ngrinder-controller-3.5.9-p1.war

 

기본 포트는 8080이나 저는 이미 사용 중이어서 포트를 지정하여 실행하였습니다.

(--port=8081)

브라우저로 http://localhost:8081 접속하면 nGrinder 로그인 화면이 나타납니다.

초기 로그인 정보
ID: admin
PW: admin

 

 

방법 2. Docker로 실행

Docker 환경이라면 훨씬 간단히 실행할 수 있습니다.

docker run -d --name ngrinder-controller \
  --platform linux/amd64 \
  -p 8080:80 \                 # UI
  -p 16001:16001 \             # Agent 제어포트
  -p 12000-12009:12000-12009 \ # ✅ 콘솔 포트(동시 테스트용 범위)
  ngrinder/controller:3.5.9-p1
✅ 실행 확인
브라우저에서 http://localhost:8080으로 접속했을 때
nGrinder Console 화면이 보이면 Controller 설치가 완료된 것입니다.

 

 

3️⃣ Agent 설치

Agent는 실제로 부하를 발생시키는 역할을 합니다.
Controller에서 테스트 명령을 받아 요청을 보내고, 결과를 다시 전달합니다.

 

1. Controller 웹 UI → 상단 메뉴 “Agent Download” 클릭

2. 다운로드한 파일(ngrinder-agent-3.5.9-p1-localhost.tar) 압축 해제

3. 아래 명령으로 실행

./run_agent.sh

 

 

4. 콘솔 로그에 아래와 같은 메시지가 뜨면 성공입니다.

Controller UI의 Agent Management 탭에서 Agent 상태가 Active로 표시되는지 확인합니다.

💡 여러 대의 Agent를 동시에 등록할 수도 있습니다.
테스트 규모가 클수록 Agent 수를 늘리면 분산 부하를 효율적으로 발생시킬 수 있습니다

 

 

첫 테스트 실행 (Hello nGrinder)

Controller와 Agent가 모두 준비되었으니, 실제로 nGrinder에서 부하 테스트를 만들어 실행해 볼 차례입니다.

nGrinder는 웹 UI에서 바로 스크립트를 작성하고, 실행 후 결과를 시각적으로 확인할 수 있습니다.

 

1️⃣ 로그인 및 기본 화면 살펴보기

브라우저에서 Controller 주소로 접속합니다.

기본 계정으로 로그인합니다.

  • ID: admin
  • PW: admin

테스트 작성과 실행을 빠르게 할 수 있는 “Quick Start” 영역을 중심으로 구성돼 있습니다.

메뉴 설명
Performance Test 실제 부하 테스트를 설정하고 실행하는 메인 메뉴
Script 테스트 스크립트를 작성하고 관리하는 공간
admin ▼ 사용자 계정 설정, Agent 관리, 시스템 설정 등
Help 공식 문서 및 Q&A 링크

Quick Start 영역

  • Type URL: 부하를 걸고 싶은 대상 URL을 입력하는 곳이에요.
    예를 들어 https://localhost:8080/get 입력 후 Start Test 클릭하면,
    자동으로 간단한 부하 테스트가 실행됩니다.
  • Groovy / Jython 선택: 사용할 스크립트 언어를 선택할 수 있어요.
    (기본은 Groovy, Python 스타일을 원하면 Jython 선택)

하단 영역

  • Q&A: 자주 묻는 질문과 커뮤니티 문서 링크
  • Developer Resources: API 문서, GitHub 링크 등 개발 참고자료

 

2️⃣ 샘플 스크립트 생성

처음 사용하는 경우라면,
nGrinder는 기본 HTTP 테스트 스크립트 샘플을 자동으로 제공합니다.

  1. 상단 메뉴 → Scripts 클릭
  2. “Create Script” 버튼 클릭
  3. Script Name 입력 (예: get-test)
  4. “Create” 클릭

 

생성 후 확인

스크립트 편집 화면에는 기본 템플릿 코드가 자동으로 생성됩니다.

 

보통 이런 형태로 시작해요 👇

import static net.grinder.script.Grinder.grinder
import static org.hamcrest.Matchers.*
import static org.junit.Assert.*

import net.grinder.script.GTest
import net.grinder.scriptengine.groovy.junit.GrinderRunner
import net.grinder.scriptengine.groovy.junit.annotation.BeforeProcess
import net.grinder.scriptengine.groovy.junit.annotation.BeforeThread
import org.junit.Before
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

@RunWith(GrinderRunner)
class TestRunner {

    public static GTest test
    public static HTTPRequest request

    // 필요 시 헤더/쿠키 넣고 싶을 때 여기 채워쓰면 됩니다.
    public static Map<String, String> headers = [:]
    public static List<Cookie> cookies = []

    @BeforeProcess
    public static void beforeProcess() {
        // ⚠️ setUseCookies(), getCookieManager() 같은 호출 넣지 말 것!
        HTTPRequestControl.setConnectionTimeout(300000)
        test = new GTest(1, "Sample HTTP Test")
        request = new HTTPRequest()
        grinder.logger.info("before process.")
    }

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

    @Before
    public void before() {
        // 공통 헤더/쿠키가 있으면 여기서 적용 (비어있으면 아무 일도 안 함)
        request.setHeaders(headers)
        CookieManager.addCookies(cookies)
    }

    @Test
    public void test() {
        String targetUrl = "https://httpbin.org/get"  // 필요 시 수정
        HTTPResponse res = request.GET(targetUrl)

        grinder.logger.info("GET {}", targetUrl)
        grinder.logger.info("status={}", res.statusCode)

        assertThat("Response code should be 200", res.statusCode, is(200))
    }
}

 

  • @BeforeProcess → 테스트 전 초기 설정 (전역, 1회)
  • @BeforeThread → 각 쓰레드 시작 전 1회
  • @Before → 매 요청 전에 실행 (쿠키, 헤더 초기화 등)
  • @Test → 실제 요청과 검증 수행

 

3️⃣ 테스트 설정

상단 메뉴에서 Performance Test로 이동하여 Create Test 버튼을 클릭합니다.

이 한 화면에서 “얼마나 많은 사용자(Vuser)”가 “어떤 스크립트”를 “얼마 동안” 돌릴지를 전부 지정하게 됩니다.

Performance Test

항목 설정 값 설명
Agent 1 컨트롤러에 연결된 에이전트 1개
Vuser per Agent 10 각 Agent가 10명 시뮬레이션
Processes × Threads 1 × 10 10명의 가상 사용자
Script get-test.groovy 실행할 테스트 스크립트
Duration 0:01:00 1분 동안 테스트 실행
Ramp-Up 비활성 모든 사용자 즉시 시작

➡️ 이 설정으로 “총 10명의 가상 사용자”가 “1분 동안” get-test.groovy 스크립트를 계속 실행하게 됩니다.

기본 정보 (상단)

  • Test Name: 테스트 이름. 리포트에 표시됩니다. (예: Get Test)
  • Description: 테스트 목적이나 메모를 남기는 곳.
    → “nGrinder GET 요청 테스트”처럼 기록용으로 사용.
  • Tags: 리포트 필터링용 태그. 여러 테스트를 구분할 때 유용

Test Configuration (중앙)

여기가 핵심 설정 구간이에요.

Agent

  • Agent (Max:1)
    → 현재 연결된 부하 발생기(Agent) 수.
    → 지금은 1개가 연결되어 있으니 1로 지정해야 함.
    → 여러 개 연결되어 있다면 2~3개 이상 선택 가능.

💡 Agent 1개 = 실제 테스트를 실행하는 서버 1대.

 

Vuser per agent (가상 사용자 수)

  • Agent 한 대가 동시에 시뮬레이션할 가상 사용자(Virtual User)
    → 예시 설정: 10
    → 즉, Agent 1개 × 10명 = 총 10명의 가상 사용자가 동시에 API 호출을 반복.
  • Processes: JVM 프로세스 수 (부하 발생 프로세스 단위)
  • Threads: 프로세스당 쓰레드 수
    → 실제 Vuser 수 = Processes × Threads
    → 지금은 1 × 10 = 10명.

💡 대부분의 경우 프로세스 1개, 쓰레드 수로 사용자 수 조절이 효율적입니다.

 

Script

  • 실행할 테스트 스크립트를 선택하는 부분.
    → 방금 작성한 get-test.groovy 선택!
    (파일명은 Script > List 탭에서 관리됩니다.)

Script Resources

  • 외부 리소스(예: CSV 데이터, 이미지, JSON 파일)를 같이 업로드할 때 사용.
    → 일반적인 API 테스트에는 비워둬도 OK.

Target Host

  • 테스트 대상 호스트의 공통 prefix URL을 지정하는 곳.
    → 예: http://wiremock:8080
    → 스크립트 안에서 상대 경로(/api/customers)로 호출할 수 있게 됩니다.

💡 스크립트에서 이미 전체 URL을 쓴다면 이 필드는 비워도 됩니다.

 

Duration / Run Count (하단)

부하 테스트의 “지속 시간” 또는 “반복 횟수”를 결정하는 부분입니다.

  • Duration
    → 테스트를 정해진 시간 동안 반복 실행
    → 예시: 0시간 1분 0초 → 1분 동안 테스트 실행
  • Run Count
    → 시간 대신 “몇 번 반복할지” 설정
    → 예: 1000 → 각 Vuser가 1000번 요청 보냄

💡 Duration과 Run Count 중 하나만 선택합니다.
보통은 Duration(시간 기반) 이 더 많이 쓰입니다.

Ramp-Up (점진적 부하 증가)

  • 체크하면 부하를 천천히 늘릴 수 있습니다.
    (모든 Vuser를 한 번에 실행하지 않고, 일정 간격으로 추가)
  • Initial Count: 처음 실행할 Vuser 수
  • Incremental Step: 한 번에 늘릴 Vuser 수
  • Interval: Vuser 증가 간격(ms 단위)

예: Initial 0, Step 1, Interval 1000 → 1초마다 1명씩 추가
즉, 점진 부하 테스트(Gradual Ramp-Up) 용도입니다.

 

설정 후 “Save & Start Test” 버튼을 클릭합니다.

 

4️⃣ 테스트 실행 및 모니터링

테스트가 실행되면 다음과 같은 화면이 나타납니다:

  • 그래프(Throughput, TPS, Response Time 등)가 실시간 갱신
  • 왼쪽 하단 로그 영역에서는 Agent 상태 확인 가능
  • 우측 상단에서는 현재 진행률실패율을 모니터링할 수 있습니다.
💡 팁: 테스트 도중 “Stop” 버튼을 눌러 중단할 수 있으며, 테스트 로그는 자동으로 압축되어 결과 리포트에 포함됩니다.

 

5️⃣ 결과 리포트 확인

테스트가 완료되면 자동으로 결과 리포트가 생성됩니다.
리포트는 다음 3가지 주요 섹션으로 나뉘어 있어요.

  1. Summary
    • 테스트 이름, 실행 시간, Vuser 수, TPS(초당 트랜잭션 수), 평균 응답 시간 등
    • 실패율 및 에러 코드 비율 확인 가능
  2. Charts (그래프)
    • TPS(Time Per Second): 초당 요청 처리량
    • Mean Response Time: 평균 응답 시간
    • Peak TPS: 시스템이 감당 가능한 최대 처리 속도
    • Errors: HTTP 오류(4xx, 5xx) 발생 비율
  3. Details (상세 데이터)
    • 스크립트별, 요청별 세부 응답 시간
    • 분당 요청 수, 응답 분포(Percentile 90, 95, 99)
    • 개별 스레드의 지연 시간까지 확인 가능

📦 리포트는 .zip 형태로 다운로드 가능하며, 팀 단위로 공유하거나 이전 테스트와 비교 분석할 수 있습니다.

 

 

6️⃣ 테스트 결과 해석 팁

nGrinder 리포트는 단순한 수치 이상의 정보를 제공합니다.

아래는 결과를 해석할 때 도움이 되는 핵심 포인트입니다 👇

항목 의미 해석 포인트
TPS (Transaction Per Second) 초당 요청 처리량 높을수록 처리 효율이 좋지만, 응답시간과 함께 봐야 함
Mean Response Time (평균 응답시간) 요청에 대한 평균 처리 시간 급격히 상승하면 서버 부하 또는 병목 가능성 있음
Error % 실패한 요청 비율 1% 이상이면 네트워크, 코드 예외, 타임아웃 등을 점검 필요
Vuser Stability 가상 유저의 응답 일관성 일부 유저만 느려진다면 특정 세션 또는 DB 락 이슈 가능
95% Line 상위 5% 요청의 응답시간 SLA 기준을 판단할 때 자주 활용 (예: 95% 응답이 2초 이내)

 

💬 예시 해석

TPS가 일정 수준 이상에서 평탄해지고 Response Time이 급상승한다면, 해당 시점이 시스템의 처리 한계 지점(Throughput Bottleneck)입니다.
Error가 특정 시점부터 증가한다면, DB 커넥션 부족 또는 Thread Pool 한계일 수 있습니다.

 

 

 

 

nGrinder는 단순한 부하 테스트 도구를 넘어, 테스트를 운영 프로세스에 자연스럽게 녹일 수 있는 플랫폼입니다.

한 번 환경만 세팅해 두면, 클릭 몇 번으로 팀 전체가 동일한 테스트를 재사용하고 결과를 한눈에 비교할 수 있죠.

앞으로는 Jenkins나 GitLab CI와 연동해 정기적인 성능 테스트 자동화까지 진행해 볼 계획입니다. 🚀