서비스 운영 대응 #헬스 체크부터 장애 분석과 보고서 작성까지

운영 대응이란?

운영 대응(Incident Response)은 서비스 운영 중 발생하는 장애를 탐지하고, 영향 범위를 파악하며, 서비스를 복구하고, 재발 방지 대책을 수립하는 일련의 과정이다.

서비스를 개발할 때는 정상적인 상황에서 기능이 동작하는지 확인하는 데 집중한다. 하지만 실제 운영 환경에서는 네트워크 단절, 데이터베이스 지연, 메모리 부족, 외부 API 장애, 트래픽 급증 등 다양한 문제가 발생한다.

이러한 상황에서 중요한 것은 단순히 오류를 수정하는 것이 아니다. 장애를 빠르게 감지하고, 원인을 정확히 파악하고, 사용자 영향을 최소화하며, 동일한 문제가 반복되지 않도록 시스템을 개선하는 것이 운영 대응의 핵심이다.

운영 대응은 다음과 같은 흐름으로 구성된다.

  • 헬스 체크를 통한 서비스 상태 확인
  • 알림 정책을 통한 이상 징후 탐지
  • 로그·메트릭·트레이스를 활용한 장애 원인 분석
  • 장애 복구와 서비스 정상화
  • 장애 보고서 작성과 재발 방지 대책 수립

이러한 체계가 갖춰져야 서비스 규모가 커지더라도 안정적인 운영이 가능하다.

헬스 체크

헬스 체크(Health Check)는 애플리케이션과 인프라가 정상적으로 동작하는지 확인하는 절차다.

프로세스가 실행 중이라는 사실만으로 서비스가 정상이라고 판단할 수는 없다. 서버 프로세스가 살아 있더라도 데이터베이스 연결이 끊겼거나, 이벤트 루프가 장시간 차단되었거나, 요청을 처리할 수 없는 상태일 수 있다.

따라서 헬스 체크는 서비스의 실제 상태를 판단할 수 있도록 목적에 따라 구분해야 한다.

Liveness Check

Liveness Check는 애플리케이션이 계속 실행될 수 있는 상태인지 확인한다.

애플리케이션이 교착 상태에 빠지거나 내부 오류로 인해 정상적인 처리가 불가능해졌다면 프로세스를 재시작하는 것이 해결책이 될 수 있다.

Kubernetes에서는 Liveness Probe를 통해 이러한 상태를 감지하고 컨테이너를 재시작할 수 있다.

다만 데이터베이스 연결 실패와 같은 외부 의존성 문제를 무조건 Liveness Check에 포함하면 안 된다. 데이터베이스가 일시적으로 장애를 겪는 동안 모든 애플리케이션 인스턴스가 반복적으로 재시작되는 상황이 발생할 수 있기 때문이다.

Liveness Check는 애플리케이션 자체의 복구 가능성을 판단하는 데 집중해야 한다.

Readiness Check

Readiness Check는 애플리케이션이 실제 요청을 처리할 준비가 되었는지 확인한다.

서버가 시작되었더라도 데이터베이스 연결 풀 초기화, 필수 설정 로딩, 캐시 초기화 등이 완료되지 않았다면 요청을 처리하기 어려울 수 있다.

Kubernetes의 Readiness Probe는 이러한 상태를 확인하고 준비되지 않은 Pod로 트래픽이 전달되지 않도록 하는 데 사용된다.

서비스가 정상적으로 복구되었을 때 다시 트래픽을 받을 수 있도록 상태 전환도 고려해야 한다.

Startup Check

Startup Check는 애플리케이션의 초기화가 완료되었는지 확인한다.

초기 데이터 로딩이나 복잡한 초기화 과정 때문에 애플리케이션이 시작되는 데 시간이 오래 걸리는 경우 유용하다.

Kubernetes의 Startup Probe를 사용하면 초기화가 완료되기 전에 Liveness Probe가 애플리케이션을 반복적으로 재시작하는 문제를 방지할 수 있다.

의존성 헬스 체크

애플리케이션 자체뿐 아니라 서비스가 의존하는 외부 시스템의 상태도 확인해야 한다.

