대시보드와 경보 설계
RED·USE·업무 메트릭을 계층 대시보드로 구성하고 SLI·SLO·오류 예산·다중 구간 소진율 경보·데이터 없음·배포 애노테이션·대응 절차·로그·트레이스 연계를 통해 대응 가능한 모니터링을 완성합니다.
메트릭을 많이 수집하는 것과 장애를 빨리 발견하는 것은 다릅니다. 대시보드가 JVM 차트 수십 개를 나열하고 경보가 CPU 80%마다 울리면 사용자가 실패하는 순간을 놓칠 수 있습니다. 먼저 서비스의 요청 성공·지연 시간·트래픽 같은 증상을 보고, 리소스와 의존성으로 좁힌 뒤, 로그와 트레이스에서 개별 원인을 확인하는 계층을 만듭니다.
첫 대시보드 화면
RED는 요청 비율, 오류, 지속 시간을 서비스 관점에서 봅니다. USE는 자원 사용률, 포화도, 오류를 CPU, 메모리, 스레드 풀, 연결 풀에 적용합니다. 회원 게시판에는 허용·거부 비율, 가져오기 대기량과 경과 시간 같은 업무 신호를 더합니다. 첫 화면은 증상, 트래픽, 포화도, 배포 버전, 수집 최신성을 제한된 수의 패널로 보여 줍니다.
평균 지연 시간만 두지 않고 p50·p95·p99 또는 SLO 버킷을 함께 봅니다. 평균 100ms는 99%가 10ms이고 1%가 9초인 상태를 숨길 수 있습니다. 요청량이 거의 없을 때 비율이 요동치는 것도 절대 개수와 함께 해석합니다.
package board.monitoring;
import java.time.Duration;
public record ServiceSnapshot(
double requestsPerSecond,
double errorRatio,
Duration p95,
int pendingEntries,
Duration oldestPendingAge,
boolean scrapeCurrent
) {
public String headline() {
if (!scrapeCurrent) return "OBSERVABILITY_STALE";
if (errorRatio > 0.02) return "USER_ERRORS_HIGH";
if (oldestPendingAge.compareTo(Duration.ofMinutes(5)) > 0) {
return "BACKLOG_AGING";
}
return "WITHIN_OBJECTIVE";
}
}이 판정은 실제 경보 엔진을 대체하지 않지만 패널이 어떤 질문에 답해야 하는지 명시합니다.
대시보드 상세 분석 흐름
서비스 개요에서 엔드포인트·영역·결과별 세부 분석으로, 다음에 인스턴스 리소스와 의존성, 마지막에 엑젬플러·트레이스·로그로 이동합니다. 패널 링크가 같은 시간 범위와 레이블 필터를 전달하면 장애 중 쿼리를 다시 입력하지 않아도 됩니다.
대시보드 변수에 사용자 ID나 무제한 경로를 넣지 않습니다. 인스턴스 변수는 오래된 파드를 포함하는지, 배포 변수는 현재 배포 버전을 반영하는지 검증합니다. 대시보드 JSON과 경보 규칙을 버전 관리하고, UI에서 수정한 내용도 검토 가능한 변경 사항으로 내보냅니다.
SLI·SLO
가용성 SLI는 정상 이벤트 수 / 유효 이벤트 수로 정의합니다.
클라이언트가 잘못 보낸 검증 4xx를 서비스 실패에 포함할지, 타임아웃과 취소를 어떻게 분류할지 제품 계약으로 정합니다.
지연 시간 SLI는 임계값 안에 완료된 요청 비율로 만들 수 있습니다.
메트릭 이름보다 집계 대상 이벤트와 정상 판정 조건이 먼저입니다.
99.9% 월 SLO는 약 0.1% 오류 예산을 허용합니다. 모든 순간 0 오류를 요구하지 않고 예산 소비 속도로 위험을 봅니다. 계획된 유지보수와 저트래픽 구간을 어떻게 처리하는지도 정책에 포함합니다.
package board.monitoring;
public record ErrorBudget(long validEvents, long badEvents, double objective) {
public ErrorBudget {
if (validEvents < 1 || badEvents < 0 || badEvents > validEvents) {
throw new IllegalArgumentException("invalid SLI counts");
}
if (objective <= 0.0 || objective >= 1.0) {
throw new IllegalArgumentException("invalid objective");
}
}
public double observedErrorRatio() {
return (double) badEvents / validEvents;
}
public double budgetFractionConsumed() {
return observedErrorRatio() / (1.0 - objective);
}
}표본 수가 너무 적을 때 1 오류가 만든 비율 경보는 최소 트래픽 조건과 함께 다룹니다.
다중 창 소진율 경보
짧은 구간의 높은 소진율은 급격한 장애를 빠르게 감지하지만 잡음이 큽니다. 긴 구간을 함께 요구하면 지속성을 확인합니다. 별도 규칙은 낮은 소진율의 장기 소비를 감지합니다. 임계값은 복사하지 말고 목표와 대응의 긴급도에서 계산하고 과거 데이터 재생으로 오탐을 검토합니다.
package board.monitoring;
public record BurnRateDecision(double shortWindow, double longWindow) {
public String severity() {
if (shortWindow >= 14.4 && longWindow >= 14.4) {
return "PAGE_FAST_BURN";
}
if (shortWindow >= 6.0 && longWindow >= 3.0) {
return "TICKET_SLOW_BURN";
}
return "NO_ALERT";
}
}실제 규칙은 서로 다른 지속 시간 구간과 최소 이벤트 개수를 사용합니다. 한 숫자 임계값만으로 페이지를 보내지 않습니다.
short-window burn=18.2
long-window burn=15.1
minimum valid events satisfied=true
result=PAGE_FAST_BURN
next=runbook/board-write-slo행동 가능한 경보
경보 애노테이션에는 영향받는 서비스·영역, 현재 SLI, 시작 시각, 대시보드와 대응 절차 링크, 최근 배포, 담당 팀을 넣습니다. “CPU 높음” 대신 “회원 게시판 쓰기 SLO 빠른 소진, 연결 풀 포화도 동반”처럼 증상과 보조 신호를 연결합니다. 원인 추측을 확정 사실처럼 쓰지 않습니다.
경고와 호출의 차이는 숫자 크기보다 즉시 사람을 깨워야 하는지에 있습니다. 자동 복구 가능한 일시적 급증은 티켓이나 대시보드 이벤트로 남기고, 사용자 영향이 지속되고 예산을 빠르게 태우는 경우 담당자를 호출합니다. 동일 근본 원인에서 나온 인스턴스 수십 개의 경보는 서비스 수준으로 묶고 중복 알림을 억제합니다.
배포 변화·수집 공백 표시
릴리스 버전, 기능 플래그, 데이터베이스 마이그레이션, 자동 확장 이벤트를 애노테이션으로 표시하면 변화 직후의 회귀를 빠르게 찾습니다. 그러나 상관관계가 원인을 증명하지는 않으므로 비교 집단과 트레이스를 확인합니다.
데이터 없음은 정상적인 0과 분리합니다. Prometheus 수집 대상 중단, 쿼리 오류, 메트릭 전송 구성 요소 실패, 트래픽 없음은 각각 다른 상태 패널로 표시합니다. 경보 규칙 자체의 평가 실패와 알림 전달 실패도 별도로 감시합니다.
SLI query empty + target up=0 -> SCRAPE_FAILURE, not zero errors
alert rule evaluation error -> RULE_ENGINE_FAILURE
alert firing + notification attempts=0 -> ROUTING_CONFIGURATION_MISSING
notification rejected by receiver -> DELIVERY_FAILED
dashboard current + deployment marker absent -> RELEASE_METADATA_GAP메트릭·로그·트레이스 연결
메트릭은 전체 추세, 트레이스는 한 요청의 서비스 스팬, 로그는 가장 세부적인 애플리케이션 이벤트를 제공합니다. 엑젬플러나 트레이스 ID 링크로 높은 지연 시간 버킷에서 트레이스로 이동하고, MDC 상관관계 ID로 관련 로그를 찾습니다. 트레이스 ID를 메트릭 태그로 넣어 카디널리티를 폭발시키지 않습니다.
일반 로그와 오류 로그의 저장·검색 정책을 분리할 수 있지만 같은 장애 타임라인에서 함께 조회할 수 있어야 합니다. 민감한 페이로드는 어느 관측 도구에도 기본 수집하지 않습니다. 표본 추출 때문에 트레이스가 없을 수 있으므로 꼬리 표본 추출과 오류 보존 기간 정책을 정합니다.
연습 문제
회원 게시판 개요에 요청 비율, 오류 비율, p95, 대기량 경과 시간, 풀 포화도, 수집 최신성, 현재 버전을 배치하세요. 99.9% 가용성 SLO의 빠른/느린 소진율 규칙과 최소 트래픽 조건을 만들고 대상 중단·규칙 실패·알림 실패를 각각 다른 상위 경보로 검증하세요.
해설 보기
패널 목록보다 위에서 아래로 답할 질문을 먼저 씁니다. 페이지에는 사용자 영향과 즉시 실행할 대응 절차가 있어야 합니다.
package board.monitoring;
public record AlertEnvelope(
String service,
String severity,
String symptom,
String runbook,
String owner
) {
public AlertEnvelope {
if (service.isBlank() || severity.isBlank() || symptom.isBlank()
|| runbook.isBlank() || owner.isBlank()) {
throw new IllegalArgumentException("alert must be actionable");
}
}
}경보를 추가한 뒤 과거 트래픽으로 재생하고 실제 장애 종료 후 임계값과 대응 절차를 회고합니다.