부하 테스트 가이드

nGrinder 완전 가이드

👥 방문자 수

nGrinder는 네이버가 개발한 오픈소스 분산 부하 테스트 플랫폼입니다. 웹 UI 기반으로 Controller와 Agent를 관리하고, Groovy/Jython 스크립트로 복잡한 시나리오를 손쉽게 구성할 수 있습니다.

오픈소스 웹 UI 분산 테스트 Groovy/Jython 네이버 개발
🧪 실전 예제 보기 → ← TestForge 홈으로

nGrinder란?

nGrinder는 Naver가 The Grinder를 기반으로 만든 엔터프라이즈급 부하 테스트 플랫폼입니다. 국내 대형 서비스에서 검증된 안정성과 웹 UI를 통한 편리한 관리가 특징입니다.

주요 특징

아키텍처

컴포넌트역할포트
Controller웹 UI 제공, 테스트 조율, 결과 수집8080 (HTTP)
Agent실제 부하 생성 워커 노드16001 (Controller 통신)
Monitor대상 서버의 CPU/메모리 모니터링13243

Controller 1대 + Agent N대 구성으로 선형적으로 부하를 확장할 수 있습니다. Agent 1대당 일반적으로 500~2000 VU를 처리할 수 있습니다.

설치

Controller 설치

요구사항

# nGrinder Controller WAR 다운로드
wget https://github.com/naver/ngrinder/releases/download/ngrinder-3.5.9/ngrinder-controller-3.5.9.war

# 실행 (기본 포트 8080)
java -jar ngrinder-controller-3.5.9.war

# 포트 변경
java -jar ngrinder-controller-3.5.9.war --port 8090

# 백그라운드 실행
nohup java -jar ngrinder-controller-3.5.9.war > ngrinder.log 2>&1 &bash

실행 후 http://localhost:8080에 접속합니다. 기본 계정: admin / admin

⚠️
보안 주의: 프로덕션 환경에서는 반드시 기본 관리자 비밀번호를 변경하고, nginx 등 리버스 프록시 뒤에 배치하세요.

Agent 설치

# Controller 웹 UI에서 Agent 패키지 다운로드
# Admin 메뉴 → Download Agent

# 또는 직접 다운로드
wget https://github.com/naver/ngrinder/releases/download/ngrinder-3.5.9/ngrinder-agent-3.5.9-localhost.tar

tar -xf ngrinder-agent-3.5.9-localhost.tar
cd ngrinder-agent

# Agent 시작
./run_agent.sh

# Controller IP 지정
./run_agent.sh -ch CONTROLLER_IPbash
Agent가 성공적으로 연결되면 Controller 웹 UI의 Agent Management 페이지에서 확인할 수 있습니다.

Agent 설정 파일 (agent.conf)

# ~/.ngrinder_agent/agent.conf
agent.controller_host=192.168.1.100
agent.controller_port=16001
agent.region=NONEini

스크립트 작성

Groovy 기본 스크립트

웹 UI에서 Script → Create Script를 선택하거나, 아래 템플릿을 사용합니다.

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.RunWith
import net.grinder.scriptengine.groovy.junit.annotation.BeforeThread
import net.grinder.scriptengine.groovy.junit.annotation.BeforeProcess
import org.ngrinder.http.HTTPRequest
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 headers = [:]

    @BeforeProcess
    public static void beforeProcess() {
        HTTPRequestControl.setConnectionTimeout(300000)
        test = new GTest(1, "testforge.kr")
        request = new HTTPRequest()
        grinder.logger.info("프로세스 초기화 완료")
    }

    @BeforeThread
    public void beforeThread() {
        test.record(this, "test")
        grinder.statistics.delayReports = true
        grinder.logger.info("스레드 초기화 완료")
    }

    @Test
    public void test() {
        HTTPResponse response = request.GET("https://testforge.kr/")

        if (response.statusCode == 301 || response.statusCode == 302) {
            grinder.logger.warn("리다이렉트: ${response.headers.location}")
        }

        assertThat(response.statusCode, is(200))
    }
}groovy

고급 시나리오 — 로그인 후 API 호출

