Incident Library
적용된 필터 구성 요소데이터베이스기여 요인기본 설정 방치모두 풀기검색어 없이 필터만 적용한 목록입니다. 최근 사례부터입니다.
추천 필터 검색하면 검색어에서 찾은 분류 값이 여기에 나옵니다.

그래프

  • 원인
  • 구성 요소
  • 증상
  • 기여 요인
  • 사례

사례10건

10건 중 1~5번째

  1. 증상

    월말 마지막 영업일 아침 6시쯤부터 Cloud Pub/Sub 메시지가 밀리기 시작했고, Cloud Spanner에 새 회계 데이터를 등록하지 못하는 상태가 간헐적으로 이어졌다. 밀린 메시지는 1000만 건 규모에 이르렀다. 복구와 재발을 거듭하며 수습하기까지 하루가 넘게 걸렸다.

    촉발

    장애 한 달여 전 Cloud Functions를 1st gen에서 Cloud Run 기반 2nd gen으로 옮기면서 --max-instances 를 지정하지 않아, 스케일 상한이 1st gen 기본값인 사실상 무제한에서 2nd gen 기본값인 100으로 내려갔다. 월말 아침 부하가 쉬는 구간 없이 약 40분 이어지자 이 상한에 걸렸다.

    원인
    구성 요소
    기여 요인
    조치
    • 별도 pull 구독으로 Dataflow가 Cloud Storage에 저장해 둔 데이터를 다시 넣어 데이터 손실을 피했다.
    후속 조치
    • max-instances 를 비롯한 스케일 관련 파라미터를 배포 정의에 모두 명시해 세대나 기본값이 바뀌어도 영향을 받지 않게 했다. max-instances 는 Spanner 부하를 생각해 100에서 1000까지 단계적으로 올렸다.
    • 콜드 스타트를 피하려고 min-instances 를 1로 두고, 핸들러의 공유 상태가 안전한지 확인한 뒤 concurrency 를 1에서 10으로 올렸다. 이에 맞춰 cpu는 1, memory는 512MB에서 1Gi로 늘렸다.
    • mercari/spanner-autoscaler를 관리하는 SRE 팀이 High priority CPU와 Total CPU를 OR 조건으로 보는 dual CPU scaling mode를 구현했다. 팀은 이 기능이 담긴 v0.8.0을 도입해 Total CPU 임계값 70%를 새로 뒀다.
    • 스케일업이 더 빨리 시작되도록 High priority CPU 임계값을 60%에서 55%로 내렸다.
    • 월말 피크가 시작될 때 확보한 PU가 줄지 않도록 아침 5시부터 7시까지 Spanner 스케일다운을 막는다.
    • 월말 아침이나 대규모 리컨사일이 도는 달처럼 부하를 예상할 수 있는 기간에는 일정에 따라 PU를 미리 확보한다.
    • Datadog에 Cloud Run 인스턴스 수가 상한의 40%와 60%에 이르면 각각 경고 단계와 심각 단계로 알리는 모니터를 더했다.
    • Datadog에 Pub/Sub의 전달되지 않은 메시지 수가 임계값을 넘으면 알리는 모니터를 더했다. 오탐을 피하려고 보수적인 임계값에서 시작해 평소 상태를 알아 가며 단계적으로 낮춘다.
    교훈

    관리형 서비스의 세대를 옮길 때는 직접 바꾸지 않은 기본값이 부하가 걸릴 때 문제로 드러난다. 스케일 상한, 동시 처리 수, 타임아웃처럼 평소에는 효과가 보이지 않는 파라미터는 옮길 때마다 명시해야 한다. 장애 원인은 하나가 아닐 수 있으므로 촉발, 증폭, 실제 피해로 이어진 요인을 각각 봐야 한다. 설정 최적화와 그 한계에 가까워지는 것을 알아채는 모니터링은 늘 함께 갖춰야 하고, 물려받아 운영하는 시스템일수록 설정과 전제를 정기적으로 다시 살펴야 한다.

  2. 증상

    어느 날 갑자기 애플리케이션 오류율이 나빠졌다는 알림이 울렸다. 그 시간대 Aurora MySQL RDS 인스턴스의 오류 로그에는, Aurora MySQL 이 메모리 부족으로 OOM 이 나는 것을 피하려고 커넥션을 끊고 쿼리를 거부한 기록이 남아 있었다.

    촉발

    FreeableMemory 가 내려가기 시작한 날의 애플리케이션 릴리스에서 쿠버네티스 CronJob 으로 매분 도는 배치 처리가 더해졌다.

    원인
    구성 요소
    기여 요인
    감지

    애플리케이션 오류율이 나빠졌다는 알림이 울렸다.

    조치
    • Aurora MySQL 파라미터 그룹에서 Performance Schema 를 자동 관리를 뜻하는 0 에서 수동 관리를 뜻하는 1 로 바꾸고, 기본값 -1 로 무제한이던 관련 파라미터 두 개에 상한 100 을 두었다. 적용에는 RDS 인스턴스 재시작이 필요했고, 이 조치로 FreeableMemory 감소와 SwapUsage 발생이 멈췄다.
    교훈

    시스템 알림이 울렸는데 DB 부하 지표가 조용하면 Performance Schema 가 불어난 것도 의심해야 한다. 상한을 둔 두 파라미터는 기본값이 무제한이라 이번처럼 기록이 계속 쌓였다. 상한을 두면 퍼포먼스 인사이트의 호스트별 집계에서 상한을 넘은 호스트의 정보가 빠지는 단점이 있다. 애플리케이션과 Aurora MySQL 사이에 RDS Proxy 를 두어 DB 에 접속하는 HOST 를 일정하게 유지하는 방법도 있다.

  3. 증상

    13:30 UTC 에 ZooKeeperWait 지표가 갑자기 오른다는 알림이 왔다. 이 클러스터의 알림 기준은 낮은 쪽 10초, 높은 쪽 20초인데 값은 수천 초였다. 값은 대칭으로 이중화된 인스턴스 세 곳에서 똑같이 올랐다.

    촉발

    몇 달 동안 네트워크에서 떨어져 있던 클라이언트 머신 두 대가 다시 연결되면서, 그동안 쌓인 몇 달 치 헬스 체크 데이터를 아주 작은 배치로 빠르게 보냈다.

    원인
    구성 요소
    기여 요인
    감지

    13:30 UTC 에 팀은 ZooKeeperWait 지표가 갑자기 오른다는 알림을 받았다. 이 클러스터 크기에 맞춘 알림 기준은 낮은 쪽 10초, 높은 쪽 20초였다.

    조치
    • 쌓인 파트를 끝내 정리하지 못한 5분 단위 파티션 테이블을 장애 뒤 DROP-CREATE 로 다시 만들어 정상으로 되돌렸다.
    • 그 테이블의 파티션 단위를 분에서 시간으로 넓혔다.
    후속 조치
    • 루트 MaterializedView 테이블에서 범위를 벗어난 타임스탬프를 거부하도록 구현했다.
    • 두 번째 MaterializedView 가 거부된 데이터의 통계를 기록한다.
    • 거부 범위는 과거 데이터 백필을 위해 일부러 넓게 잡았고, 거부되는 데이터를 모아 가며 범위를 다듬는다.
    • 타임스탬프가 며칠이나 몇 달에 걸친 insert 쿼리 하나로 이번 상황을 재현하는 최소 시험 시나리오를 만들었다.
    • 관측 기능을 여러 가지 개선한다.
    교훈

    이 파이프라인은 주로 데이터 양을 다루지만, 어긋난 타임스탬프도 카디널리티 변화만큼 파이프라인을 흔들 수 있었다. 이상한 지표를 바로 설명하지 못했다고 치워 두면 안 된다. 이번에도 원인으로 이끈 것은 처음에 무시한 insert 크기 감소였다. 중앙값과 평균은 각자 쓸모가 있고, 이번에는 평균이 실마리였다. 파티션이 너무 적으면 파트가 커지고 mutation 이 느려지며 TTL 이 너무 비싸지거나 아예 동작하지 않는다. 반대로 너무 많으면 열 스캔과 집계 쿼리가 느려지고 Keeper 가 과부하된다. Keeper 작업은 파트 수에 따라 선형보다 훨씬 빠르게 늘었다.

  4. 증상

    2025-09-22 11:05 UTC 에 Railway 프로젝트 캔버스가 열리지 않는다는 첫 신고가 들어왔다. 캔버스는 실제 오류를 보여 주지 않고 끝없이 로딩 상태에 머물렀다.

    촉발

    코드 정리 중 쓰지 않는 컬럼을 지우는 스키마 변경을 했는데, 뒤이은 코드 변경이 그 일부를 의도치 않게 되돌려 프런트엔드가 쓰는 핵심 API 가 실패했다. 이 문제를 고친 뒤 밀린 배포가 한꺼번에 시작되면서, 몇 버전 올라간 PgBouncer 를 쓰던 Control Plane 이 부하를 이기지 못했다.

    원인
    구성 요소
    기여 요인
    감지

    11:05 UTC 에 사용자들이 Railway 프로젝트 캔버스가 열리지 않는다고 신고했다. 두 번째 문제는 11:48 UTC 에 Control Plane 의 자원 사용이 비정상으로 늘고 API 지연이 높아지면서 드러났다.

    조치
    • 사고를 선언하고 15분 안에 수정을 배포해 프로젝트 캔버스 문제를 풀었다.
    • 먼저 Free, Trial, Hobby 등급 사용자의 배포를 멈춰 Pro 사용자는 평소대로 배포하게 하고 배포 대기열이 차츰 줄게 했다.
    • 가장 불안정할 때는 Pro 를 포함한 모든 새 배포를 최대 20분 멈춰 대기열을 더 줄였다.
    • Control Plane 데이터베이스의 CPU 와 메모리를 늘리고, 커넥션 한도를 조정하고, IOPS 용량을 늘렸다.
    • 설정을 손보는 대신 안정적이던 이전 PgBouncer 버전으로 곧바로 롤백했고, 성능이 100배 좋아지며 모든 지표가 정상으로 돌아왔다.
    • 롤백 뒤 Pro 가 아닌 사용자 모두의 배포를 다시 열었다.
    • 21:27 UTC 에 사설 네트워크와 그 엔드포인트가 대시보드에 보이지 않던 드문 경우를 뒤늦게 고쳤다.
    후속 조치
    • Control Plane 저장 계층의 큰 부분을 Postgres 밖으로 옮기는 재설계를 계속한다. 이 작업은 3분기 초에 시작했고, 한 리전의 Control Plane 장애가 플랫폼 전체에 번지는 것을 막고 지금의 Postgres 보다 몇 자릿수 높은 IOPS 를 낼 것을 목표로 한다.
    • CI 파이프라인 검증을 강화해 중단을 일으키는 스키마 변경이 운영에 닿지 못하게 하고, 백엔드 배포 전에 스키마 호환성을 자동으로 검사한다.
    • PgBouncer 노드의 CPU, 메모리, 커넥션 풀 사용률을 모니터링하고 알림을 건다.
    • PgBouncer 업그레이드는 한꺼번에 하지 않고 인스턴스마다 단계적으로 적용한다.
    교훈

    Railway 는 호환되지 않는 스키마 변경이 운영에 닿지 않았다면 이번 연쇄 장애가 없었을 것으로 보았다. PgBouncer 의 성능 저하를 미리 알았다면 훨씬 빨리 복구할 수 있었다고 했다. PgBouncer 를 한꺼번에 올리지 않고 인스턴스마다 차례로 올렸다면 전체에 퍼지기 전에 버전별 성능 문제를 찾았을 것이라고도 했다.

  5. 증상

    Aurora MySQL 에 접속 실패가 잦아지다가 결국 웹 페이지를 열 수 없게 되어 서비스 전체가 다운되었다. 웹 애플리케이션은 DB 가 응답하지 않아 타임아웃이 잇따랐고 새 DB 접속을 맺지 못했다.

    촉발

    롱 트랜잭션 안에서 SAVEPOINT 를 만들고 대상 테이블에 INSERT 한 뒤 ROLLBACK TO SAVEPOINT 를 실행했고, 이 롤백이 그 테이블의 supremum 에 배타 락을 남겼다.

    원인
    구성 요소
    기여 요인
    후속 조치
    • 원칙적으로 SAVEPOINT 를 쓰지 않는다. 부분 롤백이 필요하면 트랜잭션 자체를 나누고, 꼭 트랜잭션을 중첩해야 하면 애플리케이션 쪽에 타임아웃을 둔다.
    • 트랜잭션 격리 수준은 세션 단위로도 정할 수 있다. 그래서 팬텀 행을 허용할 수 있는 경우에는 갭 락을 잡지 않는 READ COMMITTED 를 쓰는 것도 고려하도록 개발자를 교육하고 안내한다.
    • 롱 트랜잭션을 감시하고, 회사 전체에서 롱 트랜잭션을 없애는 자발적인 활동을 이어 간다.
    교훈

    supremum 락 하나로는 문제가 되지 않지만 롱 트랜잭션과 겹치면 서비스 정지로 이어진다. ORM 프레임워크는 중첩 트랜잭션을 만들려고 내부에서 SAVEPOINT 를 쓰는 일이 많아 개발자가 모르고 쓰게 된다. 롱 트랜잭션이 잡은 락은 영향 범위가 좁아 막히는 작업이 적으면 지나치기 쉽지만, 이번 일로 그 잠재 위험이 드러났다.

