이번 실습은 Docker로 Spring 예제 서버와 DB를 실행한 뒤, nGrinder를 이용해 서버 또는 DB에 부하를 주고 성능 테스트 결과를 확인하는 과정이다.
nGrinder는 네이버에서 개발한 Java 기반 오픈소스 성능 테스트 도구이다.
주요 구성은 다음과 같다.

맥북에서는 터미널을 열고 원하는 위치로 이동한다.
예시로 Documents 폴더에 실습 폴더를 만든다.
cd ~/Documents
mkdir ngrinder-practice
cd ngrinder-practice


교수님 자료에서는 Docker의 awesome-compose 저장소를 사용한다.

git clone https://github.com/docker/awesome-compose.git

클론이 끝나면 폴더로 이동한다.
cd awesome-compose
강의록에서는 Spring + PostgreSQL 예제를 사용한다.
cd spring-postgres
현재 파일 구조를 확인한다.
ls
대략 이런 파일들이 있어야 한다.
backend
db
compose.yaml
README.md


맥북에서는 VS Code가 있으면 아래처럼 열 수 있다.
code compose.yaml
VS Code가 없다면 터미널에서 직접 열 수 있다.
nano compose.yaml

강의록에서는 8080 포트가 이미 사용 중이면 다른 포트로 바꾸라고 되어 있다.
lsof -i :8080

아무것도 안 나오면 → 8080 사용 안 하는 중
뭔가 나오면 → 이미 사용 중
만약 8080이 이미 사용 중이면 아래처럼 바꿀 수 있다.
ports:
- 8081:8080
이 경우 내 맥북에서 접속할 주소는 다음과 같다.
http://localhost:8081
PostgreSQL 포트는 보통 아래처럼 되어 있다.
ports:
- 5432:5432
만약 내 컴퓨터에서 5432 포트를 이미 쓰고 있으면 다음처럼 바꿀 수 있다.
ports:
- 5433:5432
단, 이 경우 외부에서 DB에 접근할 때 포트는 5433을 사용해야 한다.
image를 postgres에서 postgres:17로 변경한다.
ports도 추가한다.

맥북에서는 먼저 Docker Desktop을 켜야 한다.

왼쪽 하단에 Engine running이라고 되면 완전히 켜진거다.
Docker Desktop이 완전히 실행된 뒤 터미널에서 아래 명령어를 입력한다.
docker compose up -d
참고로 요즘 Docker에서는 docker-compose보다 docker compose 명령어를 많이 쓴다.

docker ps
Spring 서버와 PostgreSQL 컨테이너가 실행 중인지 확인한다.

브라우저에서 접속해본다.
http://localhost:8080
또는 포트를 바꿨다면:
http://localhost:8081

nGrinder Controller에 접속한다.
강의록에서는 다음 형태로 접속한다.
http://localhost

id와 pw모두 admin, admin으로 접속
nGrinder 화면에서 오른쪽 위의 admin 메뉴를 클릭한다.

여기서 Agent가 실행 중인지 확인한다.
Agent가 정상 실행 중이면 목록에 초록색 상태 표시 또는 Agent 정보가 나타난다.

상단 메뉴에서 Script로 이동한다.


테스트할 URL을 입력한다.
http://{ip 주소}:8080

스크립트를 만들면 Sample Groovy 스크립트가 자동으로 생성된다.

교수님이 올려주신걸로 바꾼다.
import static net.grinder.script.Grinder.grinder
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.Test
import org.junit.runner.RunWith
import groovy.sql.Sql
@RunWith(GrinderRunner)
class DBTest {
public static GTest test1 = new GTest(1, "조회 시나리오")
public static GTest test2 = new GTest(2, "작성 시나리오")
public static GTest test3 = new GTest(3, "삭제 시나리오")
public static Sql sql
@BeforeProcess
public static void beforeProcess() {
def url = "jdbc:postgresql://host.docker.internal:5432/example"
def user = "postgres"
def password = "db-wrz2z"
def driver = "org.postgresql.Driver"
sql = Sql.newInstance(url, user, password, driver)
}
@BeforeThread
public void beforeThread() {
test1.record(this, "doSelect")
test2.record(this, "doInsert")
test3.record(this, "doDelete")
grinder.statistics.delayReports = true
}
@Test
public void test() {
def threadId = grinder.threadNumber % 10
switch (threadId) {
case 0..5:
doSelect()
break
case 6..7:
doInsert()
break
case 8..9:
doDelete()
break
}//여기 고쳐야함
}
public void doSelect() {
def result = sql.firstRow("SELECT COUNT(*) as cnt FROM greetings")
grinder.logger.info("greetings row 수: {}", result.cnt)
assertNotNull(result)
}
public void doInsert() {
def name = "Tester"
sql.executeInsert("INSERT INTO greetings(name) VALUES (?)", [name])
grinder.logger.info("INSERT 완료 - ${name}")
}
public void doDelete() {
def deleted = sql.executeUpdate("DELETE FROM greetings WHERE id IN (SELECT id FROM greetings ORDER BY id DESC LIMIT 1)")
grinder.logger.info("레코드 삭제: ${deleted}건")
}
}
수정한 뒤에는 반드시 Validate 버튼을 눌러 오류가 없는지 확인한다.
정상이라면:
Save / Close
DB 테스트를 하려면 PostgreSQL JDBC 드라이버 jar 파일이 필요하다.
강의록에서는 아래 파일을 사용한다.
postgresql-42.2.10.jar
다운로드 주소:
nGrinder에서 업로드 위치:
Script → lib → Upload → jar 파일 추가