주요 확인 대상은 다음과 같다.

  • 데이터베이스 연결 및 쿼리 수행 가능 여부
  • Redis 연결 및 기본 명령 수행 가능 여부
  • 메시지 브로커 연결 상태
  • 외부 API 응답 상태
  • 디스크 여유 공간과 메모리 사용량
  • 이벤트 루프 지연과 요청 처리 상태

다만 모든 의존성을 단일 헬스 체크에 연결하면 외부 시스템의 일시적인 장애가 전체 서비스의 장애로 확대될 수 있다.

따라서 단순 생존 여부와 실제 요청 처리 가능 여부를 분리하고, 외부 의존성 상태는 별도의 메트릭과 알림으로 관찰하는 것이 효과적이다.

알림 정책

알림 정책(Alerting Policy)은 서비스에 이상이 발생했을 때 어떤 조건으로 알림을 발생시키고, 누구에게 전달하며, 어떤 대응을 수행할지 정의하는 규칙이다.

모든 오류를 즉시 알림으로 전달하면 알림이 과도하게 발생한다. 반대로 기준이 지나치게 느슨하면 심각한 장애를 늦게 발견할 수 있다.

따라서 알림 정책은 오류의 개수가 아니라 서비스에 미치는 영향과 대응의 긴급성을 기준으로 설계해야 한다.

임계치 기반 알림

임계치 기반 알림은 특정 메트릭이 설정된 기준을 초과하거나 미달할 때 발생한다.

대표적인 대상은 다음과 같다.

  • HTTP 요청 오류율
  • 응답 지연 시간
  • CPU와 메모리 사용량
  • 데이터베이스 연결 수
  • Redis 응답 지연
  • 이벤트 루프 지연
  • 활성 WebSocket 연결 수
  • 메시지 큐 적체량

예를 들어 CPU 사용률이 높더라도 요청 지연과 오류율이 정상이라면 즉각적인 장애로 판단하지 않을 수 있다. 반대로 CPU 사용률이 높지 않더라도 요청 오류율이 급증한다면 서비스 장애로 판단해야 한다.

가능하면 인프라 자원 지표와 사용자 관점의 서비스 지표를 함께 사용해야 한다.

지속 시간 기반 알림

메트릭이 순간적으로 임계치를 초과했다고 해서 반드시 장애인 것은 아니다.

짧은 트래픽 급증이나 일시적인 작업 부하로 인해 지표가 일시적으로 상승할 수 있다. 따라서 일정 시간 동안 조건이 지속될 때 알림을 발생시키면 불필요한 알림을 줄일 수 있다.

다만 결제 실패, 인증 시스템 장애, 데이터 손실 가능성과 같이 즉각적인 대응이 필요한 이벤트는 지속 시간 조건을 최소화하거나 별도의 즉시 알림으로 처리해야 한다.

심각도에 따른 알림 분류

알림은 장애의 영향과 긴급성에 따라 분류할 수 있다.

심각도판단 기준대응 방식
Critical서비스 전체 중단, 데이터 손실 위험, 핵심 기능 사용 불가즉시 대응 및 담당자 호출
High주요 기능 장애, 오류율 급증, 심각한 성능 저하신속한 조사 및 복구
Warning자원 사용량 증가, 지연 시간 악화, 용량 부족 징후추세 확인 및 예방 조치
Info배포 완료, 복구 완료, 운영 상태 변경기록 및 상황 공유

심각도 분류는 조직의 서비스 수준 목표와 운영 체계에 맞춰 정의해야 한다.

알림 피로 방지

알림 피로(Alert Fatigue)는 불필요한 알림이 반복되어 운영자가 중요한 알림까지 무시하게 되는 현상이다.

이를 방지하려면 다음 사항을 고려해야 한다.

  • 동일한 원인에서 발생한 알림을 그룹화한다.
  • 반복 알림에 억제 시간과 재알림 조건을 설정한다.
  • 장애 발생 시 관련 알림을 연관된 사건으로 묶는다.
  • 복구되었을 때 복구 알림을 전달한다.
  • 실제 대응이 필요한 알림과 단순 관찰용 알림을 분리한다.
  • 알림마다 담당자와 대응 절차를 명시한다.