내 클러스터에도 있는지 확인하기

이 10건에서 가장 많이 나오는 구성 요소: 데이터베이스, 데이터베이스 복제. kubegap 은 Claude Code 나 Codex 에서 쿠버네티스 클러스터를 읽기만 하며 이런 틈을 점검합니다. 점검 항목의 근거는 이 라이브러리와 같은 공개 보고서입니다.

원인별5

업그레이드로 깨진 호환성2건

  1. IL-0572 Merpay 회계 이벤트 처리 시스템에서 Cloud Pub/Sub 메시지 1000만 건이 밀려 새 회계 데이터가 하루 넘게 Cloud Spanner에 들어가지 못했다
  2. IL-0316 밀린 배포가 한꺼번에 몰린 Control Plane 에서 새 버전 PgBouncer 가 CPU 와 메모리를 비정상적으로 많이 써 데이터베이스 연결이 타임아웃됐다

용량 한계3건

  1. IL-0435 Aurora MySQL 이 OOM 을 피하려고 커넥션을 끊고 쿼리를 거부해 애플리케이션 오류율이 올랐다
  2. IL-0288 CDN77 의 ClickHouse 데이터 파이프라인에서 이중화된 인스턴스 세 곳의 ZooKeeperWait 가 수천 초로 치솟아 복제가 한 시간 넘게 느려졌다
    CDN772026
  3. IL-0386 Google Cloud 로 옮긴 뒤 GKE 노드에서 Postgres 연결 타임아웃과 memcached i/o timeout 이 간헐적으로 튀었다

소프트웨어 결함1건

구성 요소
조직
  1. IL-0436 Aurora MySQL 에서 INSERT 가 supremum 락에 막혀 커넥션이 고갈되고 freee 웹 서비스 전체가 다운되었다
    freee2025

운영 실수3건

  1. IL-0582 Aurora PostgreSQL 위의 qg 잡 큐에서 que_jobs 의 dead tuples 가 계속 늘어 잡이 대량으로 밀렸다
    Kanmu2024
  2. IL-0431 AWS 로 옮기는 점검 중 PostgreSQL 이 의도하지 않게 장애 조치되어 한 시간 동안 갱신된 데이터가 사라졌다
    Hatena2017
  3. IL-0218 복제를 다시 맞추다 PostgreSQL 프라이머리의 데이터 디렉터리가 지워지고 백업이 작동하지 않아 GitLab.com 이 약 18시간 멈추고 데이터를 잃었다
    GitLab2017

설정 변경1건

  1. IL-0511 Vault 가 새로 발급한 데이터베이스 자격 증명이 SCRAM 으로 만들어져 pgbouncer 가 RDS 에 로그인하지 못하고 xPro 운영 사이트가 멈췄다