@RunWith(GrinderRunner)
의미:
nGrinder에서 실행 가능한 테스트 스크립트라는 뜻이다.
즉, “이 Groovy 파일은 nGrinder 테스트용 코드다”라고 알려주는 부분이다.
@BeforeProcess
public static void beforeProcess() {
...
}
의미:
테스트가 시작되기 전에 한 번만 실행되는 부분이다.
주로 다음 작업을 한다.
@BeforeThread
public void beforeThread() {
...
}
의미:
각 스레드가 실행되기 전에 준비하는 부분이다.
주로 다음 작업을 한다.
delayReports = true는 테스트 측정 정확도를 높이기 위해 리포트 기록을 약간 지연시키는 설정이다.
@Test
public void test() {
...
}
의미:
실제로 성능 테스트가 실행되는 부분이다.
여기에서 조회, 삽입, 삭제 같은 작업을 실행한다.
강의록에서는 threadID를 기준으로 작업을 나누어 서로 다른 비율로 테스트를 진행한다.
예시 구조:
전체 요청 중 일부는 조회
일부는 삽입
일부는 삭제
이렇게 하면 실제 사용자의 행동 패턴을 비슷하게 반영할 수 있다.
테스트 메소드에서는 SQL 명령을 실행한다.
예시 역할:
SQL 실행은 주로 아래 형태를 사용한다.
sql.execute(...)
sql.executeInsert(...)
sql.firstRow(...)
nGrinder 상단 메뉴에서 Performance Test로 이동한다.
Performance Test → 테스트 생성

방금 만든 Groovy 테스트 스크립트를 선택한다.

| 항목 | 의미 |
|---|---|
| Agent | 성능 테스트에 사용할 에이전트 수 |
| Vuser per agent | 에이전트 1대당 가상 사용자 수 |
| Process | 하나의 Agent에서 생성할 프로세스 수 |
| Thread | 하나의 Process 안에서 실행할 스레드 수 |
| Script | 실행할 Groovy 테스트 스크립트 |
| Duration | 테스트를 얼마나 오래 실행할지 설정 |
| Run Count | 스레드 1개당 스크립트를 몇 번 반복할지 설정 |
| Enable Ramp-up | 테스트 시작 시 부하를 점진적으로 늘릴지 여부 |
| Initial Count | 처음 시작할 Process 또는 Thread 수 |
| Initial Sleep Time | 테스트 시작 전 대기 시간 |
| Incremental Step | 부하를 증가시킬 단위 |
| Interval | 몇 초마다 부하를 증가시킬지 설정 |
설정이 끝나면 테스트를 실행한다.

실행 후 nGrinder에서 다음 결과를 확인할 수 있다.
테스트가 끝난 뒤 결과 화면에서 성능 지표를 확인한다.
주요하게 볼 부분:

프로세스와 쓰레드를 많이 넣어서, 아예 시스템이 다운되어서 테스트가 실패하면 확인받기
| Windows | Mac |
|---|---|
| PowerShell 사용 | Terminal 사용 |
dir | ls |
cd 폴더명 | 동일 |
docker-compose up -d | docker compose up -d 권장 |
localhost 사용 가능 | 동일 |
| VS Code 또는 메모장 | VS Code, nano, TextEdit 가능 |
GitHub 예제 프로젝트 clone
→ Docker Compose로 Spring + PostgreSQL 실행
→ nGrinder 접속
→ Agent 확인
→ Groovy Script 생성
→ JDBC jar 업로드
→ Performance Test 생성
→ 부하 테스트 실행
→ 결과 확인