없는 로그는 이벤트가 아닙니다 — 서버 다운을 잡으려고 10분 카운트를 붙였습니다
관제 화면에 알람이 하나도 안 뜨는 날은 두 가지 중 하나입니다. 정말 아무 일도 없었거나, 알람을 보내야 할 쪽이 죽어서 아무것도 못 보내고 있거나입니다. 두 상황은 화면에서 똑같이 보입니다. 조용한 화면을 정상으로 읽는 순간, 감지 체계는 가장 큰 장애를 놓칩니다.
인프라 운영 쪽 한 시스템에 트래픽 급감 감지를 붙인 기록입니다. 결론부터 적으면, 침묵은 이벤트 기반 감지로는 원리적으로 잡히지 않습니다. 그래서 주기 카운트라는 다른 축을 하나 더 두었습니다.
에러 감지를 강화해도 서버 다운은 안 잡힙니다
그 시스템에는 앱 로그의 에러 감지가 이미 붙어 있었습니다. 특정 레벨과 키워드가 들어온 로그를 잡아 알람 인박스로 넘기는 구조였고, 실제로 많은 장애를 이 경로로 잡았습니다. 감지 품질을 올리는 작업도 줄곧 이 축 위에서 해왔습니다.
문제는 이 감지가 전부 로그가 온다는 전제 위에 서 있다는 점이었습니다. 서버가 통째로 내려가면 에러 로그조차 남지 않습니다. 반응할 이벤트가 아예 생기지 않으니, 이벤트 기반 규칙을 아무리 정교하게 다듬어도 이 구간은 계속 비어 있습니다.
더 곤란한 쪽은 여러 호스트가 같은 시스템 로그를 만드는 구성에서 한 대만 죽는 경우였습니다. 나머지 호스트가 계속 로그를 보내니 수집 파이프라인은 평소와 같아 보입니다. 처리량은 절반으로 떨어졌는데 화면은 조용합니다.

세 가지 선택지를 놓고 봤습니다
방식 | 잡히는 것 | 못 잡는 것 |
|---|---|---|
이벤트 기반 감지 | 에러 로그, 이상 패턴 | 침묵 — 원리적으로 불가 |
헬스체크 핑 | 프로세스 생존 여부 | 살아 있는데 일을 안 하는 상태 |
주기 카운트 + 기대 밴드 | 급증·급감·부분 장애 | 시간대별로 크게 출렁이는 패턴 |
헬스체크 핑을 꽤 오래 검토했습니다. 붙이기 쉽고 결과도 명확합니다. 다만 프로세스는 떠 있는데 업스트림 연결이 끊겨 아무 일도 안 하는 상태는 핑으로 안 보입니다. 알고 싶었던 것은 죽었는지가 아니라 평소만큼 일하고 있는지였습니다.
그래서 주기 카운트에 기대 밴드를 얹는 방식을 골랐습니다. 정해진 구간마다 로그 건수를 세고, 미리 정한 하한과 상한 사이에 있는지를 봅니다. 급증도 급감도 같은 룰 체계로 잡히고, 완전한 침묵은 카운트 0으로 또렷하게 드러납니다.
룰은 필터·윈도우·밴드 세 조각입니다
필터: 로그 레벨과 키워드 부분일치를 AND 로 묶어 셀 대상을 좁힙니다
윈도우: 10분 배수로 집계 구간을 잡습니다. 이 길이가 곧 감지 지연의 하한이 됩니다
밴드: 하한과 상한을 둡니다. 상한 초과는 급증, 하한 미달은 급감 신호입니다
룰은 코드가 아니라 데이터로 관리했습니다. 테이블에 넣고 화면에서 등록·수정합니다. 감지 대상이 하나 늘 때마다 배포가 필요하면 결국 아무도 룰을 늘리지 않게 됩니다. 운영 중에 밴드를 조정할 여지도 남겨둬야 했습니다.
밴드 값은 감으로 정하지 않았습니다. 실제 볼륨을 관측해 호스트당 10분에 37건 안팎이라는 기준선을 먼저 잡았고, 거기에 여유를 둬서 하한 20·상한 60으로 넣었습니다. 기준선 없이 정한 밴드는 오탐이나 미탐 중 한쪽으로 반드시 기웁니다.
진행 중인 윈도우를 세면 항상 급감으로 보입니다
구현에서 가장 먼저 걸린 함정입니다. 10분 주기 잡이 돌 때 지금 진행 중인 구간을 세면, 그 구간은 아직 다 안 쌓인 상태입니다. 그러니 늘 하한에 못 미칩니다. 우연히 나는 버그가 아니라 구조적으로 그렇게 되는 오탐입니다.
그래서 판정 대상을 막 닫힌 직전 윈도우로 고정했습니다. 감지가 최악의 경우 20분 가까이 늦어지는 대가를 치르지만, 매 주기 거짓 급감 알람이 쌓이는 것보다는 낫다고 봤습니다. 감지 체계에서 오탐은 곧 알람에 대한 신뢰를 깎는 비용입니다.