좋은 알림은 단순히 문제가 발생했다는 사실만 전달하지 않는다. 문제가 발생한 대상, 영향 범위, 관련 대시보드, 로그 검색 조건, 권장 대응 절차까지 제공해야 한다.

장애 원인 분석

장애 원인 분석(Root Cause Analysis)은 관측된 오류의 직접적인 원인과 그 배경에 있는 시스템적 문제를 찾아내는 과정이다.

장애가 발생하면 가장 먼저 눈에 보이는 오류를 수정하고 싶어질 수 있다. 하지만 최초로 관측된 오류가 반드시 근본 원인은 아니다.

예를 들어 API 요청 시간 초과가 발생했다면 다음과 같은 원인이 존재할 수 있다.

  • 데이터베이스 쿼리 성능 저하
  • 데이터베이스 연결 풀 고갈
  • 외부 API 응답 지연
  • 이벤트 루프 차단
  • 특정 요청의 과도한 연산량
  • 연결 대기열 증가
  • 잘못된 배포 설정

따라서 오류 메시지 하나만 보고 원인을 단정하지 말고, 시간의 흐름에 따라 관련 지표와 이벤트를 연결해야 한다.

장애 발생 시 초기 대응

장애가 발생하면 원인을 찾기 전에 현재 상태와 영향 범위를 파악해야 한다.

우선 확인할 항목은 다음과 같다.

  • 어떤 기능이 영향을 받고 있는가?
  • 모든 사용자에게 발생하는가, 일부 사용자에게만 발생하는가?
  • 장애는 언제 시작되었는가?
  • 최근 배포나 설정 변경이 있었는가?
  • 오류율과 응답 지연은 어떻게 변했는가?
  • 데이터 손실이나 중복 처리 위험이 존재하는가?

초기 대응의 목적은 모든 원인을 즉시 밝혀내는 것이 아니다. 사용자 영향을 최소화하고, 추가적인 피해를 방지하며, 조사에 필요한 증거를 확보하는 것이다.

필요하다면 트래픽을 제한하거나, 문제가 발생한 기능을 비활성화하거나, 이전 버전으로 롤백하는 등 복구를 우선하는 조치를 수행한다.

시간순 이벤트 분석

장애 원인을 찾을 때는 장애 발생 전후의 이벤트를 시간순으로 정리하는 것이 효과적이다.

예를 들어 다음과 같은 흐름을 가정할 수 있다.

  • 신규 버전 배포
  • 특정 API의 응답 지연 증가
  • 데이터베이스 연결 풀 사용량 증가
  • 요청 시간 초과 발생
  • 재시도 요청 증가
  • 전체 API 오류율 상승

이 흐름에서는 데이터베이스 연결 풀의 고갈이 직접적인 원인일 수 있지만, 재시도 정책이 장애를 증폭시킨 요인일 수도 있다.

따라서 장애의 최초 원인뿐 아니라 장애가 확산된 과정과 복구를 지연시킨 요인까지 분석해야 한다.

근본 원인과 기여 요인 구분

장애 원인 분석에서는 근본 원인(Root Cause)과 기여 요인(Contributing Factor)을 구분하는 것이 중요하다.

근본 원인은 장애를 발생시킨 핵심적인 시스템 조건이나 결함을 의미한다. 기여 요인은 장애의 규모를 확대하거나 복구를 어렵게 만든 요소다.

예를 들어 데이터베이스 쿼리의 비효율성이 근본 원인이라면, 캐시 부재와 과도한 재시도는 장애의 영향을 확대하는 기여 요인일 수 있다.

이렇게 구분해야 단순히 최초의 결함만 수정하고 장애 확산 요인을 방치하는 문제를 방지할 수 있다.

또한 장애 원인을 특정 개발자의 실수로만 결론 내리는 것은 효과적인 분석이 아니다. 잘못된 설정이 배포될 수 있었던 검증 절차, 위험을 조기에 발견하지 못한 모니터링, 롤백이 지연된 운영 절차까지 함께 검토해야 한다.

장애 보고서 작성

