티스토리 뷰
백엔드 모니터링은 어디서부터 시작해야 할까? 헬스체크, 메트릭, Prometheus까지 FastAPI · Spring Boot · Node.js 실전 정리
octo54 2026. 6. 8. 11:01백엔드 모니터링은 어디서부터 시작해야 할까? 헬스체크, 메트릭, Prometheus까지 FastAPI · Spring Boot · Node.js 실전 정리
한 줄 요약
운영에서 로그만으로는 부족합니다. 최소한 헬스체크 엔드포인트, 요청 수·에러 수·응답 시간 같은 메트릭, 그리고 필요하면 Prometheus 수집 구조까지 붙여야 “서버가 살아 있나”를 넘어서 “지금 느려졌는지, 에러가 늘었는지, 어디가 병목인지”를 볼 수 있습니다. Spring Boot는 Actuator로 health와 metrics, /actuator/prometheus를 공식 지원하고, Prometheus는 카운터·게이지·히스토그램 같은 메트릭 모델을 제공합니다. FastAPI는 미들웨어로 요청 전후 처리를 넣기 쉽고, Node.js에선 prom-client가 기본 메트릭과 커스텀 메트릭 수집을 지원합니다. (Home)
이 글에서 다루는 내용
- 헬스체크와 메트릭이 왜 필요한지
- /health와 /metrics는 어떻게 다르게 생각해야 하는지
- Counter, Gauge, Histogram은 언제 쓰는지
- FastAPI, Spring Boot, Node.js에서 바로 시작 가능한 최소 구현
- 검색에 잘 걸리도록 질문형 제목, 첫 문단 정답, 정의 문장, 실행 코드, FAQ 구조를 반영한 글 구성 원칙
백엔드 모니터링이란?
백엔드 모니터링은 “서버가 켜져 있는가”만 보는 게 아니라, 응답이 느려졌는지, 에러가 늘었는지, 리소스가 부족한지, 특정 기능만 이상한지를 계속 추적하는 일입니다. Spring Boot는 production-ready features로 health와 metrics 수집을 자동 적용할 수 있다고 설명하고, Prometheus는 시계열 메트릭을 수집해 질의와 알림에 쓰는 모니터링 시스템이라고 설명합니다. (Home)
조금 더 현실적으로 말하면 이렇습니다.
- 로그는 “무슨 일이 있었는지”를 나중에 보는 기록
- 헬스체크는 “지금 살아 있는지”를 빨리 확인하는 신호
- 메트릭은 “얼마나 느리고, 얼마나 실패하고, 얼마나 바쁜지”를 수치로 보는 도구
운영으로 가면 결국 이 세 개가 같이 필요해집니다.
왜 로그만으로는 부족할까
로그는 정말 중요합니다.
그런데 로그만 있으면 이런 질문에 바로 답하기 어렵습니다.
- 지금 요청 수가 갑자기 늘었나?
- 5분 전부터 에러율이 치솟았나?
- 평균 응답 시간보다 p95 지연이 더 문제인가?
- 현재 처리 중인 작업 수가 얼마나 되나?
이런 건 로그를 뒤져서 계산할 수도 있지만, 운영에선 너무 늦고 번거롭습니다.
그래서 메트릭이 필요해요.
Prometheus는 시계열 데이터 모델을 쓰고, 메트릭 이름과 레이블로 시계열을 구분한다고 설명합니다. 그리고 이런 메트릭을 주기적으로 scrape해서 쿼리와 알림에 활용합니다. (Prometheus)
즉 로그와 메트릭은 경쟁 관계가 아니라 역할이 다릅니다.
- 로그: 사건의 맥락
- 메트릭: 수치 변화와 추세
헬스체크와 메트릭은 어떻게 다를까
이건 진짜 많이 헷갈립니다.
헬스체크
“서비스가 지금 정상적으로 응답 가능한 상태인가?”
보통은 /health 같은 엔드포인트로 둡니다.
Spring Boot는 health endpoint가 기본 애플리케이션 상태 정보를 제공한다고 설명합니다. (Home)
메트릭
“서비스가 지금 얼마나 바쁘고, 얼마나 느리고, 얼마나 실패하고 있나?”
보통은 /metrics 또는 Prometheus용 /metrics, /actuator/prometheus 같은 엔드포인트로 둡니다.
Spring Boot는 Prometheus가 애플리케이션 인스턴스를 scrape하고, Spring Boot는 /actuator/prometheus endpoint를 제공한다고 설명합니다. (Home)
아주 짧게 구분하면:
- /health는 살아 있나
- /metrics는 어떻게 살고 있나
이렇게 보면 됩니다.
그럼 최소한 뭘 먼저 붙여야 할까
저는 보통 이 순서로 추천합니다.
- /health
- 요청 수 Counter
- 에러 수 Counter
- 응답 시간 Histogram
- 필요하면 진행 중 작업 수 Gauge
- 그다음 Prometheus scrape
이 정도면 벌써 운영 감각이 꽤 달라집니다.
왜 이렇게 추천하냐면, Prometheus metric types 문서가 말하는 네 가지 타입 중에서도 초반에 가장 많이 쓰는 게 바로 이 조합이기 때문입니다. Counter는 누적 증가 값, Gauge는 오르내리는 현재값, Histogram은 관측값 분포에 적합하다고 설명합니다. (Prometheus)
Counter, Gauge, Histogram은 언제 써야 할까
Prometheus 공식 문서는 메트릭 타입을 네 가지로 설명합니다. 초반엔 사실 세 가지만 먼저 이해해도 충분합니다. (Prometheus)
Counter
계속 증가만 하는 값입니다.
예:
- 총 요청 수
- 총 에러 수
- 완료된 작업 수
Prometheus는 Counter는 단조 증가하는 누적 메트릭이고, 감소할 수 있는 값을 Counter로 쓰면 안 된다고 설명합니다. (Prometheus)
Gauge
올라가기도 하고 내려가기도 하는 현재값입니다.
예:
- 현재 진행 중 요청 수
- 현재 큐 길이
- 현재 메모리 사용량
Histogram
관측값의 분포를 기록합니다.
예:
- 응답 시간
- 외부 API 호출 시간
- 배치 작업 소요 시간
초반 운영에서 특히 중요한 건 응답 시간을 평균 하나로만 보지 않는 겁니다. 평균은 멀쩡해 보여도 tail latency가 나쁠 수 있어서, Histogram이 훨씬 현실적이에요.
Prometheus는 왜 많이 쓰일까
Prometheus는 오픈소스 모니터링 시스템이고, 시계열 메트릭을 수집해서 PromQL로 질의하고 알림까지 연결할 수 있습니다. 공식 사이트도 모니터링 시스템과 시계열 데이터베이스라고 설명하고, GitHub 저장소 설명도 configured targets에서 metrics를 주기적으로 수집한다고 설명합니다. (Prometheus)
개발자 입장에서는 이 점이 편합니다.
- 애플리케이션이 메트릭을 노출
- Prometheus가 주기적으로 가져감
- Grafana 같은 도구로 시각화
- 임계치 넘으면 알림
즉 처음엔 /metrics만 잘 노출해도, 나중에 운영 확장이 쉬워집니다.
1) FastAPI에서 헬스체크와 메트릭 시작하기
FastAPI는 미들웨어를 추가해서 모든 요청 전후에 공통 처리를 넣기 쉽습니다. 공식 문서도 미들웨어는 모든 요청이 특정 path operation으로 가기 전, 그리고 응답이 돌아가기 전에 동작한다고 설명합니다. (FastAPI)
FastAPI는 Spring Boot Actuator처럼 내장 health/metrics 시스템이 강하게 딸려오지는 않아서, 보통은 직접 /health를 만들고, 미들웨어로 요청 시간/카운트 메트릭을 기록하는 쪽으로 시작합니다.
설치 방법
pip install fastapi uvicorn prometheus-client
예제 코드
# main.py
import time
from fastapi import FastAPI, Request, Response
from prometheus_client import Counter, Gauge, Histogram, generate_latest, CONTENT_TYPE_LATEST
app = FastAPI()
REQUEST_COUNT = Counter(
"http_requests_total",
"Total number of HTTP requests",
["method", "path", "status_code"],
)
ERROR_COUNT = Counter(
"http_errors_total",
"Total number of HTTP error responses",
["method", "path", "status_code"],
)
IN_PROGRESS = Gauge(
"http_requests_in_progress",
"Number of HTTP requests currently in progress",
)
REQUEST_LATENCY = Histogram(
"http_request_duration_seconds",
"HTTP request latency in seconds",
["method", "path"],
)
@app.middleware("http")
async def metrics_middleware(request: Request, call_next):
path = request.url.path
method = request.method
IN_PROGRESS.inc()
start_time = time.perf_counter()
try:
response = await call_next(request)
except Exception:
ERROR_COUNT.labels(method=method, path=path, status_code="500").inc()
IN_PROGRESS.dec()
raise
duration = time.perf_counter() - start_time
status_code = str(response.status_code)
REQUEST_COUNT.labels(method=method, path=path, status_code=status_code).inc()
REQUEST_LATENCY.labels(method=method, path=path).observe(duration)
if response.status_code >= 400:
ERROR_COUNT.labels(method=method, path=path, status_code=status_code).inc()
IN_PROGRESS.dec()
return response
@app.get("/health")
def health():
return {"status": "ok"}
@app.get("/metrics")
def metrics():
return Response(generate_latest(), media_type=CONTENT_TYPE_LATEST)
@app.get("/api/sample")
def sample():
time.sleep(0.05)
return {"message": "hello"}
실행 방법
uvicorn main:app --reload
FastAPI에서 핵심 감각
여기서 중요한 건 미들웨어에서 공통 메트릭을 기록한다는 점입니다.
FastAPI 공식 문서가 말하는 미들웨어 구조가 이런 관측 기능과 정말 잘 맞아요. 요청 전후 시간을 재고, status code를 보고, 공통 카운터를 올리는 식이 자연스럽습니다. (FastAPI)
그리고 Counter, Gauge, Histogram의 역할을 나눠 두면 나중에 Prometheus나 Grafana로 넘기기 쉬워집니다.
솔직히 FastAPI에서 처음부터 거대한 observability stack을 붙이기보다, 이 정도부터 시작하는 게 훨씬 현실적입니다.
2) Spring Boot에서 Actuator와 Prometheus 붙이기
Spring Boot는 이 파트가 정말 강합니다. 공식 문서도 production-ready features로 health와 metrics를 제공한다고 설명하고, actuator endpoints를 통해 애플리케이션을 모니터링하고 상호작용할 수 있다고 설명합니다. health endpoint는 기본 health 정보를 제공하고, Prometheus용 /actuator/prometheus endpoint도 제공합니다. (Home)
build.gradle
plugins {
id 'java'
id 'org.springframework.boot' version '4.0.3'
id 'io.spring.dependency-management' version '1.1.7'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'io.micrometer:micrometer-registry-prometheus'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
application.yml
spring:
application:
name: backend-series-monitoring
management:
endpoints:
web:
exposure:
include: health,metrics,prometheus
endpoint:
health:
show-details: always
Spring Boot 문서는 /actuator/prometheus endpoint가 기본적으로 노출되지 않으므로 expose 설정이 필요하다고 설명합니다. 또한 metrics endpoint는 현재 등록된 메트릭을 확인하는 진단용 endpoint라고 설명합니다. (Home)
간단한 커스텀 메트릭 예제
// DemoController.java
package com.example.backend.controller;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api")
public class DemoController {
private final Counter sampleCounter;
public DemoController(MeterRegistry registry) {
this.sampleCounter = Counter.builder("sample_requests_total")
.description("Number of sample endpoint calls")
.register(registry);
}
@GetMapping("/health-check-sample")
public Object sample() {
sampleCounter.increment();
return java.util.Map.of("message", "hello");
}
}
실행 후 확인
/actuator/health
/actuator/metrics
/actuator/prometheus
Spring Boot에서 핵심 감각
Spring Boot는 여기서 정말 편해요.
- health는 거의 바로 시작 가능
- metrics도 내장
- Prometheus endpoint도 공식 지원
- Micrometer로 커스텀 메트릭 추가도 쉬움
즉 Spring Boot는 “백엔드 모니터링 어디서부터 시작할까”라는 질문에 가장 대답이 잘 되어 있는 프레임워크 중 하나입니다.
처음 운영 붙일 때 이 점이 꽤 크게 느껴집니다.
3) Node.js에서 prom-client로 시작하기
Node.js에선 prom-client가 가장 흔한 출발점 중 하나입니다. GitHub README도 Node.js용 Prometheus client라고 설명하고, histogram, summary, gauge, counter를 지원한다고 말합니다. 또 collectDefaultMetrics()로 Prometheus가 권장하는 기본 메트릭과 Node.js-specific 메트릭을 함께 수집할 수 있다고 설명합니다. 메트릭 노출은 await registry.metrics() 결과를 scrape 요청에 응답하면 된다고도 나옵니다. (GitHub)
설치 방법
npm install express prom-client
예제 코드
// server.js
import express from "express";
import client from "prom-client";
const app = express();
app.use(express.json());
const register = new client.Registry();
client.collectDefaultMetrics({ register });
const requestCount = new client.Counter({
name: "http_requests_total",
help: "Total number of HTTP requests",
labelNames: ["method", "path", "status_code"],
registers: [register],
});
const errorCount = new client.Counter({
name: "http_errors_total",
help: "Total number of HTTP error responses",
labelNames: ["method", "path", "status_code"],
registers: [register],
});
const inProgress = new client.Gauge({
name: "http_requests_in_progress",
help: "Number of HTTP requests currently in progress",
registers: [register],
});
const requestDuration = new client.Histogram({
name: "http_request_duration_seconds",
help: "HTTP request latency in seconds",
labelNames: ["method", "path"],
buckets: [0.01, 0.05, 0.1, 0.3, 0.5, 1, 2],
registers: [register],
});
app.use((req, res, next) => {
const end = requestDuration.startTimer({
method: req.method,
path: req.path,
});
inProgress.inc();
res.on("finish", () => {
const statusCode = String(res.statusCode);
requestCount.inc({
method: req.method,
path: req.path,
status_code: statusCode,
});
if (res.statusCode >= 400) {
errorCount.inc({
method: req.method,
path: req.path,
status_code: statusCode,
});
}
inProgress.dec();
end();
});
next();
});
app.get("/health", (req, res) => {
res.json({ status: "ok" });
});
app.get("/metrics", async (req, res) => {
res.set("Content-Type", register.contentType);
res.end(await register.metrics());
});
app.get("/api/sample", async (req, res) => {
await new Promise((resolve) => setTimeout(resolve, 50));
res.json({ message: "hello" });
});
app.listen(3000, () => {
console.log("server running on http://localhost:3000");
});
Node.js에서 핵심 감각
prom-client의 장점은 정말 명확합니다.
- Counter, Gauge, Histogram을 바로 만들 수 있고
- collectDefaultMetrics()로 Node.js 기본 메트릭도 얻고
- /metrics에 바로 노출할 수 있어요
특히 공식 README가 말하듯, 웹 프레임워크와 강하게 묶여 있지 않아서 Express에도 붙이기 쉽습니다. 그리고 default metrics는 scrape 시점에 수집된다고 설명하는 점도 기억해둘 만합니다. (GitHub)
/health는 얼마나 자세해야 할까
이건 꽤 중요합니다.
초반엔 보통 이런 정도면 충분합니다.
{"status":"ok"}
그런데 운영으로 가면 보통 이런 질문이 생깁니다.
- DB 연결 가능한가?
- Redis 연결 가능한가?
- 외부 API는 살아 있나?
그래서 health도 보통 두 단계로 나눕니다.
Liveness
프로세스가 살아 있나
Readiness
지금 트래픽을 받아도 되나
Spring Boot Actuator health는 기본적으로 health 정보를 주고, 세부 정보 노출도 설정할 수 있습니다. FastAPI와 Node.js는 이 구분을 직접 설계하는 경우가 많아요. (Home)
즉 /health 하나로 시작해도 되지만, 나중엔 /health/live, /health/ready처럼 분리하는 게 운영상 더 좋을 수 있습니다.
메트릭 이름은 어떻게 지어야 할까
이건 별거 아닌 것 같아도 중요합니다.
Prometheus 쪽에서는 metric naming guidance를 따르는 편이 좋고, prom-client README도 공식 naming guidance를 참고하라고 안내합니다. (GitHub)
초반엔 이 정도 원칙이면 충분합니다.
- http_requests_total
- http_request_duration_seconds
- job_processed_total
- job_in_progress
- external_api_errors_total
즉 이름만 봐도 뭐를 재는지 바로 알 수 있어야 합니다.
실무에서 자주 하는 실수
1. /health만 있고 메트릭이 없음
그러면 “살아 있다”만 알지, “느린지/에러가 많은지”는 모릅니다.
2. 평균 응답 시간만 봄
평균은 멀쩡해도 tail latency가 나쁠 수 있습니다. Histogram이 더 현실적이에요. Prometheus도 Histogram을 관측값 분포용으로 설명합니다. (Prometheus)
3. Counter로 현재값을 표현함
Prometheus 공식 문서가 말하듯, 감소할 수 있는 값을 Counter로 쓰면 안 됩니다. 그런 값은 Gauge가 맞습니다. (Prometheus)
4. /metrics를 열어두고도 아무도 수집 안 함
애플리케이션이 메트릭을 노출하는 것과, Prometheus가 실제로 scrape하는 건 다른 일입니다.
5. path label을 너무 세밀하게 넣음
예: /users/123, /users/124처럼 동적 path를 그대로 라벨에 넣으면 cardinality가 나빠질 수 있습니다.
초반엔 라벨 수를 너무 늘리지 않는 습관이 좋습니다.
실무에서 주의할 점
1. 로그, 헬스체크, 메트릭은 같이 봐야 합니다
이 셋은 대체재가 아닙니다.
- 로그: 왜 실패했는지
- 헬스체크: 살아 있는지
- 메트릭: 얼마나 느리고 실패하는지
2. Prometheus scrape endpoint와 사용자용 진단 endpoint를 구분하세요
Spring Boot도 metrics endpoint는 진단용이고, production metrics backend로 scrape용은 /actuator/prometheus를 쓰라고 설명합니다. (Home)
3. 메트릭은 처음부터 많이 말고, 중요한 것부터
초반엔
- 요청 수
- 에러 수
- 응답 시간
- 진행 중 요청 수
이 정도면 충분합니다.
4. 헬스체크는 너무 무겁게 만들지 마세요
health endpoint가 느리거나 불안정하면 오히려 배포/오토스케일링 때 발목을 잡습니다.
5. 검색 가능한 개발 글처럼, 검색 가능한 운영 데이터가 중요합니다
AI 검색 최적화 글이 명확한 질문과 구조를 강조하듯, 운영도 명확한 metric name과 label 구조가 중요합니다.
FAQ
Q. 백엔드 모니터링은 무조건 Prometheus까지 붙여야 하나요?
처음부터 꼭 그럴 필요는 없습니다. 먼저 /health와 기본 메트릭부터 만들고, 필요할 때 Prometheus scrape 구조를 붙여도 충분합니다. 다만 Spring Boot는 /actuator/prometheus를 공식 지원해서 시작이 꽤 쉽습니다. (Home)
Q. FastAPI에는 Spring Boot Actuator 같은 게 있나요?
Spring Boot처럼 강한 내장 actuator 느낌은 아니고, 보통 미들웨어와 별도 endpoint로 직접 health/metrics를 만드는 편입니다. FastAPI는 미들웨어로 요청 전후 공통 처리를 넣기 쉽게 설계되어 있습니다. (FastAPI)
Q. Node.js에서는 뭘 먼저 붙이면 좋나요?
prom-client로 collectDefaultMetrics()를 켜고, /health, /metrics, 요청 수/응답 시간 메트릭부터 붙이는 게 가장 무난합니다. prom-client README도 기본 메트릭과 커스텀 메트릭 노출 방식을 잘 설명합니다. (GitHub)
Q. Histogram이 꼭 필요한가요?
응답 시간처럼 분포가 중요한 값에는 강력 추천입니다. 평균만 보면 놓치는 지연 문제가 많기 때문입니다. Prometheus도 Histogram을 관측값 분포용 메트릭으로 설명합니다. (Prometheus)
Q. /health와 /metrics를 같은 것으로 봐도 되나요?
아니요. /health는 생존/준비 상태 확인이고, /metrics는 시계열 수치 노출입니다. Spring Boot 문서도 health endpoint와 metrics/prometheus endpoint를 구분해서 설명합니다. (Home)
핵심 요약
- 로그만으로는 운영 상태를 충분히 보기 어렵습니다.
- 최소한 /health, 요청 수 Counter, 에러 수 Counter, 응답 시간 Histogram 정도는 붙이는 게 좋습니다. (Prometheus)
- FastAPI는 미들웨어 기반으로 시작하기 좋고, Spring Boot는 Actuator가 정말 강합니다. Node.js는 prom-client가 가장 현실적인 출발점입니다. (FastAPI)
- Prometheus는 시계열 메트릭 수집과 질의에 강하고, Spring Boot는 /actuator/prometheus를 공식 제공합니다. (Prometheus)
- 검색에 잘 걸리는 개발 글처럼, 운영에서도 명확한 metric name과 구조가 중요합니다.
출처
- FastAPI 공식 문서 — Middleware. (FastAPI)
- Spring Boot 공식 문서 — Production-ready Features / Actuator. (Home)
- Spring Boot 공식 문서 — Metrics / Prometheus endpoint. (Home)
- Prometheus 공식 문서 — Metric types. (Prometheus)
- Prometheus 공식 사이트 / GitHub. (Prometheus)
- prom-client 공식 GitHub README. (GitHub)
- 글 구성 참고: 업로드하신 “AI 검색에 잘 걸리는 글” 가이드.
백엔드개발, FastAPI, SpringBoot, Nodejs, Express, 모니터링, 헬스체크, Prometheus, 메트릭, 백엔드시리즈
'study > 백엔드' 카테고리의 다른 글
- Total
- Today
- Yesterday
- NestJS
- LangChain
- Prisma
- kotlin
- fastapi
- 생성형AI
- CI/CD
- seo 최적화 10개
- Next.js
- nextJS
- nodejs
- 웹개발
- DevOps
- flax
- 백엔드개발
- Express
- 개발블로그
- llm
- SpringBoot
- SEO최적화
- REACT
- node.js
- PostgreSQL
- 딥러닝
- 쿠버네티스
- JWT
- 주니어개발자
- Python
- JAX
- rag
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 |