합산 카운트는 한 대의 죽음을 가립니다
호스트 경로가 등록된 시스템은 룰 하나가 각 호스트별로 따로 평가되게 했습니다. 룰은 하나인데 평가는 호스트 수만큼 펼쳐집니다. 이 한 줄이 이번 작업의 핵심이었습니다.
합산으로 보면 무슨 일이 생기는지가 분명합니다. 두 대가 각각 37건이면 합산은 74건 근처이고, 밴드도 그 근처에 잡히게 됩니다. 한 대가 죽어 37건이 되면 하한에 걸릴 수도 있고 아닐 수도 있습니다.
그 시각 트래픽이 조금만 올라와 있었으면 살아남은 한 대가 하한을 채워버립니다. 호스트별로 펼쳐 평가하면 죽은 쪽은 0건이라 판정이 흔들릴 여지가 없습니다. 알람 제목과 dedup 키에도 호스트를 넣어, 어느 대가 조용한지가 알람 한 줄에 드러나게 했습니다.
같은 침묵이 매 주기 새 알람으로 쌓이지 않도록 안정적인 키로 묶었습니다. 죽은 호스트는 복구될 때까지 계속 하한 미달이니, 묶지 않으면 10분마다 같은 알람이 하나씩 늘어납니다. 알람이 많아지면 사람은 알람을 안 봅니다.
검증은 로컬에서 호스트 하나를 실제로 정지시켜 확인했습니다. 그 호스트만 급감으로 감지되고 나머지 호스트는 조용했습니다. 합산 평가였다면 이 시나리오에서 아무 알람도 안 떴을 것입니다.

룰만 앞서가면 구버전 코드가 오탐을 만듭니다
배포 도중에 오탐이 한 번 났습니다. 서버가 아직 호스트 구분을 모르는 구버전 코드로 돌던 기간에, 호스트 구분 없는 전체 급증 알람이 떴습니다. 룰 데이터는 새 모델로 들어가 있었고 판정 코드는 옛 모델이었습니다.
감지 시스템은 룰이 데이터에 있고 판정이 코드에 있어서 이 어긋남이 생깁니다. 룰을 화면에서 자유롭게 고칠 수 있게 만든 대가이기도 합니다. 이후로는 룰 데이터 변경과 감지 코드 배포를 한 세트로 묶어 나가는 것으로 정리했습니다.
다른 시스템으로 옮겨 쓸 수 있는 부분
안 오는 신호는 오는 신호와 다른 감지 축이 필요합니다. 이벤트 기반을 아무리 강화해도 침묵은 그 축에 안 들어옵니다
미완성 집계 구간은 언제나 부족해 보입니다. 판정 대상은 닫힌 구간으로 고정하는 편이 안전합니다
집계 단위가 감지 해상도를 정합니다. 장애가 실제로 발생하는 단위인 호스트·파티션·큐로 룰을 펼쳐야 부분 장애가 평균에 안 묻힙니다
살아서 조용한 것과 죽어서 조용한 것을 가르려면 실측 기준선이 필요합니다. 밴드는 관측값에서 나옵니다
도입 전에 확인한 것들
지금 감지 체계가 이벤트가 온다는 전제 위에서만 동작하는지
시스템이 몇 개 단위로 나뉘어 돌고, 하나만 죽었을 때 나머지가 그것을 가려주는지
정상일 때의 기대 볼륨을 숫자로 말할 수 있는지. 없으면 밴드의 근거도 없습니다
감지 지연을 얼마까지 허용할 수 있는지. 이 답이 윈도우 길이를 정합니다
감지 룰 변경과 감지 코드 배포가 같이 나가는 절차인지
마무리
남은 한계도 적어둡니다. 고정 밴드는 트래픽이 시간대·요일로 크게 출렁이는 시스템에서 오탐과 미탐을 동시에 만듭니다. 그런 시스템은 시간대별 밴드나 이동 기준선으로 넘어가는 편이 맞습니다.
윈도우가 길수록 감지는 늦습니다. 10분 윈도우면 최악의 경우 20분 가까이 걸리고, 그 지연이 곤란한 시스템은 짧은 윈도우와 높아진 오탐 비용 사이에서 선을 정하는 수밖에 없습니다.
호스트 단위 평가는 호스트 목록이 관리된다는 전제 위에 서 있습니다. 오토스케일 환경이면 목록 동기화가 별도 과제로 남습니다.
감지 체계를 점검할 때 이제는 화면에 뜬 알람을 먼저 보지 않습니다. 이 체계가 무엇을 못 보는지를 먼저 적어봅니다. 침묵은 그 목록의 맨 위에 있었습니다.