SLO를 도입하고 나면 대부분 다음 관문에서 걸린다. "그래서 알림을 어떻게 쏘지?"
에러 예산이 30일 기준으로 계산되니까 30일치를 보고 알림을 쏘면 너무 느리고, 5분만 보고 쏘면 배포 중 살짝 튀는 것에도 오작동한다. Google SRE 워크북에 있는 "multi-window multi-burn-rate" 패턴을 그대로 갖다 쓰긴 하는데, 이게 왜 이 조합인지, 내부에서 무슨 일이 벌어지는지는 대충 넘어가는 경우가 많다. 우리 팀도 그러다. 최근에 알림 튜닝을 다시 하면서 정리한 내용을 풀어본다.
번-레이트라는 지표가 사실은 뭘 계산하는가
번-레이트(burn rate)는 이름이 살짝 오해를 부른다. "얼마나 빨리 타고 있냐"인데, 기준선이 뭔지가 모호하다. 정확히는 이거다.
번-레이트 = (관측 윈도우의 실측 에러율) / (SLO가 허용하는 에러율)
SLO가 99.9% 가용성이면 허용 에러율은 0.1%다. 최근 5분간 실측 에러율이 1%면 번-레이트는 10이다. 즉 SLO가 허용하는 속도의 10배로 예산을 태우고 있다는 뜻. 이 속도가 유지되면 30일 예산(43.2분)을 3일이면 다 태운다.
내부적으로 Prometheus 쿼리 예시로 보면 결국 이런 형태다.
# 5분 윈도우 번-레이트
(
sum(rate(http_requests_total{status=~"5.."}[5m]))
/
sum(rate(http_requests_total[5m]))
) / 0.001
분모의 0.001이 SLO가 허용하는 에러율(1 - 0.999). 이걸로 나눠서 배율을 뽑는다. 사실 이렇게만 봐도 감이 온다. 단일 윈도우로 쓰면 튀는 값에 그대로 노출된다. 5분 사이에 배포 실패나 카나리 롤백이 있으면 이 값이 순간적으로 50, 100까지 튄다. 그런데 실제로 SLO를 위협하는 상황은 아닐 수도 있다.
왜 하필 "긴 창 + 짧은 창" 조합인가
Google 워크북에서 권장하는 조합은 대략 이렇다.
- Fast burn: 1시간 윈도우 번-레이트 ≥ 14.4, 그리고 5분 윈도우 번-레이트 ≥ 14.4
- Slow burn: 6시간 윈도우 번-레이트 ≥ 6, 그리고 30분 윈도우 번-레이트 ≥ 6
- Very slow burn: 3일 윈도우 번-레이트 ≥ 1, 그리고 6시간 윈도우 번-레이트 ≥ 1
숫자만 보면 마법 같은데 뜯어보면 로직이 있다.
14.4는 어디서 왔냐. 30일 예산의 2%를 1시간에 태우면 나오는 배율이다. 30일 = 720시간, 그 중 2%면 14.4시간. 이 속도로 계속 태우면 2일 3시간이면 예산 다 태운다. 이 정도면 페이지 콜 해도 무방한 심각한 이탈이다.
6은 5%를 6시간에 태우는 속도. 이 페이스면 5일이면 예산 소진. 아직 급하지 않지만 근무 시간이면 티켓 열어야 한다.
1은 말 그대로 예산을 딱 맞춰 태우는 속도. 3일 연속 이 속도면 이미 10% 예산을 썼다는 뜻이라 티켓으로 열어놓고 추적한다.
여기서 짧은 창은 왜 붙였냐. 긴 창 하나만 보면 문제가 이미 끝났는데도 계속 알림이 살아있는 문제가 생긴다. 예를 들어 1시간 윈도우 번-레이트가 14.4를 넘으면, 실제 장애는 10분 만에 끝나고 복구가 됐어도 그 10분치 에러가 1시간 윈도우 안에 있는 동안 계속 조건이 참이다. 짧은 창(5분)을 AND로 걸면 "지금 이 순간에도 여전히 태우고 있냐"를 확인해준다. Google 워크북은 이걸 short window = long window / 12 로 두라고 권장한다. 왜 12냐고 물으면, 실증적으로 노이즈와 응답성의 균형점이었다는 답이 나온다. 우리도 몇 번 튜닝해봤는데 이 비율이 대체로 무난했다.
실제로 이 조합이 어떻게 작동하는지 시나리오로 보기
작년 말에 우리 팀에서 있었던 실제 케이스를 각색해서 풀어본다. API 서비스, SLO 99.9%, 30일 윈도우.
시나리오 A - 짧고 굵은 장애. 특정 배포 후 5분간 에러율이 30%까지 튐. 5분 뒤 롤백으로 정상화.
- 5분 창: 배포 순간 번-레이트 300, 롤백 후 5분 지나면 0으로 복귀
- 1시간 창: 배포 순간부터 서서히 오르다가 최대 25 정도까지 갔다가 1시간이 지나면 0으로 복귀
- Fast burn 조건(1h ≥ 14.4 AND 5m ≥ 14.4): 배포 순간부터 5분 정도만 참. 페이지 콜 한 번 나가고, 롤백 후 5m 창이 먼저 조건 이탈하면서 자동 해제
시나리오 B - 서서히 새는 장애. DB 커넥션 풀 튜닝 실수로 에러율이 0.5%로 지속. SLO 허용치가 0.1%이니 번-레이트는 5.
- 5분 창: 5로 계속 유지
- 6시간 창: 6시간이 지나면 5로 수렴
- Slow burn 조건(6h ≥ 6 AND 30m ≥ 6): 안 걸림. 번-레이트가 5라서 조건 미달
- Very slow burn(3d ≥ 1 AND 6h ≥ 1): 3일이 지나면 걸림. 3일 후에 티켓 열림
여기서 미묘한 게 나온다. 시나리오 B는 진짜 문제인데 3일이나 걸린다. 이게 별로면 slow burn 임계값을 낮춰야 하는데, 그러면 노이즈가 늘어난다. 이 트레이드오프는 서비스 성격에 따라 다르게 잡아야 한다. 우리 팀은 결제 관련은 slow burn을 3으로 낮췄고, 내부 툴 API는 그대로 6으로 뒀다. 그리고 이 임계값 조정 근거를 사후 회고에서 데이터로 남긴다. "예산을 태우는 속도 X 배가 우리에게 얼마나 위험한가"를 팀 언어로 합의해두면 다음 튜닝이 쉽다.
OpenTelemetry로 넘어가면서 바뀌는 부분
최근 6개월간 눈에 띄는 변화는 SLO 계산의 데이터 소스를 OpenTelemetry로 옮기는 팀이 늘었다는 점이다. OneUptime 같은 곳에서 올해 나온 글들이 다들 OTel 메트릭을 소스로 놓고 번-레이트 계산하는 예제를 밀고 있다. Prometheus의 rate() 함수 자체는 그대로지만, http_requests_total이 OTel semconv 기준 http.server.request.duration_count 같은 이름으로 바뀐다. 이건 그냥 라벨/이름 맞춰주면 되는 문제라 큰 이슈는 아니다.
문제는 다른 데서 온다. OTel로 넘어가면 성공/실패 판정이 span의 status_code나 otel.status_code로 옮겨진다. 우리 팀은 처음에 HTTP 5xx만 실패로 잡던 걸 그대로 옮겼는데, span status는 클라이언트 취소도 error로 잡아버리는 경우가 있어서 번-레이트가 부풀려졌다. 결국 error.type 라벨로 client_canceled 계열을 제외하는 재필터링을 추가했다. 이런 소소한 함정이 곳곳에 있어서, OTel 마이그레이션 시에는 기존 Prometheus 알림과 병렬로 한동안 굴리면서 값이 일치하는지 확인하는 게 안전하다.
사실 여기까지 정리하고 나서도 의문은 남는다. very slow burn이 3일 후에야 걸리는 게 정말 맞는가. 어떤 팀은 이걸 아예 자동 알림에서 빼고, 주간 SLO 리포트에서만 다룬다. 알림 피로가 알림 누락보다 위험한 경우가 많으니까. 우리 팀도 최근에 very slow는 알림에서 뺐고, 대신 매주 월요일 아침 브리핑 자료에 30일 번-레이트 추이 그래프를 자동으로 붙이도록 바꿨다. 이게 더 나은지는 아직 몇 달 더 지켜봐야 할 것 같다.
혹시 다른 팀에서는 어떻게 튜닝하는지 궁금하다. 특히 임계값을 서비스 별로 다르게 두는 팀이 있으면 어떻게 근거를 관리하는지 댓글로 공유해주시면 좋겠다.
'IT > SRE' 카테고리의 다른 글
| burn rate alert 튜닝하다 3주 삽질한 이야기 (0) | 2026.08.14 |
|---|---|
| 에러버짓 정책, 이렇게 굴리면 실제로 돌아간다 (0) | 2026.08.01 |
| SLO burn rate 알람, fast burn 하나만 두지 마세요 (0) | 2026.07.11 |
| SLO burn rate alert가 4시간 반 동안 안 울린 밤 (0) | 2026.07.04 |
| SLO는 깨졌는데 burn rate 알림은 안 울렸다 (0) | 2026.06.27 |