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

그래프

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

사례3건

3건 중 1~3번째

  1. 증상

    2025년 4월 9일 14:16 UTC 부터 대시보드, 모바일 앱, Slack 앱, API 가 간헐적으로 느려졌고, 모니터링이 곧 문제를 알렸다. 14:25 부터 14:27 UTC 까지 2분 동안은 데이터베이스가 완전히 내려가 제품 전체가 영향을 받았다.

    촉발

    PGAudit 를 다시 켠 운영 데이터베이스에서 빈 테이블을 만들고 인덱스를 더하는 평범한 마이그레이션을 14:16 UTC 에 실행했다.

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

    모니터링이 문제를 빠르게 알렸다.

    조치
    • PGAudit 프로세스를 죽이는 시도가 계속 실패하자 데이터베이스를 재시작해 멈춘 프로세스를 강제로 끝냈다. 이 때문에 주 데이터베이스가 14:25 부터 14:27 UTC 까지 2분이 조금 안 되게 내려갔다.
    • 서비스를 되살린 뒤 PGAudit 확장을 잠시 껐다가 완전히 지웠다.
    후속 조치
    • PGAudit 가 안전하다고 보장할 수 있을 때까지 확장을 지운 상태로 두어, 실수로 다시 켜질 위험을 없앤다.
    • 원인 조사를 계속한다.
    • 내부 회고를 한다.
    • 비슷한 상황을 더 잘 감지하고 막고 대응하도록 절차와 모니터링을 보강한다.
  2. 증상

    인프라를 Google Cloud 로 모두 옮긴 뒤 Postgres 연결 타임아웃이 평소보다 많이 나서 인시던트를 선언했다. 초당 새로 여는 연결 수가 수백 개 수준에서 크게 오르내렸다.

    촉발

    노드에서 짧게 열고 닫는 TCP 연결이 대량으로 생겼다. 연결 풀이 초당 수백 개씩 새 연결을 열었고, 실수로 들어간 데이터베이스 join 때문에 외부 제3자 서비스로 가는 중복 호출 수천 번이 한꺼번에 나갔다.

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

    Postgres 연결 타임아웃이 평소보다 많이 나는 것을 보고 인시던트를 선언했다.

    조치
    • Postgres 연결의 최대 수명을 15m 에서 30m 로 두 배 늘렸다.
    • 연결 풀을 늘 N개의 연결을 열어 두는 고정 크기로 바꿨다.
    • memcache 클라이언트의 MaxIdleConns 를 2 에서 20 으로 올렸다.
    • 변수를 줄이려고 Google 이 운영하는 memcached 대신 쿠버네티스 클러스터 안에서 직접 돌리는 memcached 로 옮겼다. 이 전환으로는 거의 달라지지 않았다.
    • 실수로 들어간 데이터베이스 join 때문에 외부 제3자 서비스로 중복 호출을 수천 번 보내던 문제의 수정을 운영에 배포했다. 그 뒤 데이터베이스 연결 문제와 캐시 문제가 거의 사라졌다.
    후속 조치
    • 외부로 나가는 네트워크 호출에 더 알맞은 동시성 한도를 둔다. 공급자의 rate limit 안에 있어도 노드에 영향을 줄 수 있기 때문이다.
    교훈

    가설을 너무 빨리 좁히지 않는다. 이런 네트워크 타임아웃을 보면 같은 파드만이 아니라 같은 노드에서 도는 모든 것을 포함해 시스템 전체의 활동을 봐야 한다. 오류와 그 영향은 대개 요청 하나에 머물지만 늘 그렇지는 않다. 외부로 나가는 네트워크 호출의 동시성도 제한해야 한다. 이전에는 공급자의 rate limit 이 주된 제약이었지만, rate limit 안에 있어도 노드에 영향을 줄 수 있다.

  3. 증상

    2023년 초 incident.io 애플리케이션이 데이터베이스를 쓰는 동안 간헐적으로 타임아웃이 났다. 고객 신고가 들어왔고, 오류 수집 도구 Sentry 에 context canceled 오류가 한꺼번에 쏟아졌다.

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

    고객 신고가 들어왔고 Sentry 에 context canceled 오류가 쏟아지면서 알아챘다. 온콜 엔지니어가 장애를 열고 Grafana 의 API 대시보드에서 타임아웃을 확인했다. 두 번째 타임아웃 때는 장애가 자동으로 열리고 온콜 엔지니어가 호출됐다.

    조치
    • 정책 위반은 요청마다 정책과 관련 장애를 모두 가져와 계산해 왔는데, 이 계산을 머티리얼라이즈드 뷰로 옮겼다.
    • 느린 쿼리를 빠르게 하려고 데이터베이스 인덱스를 새로 더했다.
    • 인덱스 없는 열로 조인한 뒤 거르던 쿼리를, 조인에 이미 들어 있는 테이블의 인덱스 있는 같은 열로 거르도록 다시 썼다.
    • 어떤 요청이 트랜잭션을 오래 쥐고 있는지 빨리 찾으려고 모든 트랜잭션에 1초 락 타임아웃을 걸었다.
    • Slack 웹훅이 들어오면 데이터베이스 쿼리 없이 바로 PubSub 로 넘겨 Slack 이벤트를 비동기로 처리하게 바꿨다.
    • ngrok/sqlmw 패키지로 미들웨어를 만들고, trackUsage 메서드로 작업마다 데이터베이스 커넥션을 쥔 시간을 세어 로그와 트레이스에서 거를 수 있게 했다.
    • Slack 모달 제출 대부분에서 필요 없던 트랜잭션을 없애고, 트랜잭션 보장이 필요한 코드 경로에만 명시적으로 넣었다.
    교훈

    한 번에 모든 것이 풀리는 결정적인 발견은 없었다. 대신 그 과정에서 이런 문제를 진단할 준비가 훨씬 잘 됐고, 실제 성능 개선도 함께 이뤄졌다. 원인은 눈에 띄게 느린 것 하나가 아니라 짧은 트랜잭션 여러 개가 합쳐진 것이었다. 애플리케이션의 부분마다 다른 데이터베이스를 썼다면 아마 더 빨리 찾았을 것이다. 하지만 그러면 분산 트랜잭션을 고민해야 하고 개발 환경도 덜 편해지므로, 팀은 지금의 선택을 유지한다.

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

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

원인별2