PromQL 서버 자원 사용량 쿼리 시각화
node_exporter 가 노출한 메트릭이 → PromQL 변환을 거쳐 → 차트가 되기까지 (Padion Frontend)
서버
node_exporter
/metrics 노출
→
Prometheus
주기적 scrape
시계열 저장
→
→
변환
prometheusTo
UPlotSeries()
→
핵심 두 타입.
Counter = 계속 누적 증가 → 그대로는 의미없고 rate()로 "초당 증가율"을 구해야 함.
Gauge = 그 순간의 값 → 그대로 사용.
① CPU 사용률 — Counter라서 rate()로 idle을 구해 뒤집는다
CPU Usage (%) COUNTER
100 - avg by (instance) ( rate(node_cpu_seconds_total{mode="idle"}[1m]) ) * 100
1
node_cpu_seconds_total{mode="idle"}
코어별 idle 누적 초 (counter)
core0: 89,412s
core1: 90,105s · · ·
→
2
rate( … [1m] )
최근 1분 초당 증가율
= "1초 중 몇 초 놀았나" (0~1)
core0: 0.82
core1: 0.90
→
3
avg by (instance)
서버별 코어 평균
(서버 하나 = 선 하나)
srv1: 0.86
→
4
* 100 → idle %
비율 → 퍼센트
srv1: 86% idle
→
5
100 - (…)
뒤집어 사용률
srv1: 14% 사용
{instance="srv1"}
{instance="srv2"}
y축 = 사용률 %, x축 = 시간
② 메모리 사용률 — Gauge라서 rate() 없이 비율 직접 계산
Memory Usage (%) GAUGE
( 1 - ( node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes ) ) * 100
1
MemAvailable / MemTotal
현재값 두 개 (gauge)
→ 여유 비율
6.4GB / 16GB = 0.40
→
2
1 - (…)
뒤집어 사용 비율
1 - 0.40 = 0.60
→
왜 rate()가 없나? MemAvailable·MemTotal은 "지금 이 순간의 바이트"인 Gauge라
그 자체로 의미가 있습니다. 반대로 CPU·Network는 "누적 합계"인 Counter라 반드시 rate()가 필요합니다.
③ 네트워크 — Counter rate() 후 단위 환산(B/s → Mbps), 차트 2개
Network TX / RX (Mbps) COUNTER
TX: rate(node_network_transmit_bytes_total[1m]) * 8 / 1024 / 1024
RX: rate(node_network_receive_bytes_total[1m]) * 8 / 1024 / 1024
1
…_bytes_total
누적 전송 바이트 (counter)
9,812,400,128 B
→
2
rate( … [1m] )
초당 바이트 (B/s)
1,310,720 B/s
→
3
* 8
바이트 → 비트
10,485,760 b/s
→
4
/ 1024 / 1024
→ Mbps
10 Mbps
네트워크만 query 배열에 항목이 2개(TX, RX)라서 Promise.all로 병렬 호출되고
차트 2개가 그려집니다. CPU·Memory는 1개.
④ GPU — 이 프로젝트엔 미구현 (참고)
GPU Usage 미구현
PROMETHEUS_QUERY.gpu = [] // 드롭다운엔 있지만 쿼리가 빈 배열 → 차트 안 그려짐
GPU는
node_exporter가 주지 않습니다.
NVIDIA DCGM exporter를 따로 설치하면
아래처럼 쿼리할 수 있습니다 (대부분 Gauge라 rate 불필요):
DCGM_FI_DEV_GPU_UTIL // GPU 사용률 % (gauge)
DCGM_FI_DEV_FB_USED / (DCGM_FI_DEV_FB_USED + DCGM_FI_DEV_FB_FREE) * 100 // GPU 메모리 %
※ 프로젝트의 hostGpuCnt/hostGpuMemSize는 Prometheus 메트릭이 아니라 호스트 등록 폼의 수동 입력값입니다.
한눈 요약
| 리소스 | 메트릭 타입 | rate() 필요? | 핵심 변환 | 차트 수 |
| CPU | Counter | ✅ 필요 | idle율 구해 100-로 뒤집기 | 1 |
| Memory | Gauge | ❌ 불필요 | (1 - 여유/전체) × 100 | 1 |
| Network | Counter | ✅ 필요 | B/s → ×8 → Mbps 환산 | 2 (TX·RX) |
| GPU | (DCGM) | 대개 ❌ | 미구현 — DCGM exporter 필요 | 0 |
서버 선택은 어디에? 위 모든 쿼리의 메트릭 뒤에 injectNameMatcher()가
name="srv1"(1개) 또는 name=~"srv1|srv2"(여러 개)를 동적으로 끼워넣습니다.
그래서 응답이 서버별로 갈라지고 → 차트에 서버마다 선 하나로 그려집니다.