import static net.grinder.script.Grinder.grinder
import net.grinder.scriptengine.groovy.junit.annotation.*
import net.grinder.scriptengine.groovy.junit.GrinderRunner
import org.ngrinder.http.HTTPRequest
import org.ngrinder.http.HTTPResponse

@RunWith(GrinderRunner)
class ApiTestRunner {

    public static HTTPRequest request

    @BeforeProcess
    public static void beforeProcess() {
        request = new HTTPRequest()
    }

    @BeforeThread
    public void beforeThread() {
        // 스레드별 로그인 처리
        def loginBody = '{"email":"test@example.com","password":"password123"}'
        def loginRes = request.POST(
            "https://api.example.com/login",
            loginBody.bytes,
            ["Content-Type": "application/json"]
        )
        def token = parseJson(loginRes.text).token
        request.headers["Authorization"] = "Bearer ${token}"
        grinder.logger.info("로그인 성공, 토큰 획득")
    }

    @Test
    public void getUsers() {
        def res = request.GET("https://api.example.com/users")
        assertThat(res.statusCode, is(200))
    }

    @Test
    public void createUser() {
        def body = '{"name":"LoadUser","email":"load@example.com"}'
        def res = request.POST(
            "https://api.example.com/users",
            body.bytes,
            ["Content-Type": "application/json"]
        )
        assertThat(res.statusCode, is(201))
    }

    private static Map parseJson(String json) {
        new groovy.json.JsonSlurper().parseText(json)
    }
}groovy

테스트 실행

웹 UI에서 실행

  1. Quick Start 또는 Performance Test → Create Test
  2. 스크립트 선택 (SVN 저장소에서)
  3. 테스트 파라미터 설정:
파라미터설명예시
Agent사용할 Agent 수3
Vuser per agentAgent당 가상 사용자 수100 (총 300 VU)
Script실행할 Groovy 스크립트api_test.groovy
Duration테스트 시간 (분)10분
Run count각 VU의 반복 횟수Duration 또는 횟수
Ramp-upVU를 점진적으로 증가초기 10, 단계 10, 간격 1분

모니터링

nGrinder Monitor 설치 (대상 서버)

# 부하 대상 서버에 Monitor 설치
wget https://github.com/naver/ngrinder/releases/download/ngrinder-3.5.9/ngrinder-monitor-3.5.9.tar

tar -xf ngrinder-monitor-3.5.9.tar
cd ngrinder-monitor
./run_monitor.shbash

Controller 웹 UI에서 테스트 실행 시 대상 서버의 IP를 Target Host에 입력하면 CPU, 메모리, 네트워크 I/O가 실시간으로 표시됩니다.

보고서

테스트 완료 후 자동으로 HTML 보고서가 생성됩니다. 포함 내용:

Docker 배포

version: '3.8'

services:
  controller:
    image: ngrinder/controller:3.5.9
    ports:
      - "8080:8080"
      - "9010-9020:9010-9020"
      - "12000-12009:12000-12009"
    volumes:
      - ngrinder-controller:/opt/ngrinder-controller
    restart: unless-stopped

  agent:
    image: ngrinder/agent:3.5.9
    depends_on:
      - controller
    environment:
      - CONTROLLER_ADDR=controller
    deploy:
      replicas: 3
    restart: unless-stoppedyaml

실전 팁

💡
Vuser 수 계산: 목표 TPS = Vuser 수 / 평균 응답 시간(초)
예: TPS 100 목표, 평균 응답 시간 0.5초 → Vuser 50개 필요

도구 비교

항목nGrinderk6JMeter
인터페이스웹 UICLIGUI + CLI
스크립트Groovy / JythonJavaScriptGUI + Groovy
분산 테스트기본 내장 ⭐⭐⭐⭐⭐k6 Cloud별도 설정 필요
CI/CD 통합REST API⭐⭐⭐⭐⭐⭐⭐⭐
학습 곡선중간낮음중간
💡
nGrinder 추천 상황: 팀 내 비개발자도 테스트에 참여하거나, 분산 부하가 필수이고 웹 UI 기반 관리가 필요한 경우.

더 자세한 내용은 TestForge Docs에서 확인하고, 다른 도구와 비교는 k6 가이드JMeter 가이드를 참고하세요.