장애 보고서(Incident Report)는 장애의 발생 원인, 영향 범위, 대응 과정, 복구 결과, 재발 방지 대책을 기록하는 문서다.

장애 보고서의 목적은 책임을 추궁하는 것이 아니라, 장애에 대한 조직의 이해를 높이고 같은 문제가 반복될 가능성을 줄이는 데 있다.

잘 작성된 보고서는 장애를 경험하지 않은 개발자도 어떤 일이 발생했고, 왜 발생했으며, 무엇을 개선해야 하는지 이해할 수 있어야 한다.

장애 보고서의 구성

장애 개요

장애가 발생한 시각, 복구 시각, 영향을 받은 서비스, 심각도, 담당 대응자를 기록한다.

사용자 영향

장애로 인해 사용자가 경험한 문제를 구체적으로 기술한다.

예를 들어 일부 API 요청 실패, 로그인 불가, 경기 결과 저장 지연, 결제 처리 중단 등 실제 기능 관점에서 설명한다.

탐지 경로

장애를 처음 발견한 경로를 기록한다.

모니터링 알림을 통해 발견했는지, 사용자 문의를 통해 발견했는지, 운영자가 직접 확인했는지에 따라 탐지 체계의 개선 방향이 달라진다.

타임라인

장애 발생부터 복구까지의 주요 사건을 시간순으로 기록한다.

배포, 최초 오류, 알림 발생, 조사 시작, 완화 조치, 복구 확인 등의 이벤트를 포함한다.

근본 원인 및 기여 요인

장애를 직접 발생시킨 원인과 영향을 확대시킨 요인을 구분해 설명한다. 관련 로그, 메트릭, 트레이스 등 객관적인 근거를 함께 첨부한다.

대응 및 복구 과정

실제로 수행한 조치와 각 조치의 결과를 기록한다. 효과가 없었던 조치도 향후 대응 개선에 도움이 된다면 포함한다.

재발 방지 대책

코드 수정, 모니터링 개선, 테스트 추가, 배포 절차 변경, 용량 확장 등 구체적인 후속 작업을 정의한다.

각 작업에는 담당자, 완료 목표, 검증 방법을 지정한다.

좋은 장애 보고서의 기준

장애 보고서는 추측과 사실을 구분해야 한다. 아직 검증되지 않은 원인은 가설로 표시하고, 로그나 메트릭으로 확인된 사실과 혼동하지 않아야 한다.

또한 다음과 같은 표현은 피하는 것이 좋다.

  • 담당자의 실수로 장애가 발생했다.
  • 서버에 문제가 있었던 것 같다.
  • 앞으로 주의하겠다.

이러한 표현은 기술적인 원인과 개선 방향을 설명하지 못한다.

대신 다음과 같이 작성한다.

  • 특정 쿼리의 실행 시간이 증가하면서 데이터베이스 연결 풀이 고갈되었다.
  • 연결 대기 시간이 증가했지만 관련 알림이 설정되어 있지 않아 조기 탐지가 이루어지지 않았다.
  • 쿼리 실행 계획 검증을 배포 절차에 추가하고, 연결 풀 사용량과 대기 시간을 모니터링하도록 개선한다.

이처럼 원인, 증거, 개선 조치를 연결해야 장애 보고서가 실제 운영 개선으로 이어진다.

로그·메트릭·트레이스를 연결한 분석

로그(Logs), 메트릭(Metrics), 트레이스(Traces)는 서로 다른 관점에서 시스템의 상태를 설명한다.

각각을 독립적으로 수집하는 것만으로는 복잡한 장애를 빠르게 분석하기 어렵다. 공통 식별자를 활용해 세 가지 데이터를 연결하면 장애가 발생한 요청을 중심으로 원인을 추적할 수 있다.

메트릭: 문제가 발생한 시점과 범위 파악

메트릭은 시간에 따른 시스템 상태를 수치로 표현한다.

대표적인 메트릭은 다음과 같다.

  • 초당 요청 수와 처리량
  • HTTP 오류율
  • 평균 및 p95·p99 응답 지연
  • CPU와 메모리 사용량
  • 데이터베이스 연결 풀 사용량
  • 이벤트 루프 지연
  • 활성 WebSocket 연결 수

