새벽 3시에 울리는 Page는 “시스템에서 이상을 발견했다”는 통지가 아니다. 지금 사람이 개입하지 않으면 사용자 피해가 커지고 호출받은 사람이 실제로 상황을 개선할 수 있다는 요청이어야 한다.
그래서 CPU 사용률 80%, 메모리 90% 같은 숫자만으로 Page를 설계하면 문제가 생긴다. 같은 CPU 90%라도 충분한 여유 용량과 자동 확장이 작동하고 사용자는 아무 문제를 겪지 않을 수 있다. 반대로 CPU는 평범해 보여도 결제나 로그인 같은 중요한 사용자 흐름이 실패하고 있을 수 있다.
사람에게 알릴지를 결정하려면 먼저 “얼마나 이상한가”가 아니라 세 가지를 물어야 한다.
사용자가 실제로 피해를 받고 있는가. 그 피해는 얼마나 빨리 커지는가. 지금 사람이 할 수 있는 일이 있는가.
Google SRE도 Pager를 사람의 시간을 비싸게 사용하는 수단으로 보고 긴급하고 행동 가능하며 현재 또는 임박한 사용자 영향이 있는지를 Page 설계의 주요 질문으로 제시한다.
Page, Ticket, Dashboard는 우선순위 이름이 아니다
경보를 critical, warning, info로 나누는 것만으로는 실제 운영 방식이 정해지지 않는다. 더 유용한 구분은 사람이 언제 행동해야 하는가다.
Google SRE가 제시하는 구분도 이와 가깝다. 어떤 상황은 사람이 즉시 행동해야 하고 어떤 상황은 사람이 처리해야 하지만 며칠의 여유가 있으며 나머지는 나중의 진단을 위해 기록만 하면 된다.
이 글에서는 이를 세 가지 운영 경로로 정리한다.
| 경로 | 의미 | 사람에게 요구하는 것 |
|---|---|---|
| Page | 현재 또는 임박한 피해를 줄이려면 즉시 개입 필요 | 하던 일을 중단하고 대응 |
| Ticket / Work Queue | 사람이 해결해야 하지만 즉시 개입할 필요는 없음 | 정해진 업무 시간·기한 안에 처리 |
| Dashboard / Record Only | 현재 별도의 인간 행동을 요구하지 않음 | 조사나 추세 분석 때 참고 |
여기서 중요한 것은 Severity와 Route를 구분하는 것이다. 문제가 기술적으로 심각해 보여도 사람이 지금 할 수 있는 일이 없다면 무조건 Page가 되는 것은 아니다. 반대로 현재 피해 규모가 작아도 시간이 지나면 빠르게 복구 불가능한 상태가 되고 지금만 취할 수 있는 완화 조치가 있다면 Page가 될 수 있다.
Alert Routing Decision Matrix
Page 여부는 한 개의 Metric으로 결정하기보다 다음 조건을 함께 봐야 한다.
| 판단 축 | Page | Ticket / Work Queue | Dashboard / Record Only |
|---|---|---|---|
| User Impact | 중요한 사용자 기능에 실제 피해가 있거나 강하게 임박함 | 아직 직접 피해는 작지만 방치하면 품질·안정성 문제가 됨 | 사용자 결과에는 확인된 영향이 없음 |
| Urgency | 지금 대응해야 의미가 있음 | 다음 근무 시간이나 합의된 기한 내 대응 가능 | 대응 시점이 정해질 필요 없음 |
| Time to Harm | 대응이 늦어질수록 짧은 시간 안에 피해가 커짐 | 피해까지 충분한 준비 시간이 있음 | 현재 추세만으로 구체적인 피해 시점을 말하기 어려움 |
| Auto-recovery | 자동 복구가 없거나 실패했거나, 자동 복구 중에도 피해가 계속됨 | 자동 복구는 되지만 반복 원인을 사람이 개선해야 함 | 정상적으로 자동 복구됐고 후속 작업도 필요 없음 |
| Human Actionability | 지금 사람이 할 수 있는 완화·복구·우회·중단·에스컬레이션이 존재 | 사람이 변경·정비·분석해야 하지만 즉시 할 필요 없음 | 사람이 지금 해도 상황이 달라지지 않음 |
| Ownership | 호출받을 명확한 서비스·팀·On-call Owner가 있음 | 해결 책임자가 업무 큐에서 받을 수 있음 | 특정 담당자에게 작업을 배정할 단계가 아님 |
| Confidence / False Positive Cost | 사람을 중단시킬 만큼 충분히 신뢰할 수 있는 증거가 있음 | 불확실성이 조금 더 높아도 조사 작업으로 받을 수 있음 | 가설·이상 징후·진단용 데이터 수준 |
| Dependency | Dependency 문제라도 우리 쪽에서 즉시 완화할 행동이 있거나 해당 Dependency Owner가 바로 대응해야 함 | Dependency 저하가 있지만 우회가 작동하거나 여유 있게 조치 가능 | 원인 후보·상태 정보로만 필요 |
| Repetition / Deduplication | 현재 Incident를 대표하는 Page 하나로 묶음 | 반복되는 문제의 근본 개선 작업으로 전환 | 같은 Incident의 세부 증상은 Context로 보존 |
이 Matrix에서 Page는 사실상 AND 조건에 가깝다.
사용자 영향 또는 임박한 피해
짧은 Time to Harm
자동 복구만으로 충분하지 않음
지금 가능한 인간의 행동
명확한 Owner
Page 비용을 감수할 만큼 믿을 수 있는 신호
몇 개 조건이 빠졌다면 Page보다 Ticket이나 Dashboard가 더 적절할 가능성이 높다.
User Impact와 Time to Harm을 함께 본다
사용자 영향이 있다는 사실만으로 모든 문제가 동일하게 긴급해지는 것은 아니다.
예를 들어 다음 주에 인증서가 만료된다는 사실은 분명 해결해야 할 문제다. 하지만 충분한 시간이 있고 자동 갱신 상태를 점검할 수 있다면 일반적으로 업무 큐에서 처리할 수 있다.
반대로 저장 공간이 빠르게 고갈되고 있고 현재 증가 속도라면 다음 On-call 교대 전에 서비스 쓰기가 중단될 것으로 예상되며 자동 확장도 불가능하다면, 아직 사용자가 오류를 보지 않았더라도 Page가 정당화될 수 있다.
Google SRE 역시 Paging을 이미 발생한 사용자 증상에만 한정하지 않고 확실하게 임박한 문제도 고려한다. 다만 Page로 연결되는 규칙은 단순하고 이해 가능해야 한다고 강조한다.
따라서 disk > 80%보다 유용한 질문은 다음과 같다.
현재 증가 속도와 남은 여유를 고려하면 서비스가 위험 상태에 도달하기까지 얼마나 남았는가? 그 전에 자동 또는 예약된 조치가 가능한가?
이 차이가 고정 Threshold와 실행 가능한 Alert의 차이다.
자동으로 해결되는 문제라면 사람이 필요한 이유부터 설명해야 한다
서버 한 대가 비정상 상태가 됐지만 Load Balancer가 해당 인스턴스를 제외하고 새 인스턴스가 정상적으로 대체됐다고 하자. 사용자가 영향을 받지 않았고 추가 조치도 없다면, 해당 사건이 관측 데이터로서 가치가 있더라도 그 자체로 사람을 깨울 이유는 약하다.
문제가 반복되고 있다면 이야기가 달라진다. 매일 여러 차례 인스턴스가 죽었다 살아나지만 서비스는 자동 복구되는 경우, Page보다 원인을 제거하기 위한 Ticket이 더 적절할 수 있다.
특히 사람이 Page를 받을 때마다 같은 명령을 실행해 정상화한다면 Alert를 잘 설계한 것이 아니라 수동 자동화를 운영하고 있는 셈이다. Google SRE는 반복되는 Page의 대응이 기계적으로 정해져 있다면 그 대응을 자동화할 수 있는지 검토해야 한다고 지적한다.
자동 복구가 존재해도 Page가 필요한 경우는 있다. 자동 복구 자체가 실패했거나, 복구가 반복되는 동안 사용자가 계속 실패하거나, 자동 조치가 더 큰 장애로 번질 가능성이 있어 사람이 중단 여부를 결정해야 하는 경우다.
Page의 질문은 “자동 복구가 있는가?”가 아니라 “자동 복구만으로 현재 위험을 충분히 통제할 수 있는가?”다.
사람이 할 수 있는 일이 없다면 Page의 목적이 불분명하다
외부 서비스가 장애를 일으켰다고 가정하자.
우리 서비스에서 다른 공급자로 전환하거나, 기능을 제한하거나, 큐에 작업을 보존하거나, 트래픽을 우회하거나, 고객 영향 범위를 줄이는 행동을 할 수 있다면 담당자를 호출할 이유가 있다.
하지만 담당자가 깨어나서 외부 Status Page를 바라보는 것 외에는 할 수 있는 일이 없다면 Page 정책을 다시 검토해야 한다. 단, 장애 공지·거래 중단·업무 승인처럼 기술 복구 외의 운영 의사결정이 즉시 필요하다면 그것도 유효한 Human Action이다.
따라서 Actionability는 “엔지니어가 코드를 수정할 수 있는가”보다 넓다.
롤백, Failover, Load Shedding, 기능 비활성화, 트래픽 전환, 공급자 에스컬레이션처럼 지금 수행했을 때 피해를 줄일 수 있는 결정도 포함한다.
구체적인 Incident 대응 순서와 Runbook 구성은 별도의 Incident Response 문제다. Alert 정책은 그보다 앞에서 “지금 사람을 불러야 하는가”까지만 결정하면 된다.
Owner가 없는 Page는 경보 규칙보다 책임 구조의 문제다
#alerts 같은 공용 채널에 경보를 쌓아두고 누군가 발견하기를 기대하는 구조는 Page라고 보기 어렵다.
Page에는 최소한 서비스 또는 기능의 Owner가 있어야 하고 현재 On-call이 누구인지 시스템이 알 수 있어야 한다. 외부 Dependency가 문제라면 어느 팀이 사용자 결과에 책임지고 어느 팀이 Dependency 자체를 담당하는지도 구분해야 한다.
긴급한 서비스인데 아직 Owner가 정리되지 않았다면 중앙 On-call 같은 임시 경로로 보호할 수는 있다. 하지만 그것을 정상 운영 모델로 남겨서는 안 된다. Unowned Page는 Alerting Debt이 아니라 Ownership Debt이기 때문이다.
False Positive는 공짜가 아니다
경보 조건을 민감하게 만들면 장애를 놓칠 확률은 낮아질 수 있다. 대신 정상 상황에서도 사람을 자주 깨우게 된다.
반대로 너무 둔감하게 만들면 Page 수는 줄지만 실제 장애를 늦게 발견한다.
Google SRE Workbook은 이 문제를 Precision, Recall, Detection Time, Reset Time의 관계로 설명한다. 실제 의미 있는 사건만 얼마나 정확히 경보하는지, 놓치는 사건은 없는지, 탐지에 얼마나 걸리는지, 복구 후 얼마나 빨리 경보가 해제되는지를 함께 봐야 한다.
Page에는 특히 Precision 비용이 크다. 반복되는 False Positive는 그 한 번의 방해로 끝나지 않는다. 사람이 Pager 자체를 신뢰하지 않게 만들기 때문이다.
그렇다고 모든 Page가 완벽한 확신을 기다려야 한다는 뜻도 아니다. Time to Harm이 매우 짧고 놓쳤을 때의 피해가 크다면 낮은 지연을 위해 어느 정도 불확실성을 받아들여야 할 수 있다.
Confidence 기준도 고정 숫자보다는 다음 Trade-off로 정해야 한다.
오탐으로 사람을 깨우는 비용과, 이 문제를 몇 분 더 늦게 발견했을 때 발생할 피해 중 어느 쪽이 큰가?
Dependency 하나가 무너지면 Page 수십 개가 울려서는 안 된다
실제 장애에서는 하나의 원인이 여러 컴포넌트의 Alert를 동시에 일으키기 쉽다.
데이터베이스 연결 문제 하나가 API 오류, Queue 지연, Worker 실패, Health Check 실패, 사용자 오류율 증가로 이어질 수 있다. 이 모든 Alert가 각각 다른 Page를 만들면 사람에게는 다섯 개의 문제가 생긴 것처럼 보인다.
Prometheus Alertmanager는 이런 상황을 위해 Deduplication과 Grouping을 제공하고 상위 Alert가 활성화돼 있을 때 관련 하위 Alert의 알림을 억제하는 Inhibition도 지원한다.
다만 Dependency 그래프를 지나치게 영리하게 만드는 것도 위험하다. Google SRE는 시스템 구조가 계속 변하는 환경에서 복잡한 Dependency 기반 경보 계층을 유지하기 어렵다고 설명한다.
실무에서는 “정확한 Root Cause를 Alert 시스템이 알아내게 한다”보다 다음 목표가 현실적이다.
한 Incident가 사람에게 하나의 대표적인 Page로 보이도록 하고 나머지 컴포넌트 신호는 조사 Context로 남긴다.
경보 시스템은 진단 시스템 전체를 대신할 필요가 없다.
반복되는 Page는 Threshold를 조금 바꾸기 전에 존재 이유를 다시 묻는다
반복 Alert가 많아지면 흔히 가장 먼저 Threshold를 높인다.
CPU 80%에서 시끄러우니 90%로 바꾸고 90%에서도 시끄러우면 지속 시간을 늘리는 식이다.
일시적인 Spike나 Flapping을 줄이기 위해 일정 시간 조건이 지속됐을 때만 Alert를 활성화하거나 복구 직후 일정 시간 Firing 상태를 유지하는 기능은 실제로 유용할 수 있다. Prometheus도 for와 keep_firing_for를 이런 목적으로 제공한다.
하지만 이것은 원래 Page가 필요하다는 판단이 맞을 때의 튜닝 방법이다.
Page를 받을 때마다 아무 행동도 하지 않는다면 Threshold 문제가 아니다. Page를 받을 때마다 같은 작업을 한다면 자동화 문제일 수 있다. 한 장애가 열 개의 Page를 만들면 Grouping 문제다. 다른 팀이 이미 대응 중이라면 Routing이나 Inhibition 문제다.
조건식을 정교하게 만드는 것보다 Page의 존재 이유를 먼저 검토해야 한다.
고정 CPU 80%, Memory 90%가 좋은 출발점이 아닌 이유
CPU와 메모리 사용률이 필요 없다는 뜻은 아니다. 이런 자원 지표는 장애 원인을 설명하거나 Saturation이 임박했는지 판단하는 데 중요한 자료다.
문제는 자원 사용률 자체가 사용자 피해와 1:1로 대응하지 않는다는 데 있다.
다음 두 상황을 비교해보자.
| 상황 | 더 적절한 Route |
|---|---|
| CPU가 높지만 자동 확장이 정상 작동하고 사용자 지연·실패가 없으며 여유 용량도 충분함 | Dashboard / Record |
| 자원 포화가 진행 중이고 자동 확장이 실패했으며 현재 속도라면 중요한 사용자 기능이 곧 영향을 받고 On-call이 용량·트래픽을 조정할 수 있음 | Page |
같은 CPU 숫자가 다른 결과를 만든다.
그래서 임계값은 “몇 %가 위험한가”가 아니라 어떤 조건에서 이 값이 실제 사용자 피해로 이어지고 그 전에 사람이 해야 할 일이 무엇인가를 검증한 뒤 정해야 한다.
Prometheus 역시 가능한 한 개별 원인을 모두 Alert로 만들기보다 사용자 고통과 연결된 증상을 상위 계층에서 Alert하고 작은 흔들림에는 여유를 둘 것을 권고한다.
몇 가지 상황을 실제로 분류해보면
| 상황 | Route | 이유 |
|---|---|---|
| 구매 완료 실패가 실제 사용자에게 발생하고 있으며 자동 Rollback이 실패했다. On-call이 이전 버전 전환으로 피해를 줄일 수 있다. | Page | 사용자 영향 + 짧은 Time to Harm + 즉시 행동 가능 |
| 인증서 만료가 충분히 앞서 탐지됐고 담당자가 업무 시간에 갱신 상태를 수정할 수 있다. | Ticket | 행동은 필요하지만 즉시 개입할 이유 없음 |
| 인스턴스 하나가 재시작됐지만 트래픽은 정상 노드로 이동했고 자동 대체됐으며 사용자 영향이 없다. | Dashboard / Record | 현재 필요한 인간 행동 없음 |
| Worker가 매일 자동 재시작해 서비스 영향 없이 복구되지만 같은 문제가 반복된다. | Ticket | 새벽 Page보다 반복 원인 제거 작업이 필요 |
| 외부 Dependency 응답이 나빠졌지만 Fallback이 정상 작동하고 사용자 성공률에는 영향이 없다. | Dashboard 또는 Ticket | 원인 Context는 필요하지만 즉시 Page할 사용자 피해가 없음 |
| 용량 소진이 임박했고 자동 확장도 불가능하며 다음 근무 시간 전에 서비스 중단이 예상된다. | Page | 아직 장애 전이어도 Time to Harm이 짧고 사람이 예방할 수 있음 |
이 표에서 볼 수 있듯 Route를 결정하는 것은 Metric의 종류가 아니라 피해와 행동 사이의 시간 관계다.
Page에는 최소한 무엇이 들어 있어야 할까
Page를 받은 사람이 다시 처음부터 상황을 해석해야 한다면 Alert 시스템이 해야 할 일을 사람에게 넘긴 것이다.
좋은 Page에는 적어도 영향받는 서비스나 사용자 기능, 문제가 시작된 시점과 범위, 현재 담당자, 최초 대응을 위한 Runbook 또는 확인 지점, 관련 Dashboard, 같은 Incident를 묶기 위한 식별 정보가 있어야 한다.
Prometheus Alerting Rule도 Alert annotation에 설명이나 Runbook 링크 같은 추가 정보를 넣을 수 있도록 한다.
여기서 Alert가 Root Cause를 확정할 필요는 없다. “결제 실패율이 올라갔고 어떤 데이터베이스가 원인이다”까지 Alert가 추론하려다 보면 규칙이 지나치게 복잡해질 수 있다.
Page가 확실히 말해야 하는 것은 더 단순하다.
무엇이 영향을 받고 있으며 왜 지금 사람이 필요하고 누가 응답해야 하는가.
운영 중인 Alert도 계속 재분류해야 한다
처음에는 충분히 가치 있던 Page가 시간이 지나면서 불필요해질 수 있다.
자동 복구가 추가될 수도 있고 Architecture가 바뀔 수도 있고 문제 자체가 흔해져 대응 방법이 완전히 정형화될 수도 있다. 반대로 Dashboard에서만 보던 신호가 실제 장애의 선행 지표라는 사실이 반복적으로 확인되면 더 높은 Route가 필요할 수도 있다.
Alert Rule Review에서는 “현재 Threshold가 맞는가?”보다 실제 발생 이력을 가지고 다음을 확인하는 편이 낫다.
Page가 울렸을 때 사람이 실제 행동했는가. 사용자 피해가 있었거나 정말 임박했는가. 사람이 확인하기 전에 이미 자동 복구된 비율은 얼마나 되는가. 같은 Incident가 여러 Page를 만들지는 않았는가. 매번 같은 수동 대응을 반복하고 있지는 않은가. 담당자가 Page를 믿고 즉시 반응하는가.
Google SRE도 Page 빈도를 개별 Alert가 아니라 On-call의 지속 가능한 운영 부하 관점에서 추적한다. 지나치게 많은 Page는 실제 문제를 조사하고 개선할 시간을 빼앗는다.
사람을 깨우기 전에 마지막으로 물을 질문
Alerting 시스템의 목적은 시스템에 생긴 모든 이상을 사람에게 전달하는 것이 아니다.
운영에 필요한 데이터는 훨씬 많이 수집해도 된다. 원인을 찾기 위한 메트릭, 로그, 트레이스, Dependency 상태도 풍부할수록 유용할 수 있다. 하지만 그 모든 신호가 사람의 수면이나 집중을 중단시킬 자격을 갖는 것은 아니다.
Page를 만들기 전에는 이 질문 하나가 남아야 한다.
이 알림을 지금 받는 사람이 실제로 무엇을 해야 하며 그 행동을 아침까지 미루면 어떤 사용자 피해가 더 커지는가?
명확한 답이 있다면 Page 후보가 된다.
행동은 필요하지만 기다릴 수 있다면 Ticket으로 보내면 된다.
아무 행동도 요구하지 않는다면 Dashboard나 기록으로 남기는 편이 낫다.
경보의 품질은 얼마나 많은 이상을 발견하느냐보다, 정말 사람이 필요할 때 사람을 부를 수 있느냐에서 드러난다.