NestJS 메트릭 기반 모니터링 시스템 구축 (prom-client, Prometheus, Grafana)
사전 지식
Prometheus 환경 세팅
Prometheus 설정
prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
# - "first.rules"
# - "second.rules"
scrape_configs:
- job_name: prometheus
static_configs:
- targets: ['localhost:9090']
- 예제 구성 파일에는 세 가지 구성 블록이 있다.
global****: 프로메테우스 서버의 글로벌 설정scrape_interval- 데이터를 수집하는 주기
- Prometheus가 타겟에 가서 메트릭을 긁어오는 간격
- 예시: 15초마다 서버에 가서 현재 CPU, 메모리 등의 값을 가져옴
evaluation_interval- 규칙을 계산하는 주기
- 예시: “CPU가 80% 넘었나?”
rule_files****: Prometheus 서버가 로드할 규칙의 위치를 지정- 지금은 주석 처리
scrape_configs****: Prometheus가 감시할 서버 목록- 기본값은 Prometheus가 자기 자신을 모니터링
- 왜냐? Prometheus 서버도 메트릭을 제공하는 HTTP 서버이기 때문 (http://localhost:9090/metrics)
- Prometheus는 모든 타겟이 기본적으로
/metrics경로에 메트릭을 노출한다고 가정
- 기본값은 Prometheus가 자기 자신을 모니터링
도커 컴포즈 설정
docker-compose.yml
prometheus:
image: prom/prometheus
ports:
- '9090:9090'
volumes:
- ./infra/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
실행:
docker compose up prometheus -d
Prometheus UI 접속

PromQL 테스트
-
수집 정상 여부 확인
up결과:
up{job="prometheus", instance="localhost:9090"} 1 -
Prometheus HTTP 요청 수
prometheus_http_requests_total결과:

-
메모리 사용량
process_resident_memory_bytes결과:

NestJS metrics 생성
https://github.com/willsoto/nestjs-prometheus
의존성 설치
npm install @willsoto/nestjs-prometheus prom-client
AppModule 수정
import { Module } from "@nestjs/common";
import { PrometheusModule } from "@willsoto/nestjs-prometheus";
@Module({
imports: [PrometheusModule.register()],
})
export class AppModule {}
도커 컴포즈 설정
docker-compose.yml
app:
volumes:
- .:/app
- /app/node_modules
ports:
- '3000:3000'
실행:
docker compose up app -d
/metrics 엔드포인트 테스트
# HELP process_cpu_user_seconds_total Total user CPU time spent in seconds.
# TYPE process_cpu_user_seconds_total counter
process_cpu_user_seconds_total 3.92215
# ... 중략
Node.js 기본 메트릭(defaultMetrics)
-
프로세스(Process) 메트릭
메트릭 현재 값 단위 의미 process_cpu_user_seconds_total3.92 seconds 사용자 영역 CPU 사용 시간 process_cpu_system_seconds_total1.20 seconds 시스템 영역 CPU 사용 시간 process_cpu_seconds_total5.12 seconds 전체 CPU 사용 시간 process_resident_memory_bytes130,191,360 bytes 실제 물리 메모리 사용량 process_virtual_memory_bytes925,908,992 bytes 가상 메모리 process_heap_bytes407,281,664 bytes 힙 전체 크기 process_open_fds24 count 열린 파일 디스크립터 수 process_max_fds1,048,576 count 최대 허용 fd 수 -
이벤트 루프(Event Loop) 상태
메트릭 값 단위 의미 nodejs_eventloop_lag_seconds0.0064 seconds 현재 이벤트 루프 지연 nodejs_eventloop_lag_mean_seconds0.0118 seconds 평균 지연 nodejs_eventloop_lag_p99_seconds0.0154 seconds 99% 지연 nodejs_eventloop_lag_max_seconds0.0517 seconds 최대 지연 -
활성 리소스/핸들
메트릭 값 의미 nodejs_active_resources_total7 현재 이벤트루프를 유지하는 리소스 nodejs_active_handles_total5 활성 libuv 핸들 nodejs_active_requests_total1 활성 요청 수 -
힙 메모리 상태
메트릭 값 단위 nodejs_heap_size_total_bytes50,823,168 bytes nodejs_heap_size_used_bytes46,498,680 bytes nodejs_external_memory_bytes2,668,963 bytes -
GC (Garbage Collection)
종류 실행 횟수 총 소요 시간 minor 3회 0.019s major 3회 0.079s incremental 3회 0.084s
Prometheus - NestJS 연동
prometheus.yml 수정
scrape_configs:
- job_name: prometheus
metrics_path: /metrics
static_configs:
- targets: ['prometheus:9090']
- job_name: app
metrics_path: /metrics
static_configs:
- targets: ['app:3000']
PromQL 테스트
-
수집 정상 여부 확인
up결과:
up{job="app", instance="app:3000"} 1 up{job="prometheus", instance="prometheus:9090"} 1 -
NestJS 메트릭 수집 확인 (프로세스 메모리)
process_resident_memory_bytes{job="app"}
-
NestJS CPU 사용량 추이(초당 증가량)
rate(process_cpu_seconds_total{job="app"}[1m])
-
이벤트 루프 지연 확인 (ms 단위로 보기)
nodejs_eventloop_lag_p99_seconds{job="app"} * 1000
Grafana 환경 세팅
도커 컴포즈 설정
docker-compose.yml
grafana:
image: grafana/grafana
ports:
- "3002:3000"
volumes:
- grafana_data:/var/lib/grafana
depends_on:
- prometheus
volumes:
prometheus_data:
grafana_data:
실행:
docker compose up grafana -d
Grafana 접속
- http://localhost:3002/
- ID:
admin - PW:
admin
- ID:
- 첫 로그인 시 비밀번호 변경 화면이 뜰 수 있음.

Grafana - Prometheus 연동
Prometheus Data Source 추가
-
Grafana 접속 → 왼쪽 메뉴 Connections(또는 톱니바퀴 Settings) → Data sources
-
Add data source → Prometheus 선택
-
URL 입력
http://prometheus:9090 -
Save & test
-
docker-compose 네트워크 안에서 Grafana가 Prometheus를 접근할 때는
localhost가 아니라 서비스명(prometheus) 를 써야 함. -
Successfully queried the Prometheus API.안내 메시지가 뜨는지 확인
-

Grafana 대시보드 확인
Explore에서 쿼리 테스트
- 왼쪽 메뉴 Explore에서 Prometheus 선택 후 아래 쿼리 실행
up

공개 대시보드 찾기
- https://grafana.com/grafana/dashboards/
- 여기서 검색창에
node.js검색 - 원하는 디자인의 대시보드 페이지에 들어가면 Dashboard ID 가 있을텐데 기억해두기

Node.js/NestJS 대시보드 불러오기
Grafana는 Import로 공개 대시보드를 쉽게 가져올 수 있음
-
왼쪽 메뉴 Dashboards → New → Import
-
Dashboard ID로 Import
- 예시: 11159
-
DB_PROMETHEUS는prometheus선택
대시보드 확인
제대로 설정이 됐다면 아래와 같이 대시보드 화면이 잘 나오는 것을 볼 수 있음