메트릭은 장애가 언제 시작되었는지, 어느 서비스에서 문제가 발생했는지, 사용자 영향이 어느 정도인지 파악하는 데 적합하다.

예를 들어 특정 API의 p99 응답 시간이 급격히 증가했다면 해당 API의 처리 과정과 의존성을 조사할 수 있다.

로그: 개별 사건의 상세 내용 확인

로그는 특정 시점에 발생한 사건과 그 맥락을 기록한다.

구조화된 로그를 사용하면 서비스 이름, 요청 경로, 오류 코드, 사용자 세션 식별자, Request ID, Trace ID 등의 필드를 기준으로 검색할 수 있다.

예를 들어 오류 로그에 다음과 같은 정보가 포함될 수 있다.

{
  "level": "error",
  "service": "game-api",
  "message": "Database query timeout",
  "requestId": "req-a8f2",
  "traceId": "trace-91bc",
  "route": "/match/result",
  "errorCode": "DB_TIMEOUT"
}

이 로그는 오류의 종류와 발생 위치를 알려준다. 다만 로그만으로는 요청이 어떤 서비스를 거쳤으며 어느 구간에서 지연이 발생했는지 충분히 파악하기 어려울 수 있다.

트레이스: 요청 처리 경로 확인

분산 트레이싱은 하나의 요청이 여러 서비스와 시스템을 거치는 과정을 추적한다.

각 처리 구간은 Span으로 표현되며, 관련 Span은 Trace ID를 통해 하나의 요청 흐름으로 연결된다.

예를 들어 게임 결과 저장 요청은 다음과 같은 경로를 거칠 수 있다.

Client
  └─ Game API
      ├─ Authentication
      ├─ Match Service
      ├─ Database Query
      └─ Reward Service

트레이스를 분석하면 전체 요청 시간 중 어느 구간에서 지연이 발생했는지 확인할 수 있다.

전체 요청 시간이 길더라도 모든 서비스가 느린 것은 아니다. 특정 데이터베이스 쿼리나 외부 API 호출이 대부분의 지연 시간을 차지할 수 있다.

세 가지 관측 데이터를 연결하는 방법

로그·메트릭·트레이스를 연결하는 핵심은 공통 식별자와 일관된 시간 정보다.

메트릭에서 이상 징후를 발견한다.

특정 API의 오류율과 p99 응답 지연이 증가한 시점을 확인한다.

트레이스로 느린 요청을 추적한다.

해당 시간대에 발생한 느린 요청을 찾아 어떤 서비스나 처리 구간에서 지연이 발생했는지 확인한다.

로그에서 구체적인 오류를 확인한다.

트레이스의 Trace ID나 요청의 Request ID를 기준으로 관련 로그를 검색한다. 데이터베이스 타임아웃, 인증 실패, 외부 API 오류 등 구체적인 사건을 확인한다.

원인을 검증하고 복구한다.

확인된 증거를 바탕으로 쿼리, 연결 풀, 재시도 정책, 이벤트 루프 등 문제 지점을 수정한다. 이후 동일한 메트릭과 트레이스를 확인해 개선 효과를 검증한다.

이 과정에서 OpenTelemetry는 메트릭, 로그, 트레이스의 계측과 수집을 일관된 방식으로 구성하는 데 활용할 수 있다. Prometheus는 메트릭 수집과 조회에, Grafana는 대시보드와 시각화에, Loki는 로그 수집 및 검색에 활용할 수 있다.

다만 모든 도구가 자동으로 완벽하게 연결되는 것은 아니다. Trace ID 전파, 로그 필드 구성, 계측 설정, 데이터 보존 정책 등을 일관되게 설계해야 한다.

실시간 게임 서버에서의 운영 대응

실시간 게임 서버는 일반적인 웹 API와 다른 운영 특성을 가진다.

WebSocket 연결이 장시간 유지되고, 룸이나 매치 단위로 상태가 관리되며, 여러 서버 인스턴스가 동시에 동작할 수 있기 때문이다.

따라서 HTTP 요청 오류율만으로는 게임 서비스의 상태를 충분히 파악할 수 없다.

연결 및 세션 상태 모니터링

다음과 같은 지표를 관찰해야 한다.

  • 활성 WebSocket 연결 수
  • 연결 및 재접속 성공률
  • 연결 종료 코드와 종료 사유
  • 핑과 퐁을 기반으로 한 연결 상태
  • 룸별 인원수와 매치 생성 실패율
  • 서버별 처리 중인 룸 수
  • 메시지 처리 지연과 큐 적체량

특정 서버 인스턴스에서 연결이 급증하거나 재접속이 반복된다면 로드 밸런싱, 네트워크 상태, 세션 관리, 서버 자원 사용량을 함께 조사해야 한다.

매치 결과와 보상 지급 검증

게임 서버에서 특히 중요한 장애는 상태 정합성과 관련된 문제다.

경기 결과가 저장되지 않거나 보상이 중복 지급되면 단순한 서비스 지연보다 심각한 데이터 문제가 발생할 수 있다.

이러한 상황에서는 다음 사항을 확인해야 한다.

  • 경기 결과가 최종적으로 저장되었는가?
  • 동일한 결과 이벤트가 중복 처리되었는가?
  • 보상 지급과 결과 저장 사이에 정합성 문제가 발생했는가?
  • 재시도 과정에서 중복 지급이 발생할 가능성이 있는가?
  • 서버 재시작 이후 미처리 작업을 복구할 수 있는가?

보상 지급과 같은 중요 작업에는 멱등성 키, 데이터베이스 트랜잭션, 중복 처리 방지 로직 등을 적용해야 한다. 장애 분석에서도 단순히 API 성공 응답을 확인하는 데 그치지 않고 최종 데이터 상태까지 검증해야 한다.

인스턴스 장애와 연결 종료 대응

서버 인스턴스가 종료되면 해당 인스턴스에 연결된 클라이언트와 진행 중인 룸을 어떻게 처리할지 고려해야 한다.

Graceful Shutdown을 적용하면 신규 연결을 차단하고, 기존 작업을 정리하며, 가능한 경우 클라이언트가 재접속할 수 있도록 안내할 수 있다.

운영 모니터링에서는 인스턴스 종료 전후의 연결 수, 재접속률, 매치 중단 건수, 상태 복구 결과를 확인해야 한다.

이러한 지표를 통해 단순히 서버가 재시작되었다는 사실을 넘어, 실제 사용자에게 어떤 영향이 발생했는지 파악할 수 있다.

운영 대응 체계의 지속적인 개선

운영 대응은 장애가 발생했을 때만 수행하는 작업이 아니다. 장애가 발생하기 전에 위험을 발견하고, 장애가 발생했을 때 신속하게 복구하며, 복구 이후 시스템을 개선하는 지속적인 활동이다.

이를 위해 다음과 같은 운영 원칙을 유지해야 한다.

  • 서비스 상태를 판단할 수 있는 헬스 체크를 설계한다.
  • 사용자 영향과 긴급성을 기준으로 알림 정책을 구성한다.
  • 장애 발생 시 영향 범위와 복구 가능성을 먼저 판단한다.
  • 로그·메트릭·트레이스를 연결해 원인을 검증한다.
  • 장애 보고서에 객관적인 증거와 실행 가능한 개선 작업을 기록한다.
  • 개선 작업이 완료되었는지 확인하고, 실제로 재발 위험이 감소했는지 검증한다.

운영 대응의 성숙도는 장애가 한 번도 발생하지 않는지로 판단할 수 없다. 복잡한 시스템에서 장애를 완전히 제거하는 것은 현실적으로 어렵다.

중요한 것은 장애를 얼마나 빨리 감지하고, 얼마나 정확하게 분석하며, 얼마나 안전하게 복구하고, 같은 문제가 반복되지 않도록 시스템을 얼마나 개선하는가이다.

결국 좋은 운영 체계는 장애 대응을 개인의 경험과 직관에 의존하는 방식에서 벗어나, 관측 가능한 데이터와 검증 가능한 절차를 기반으로 수행하도록 만든다. 이것이 안정적인 서비스를 지속적으로 운영하기 위한 핵심이다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다