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

그래프

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

사례6건

6건 중 1~5번째

  1. 증상

    2026-04-28 10:34 BST에 새 데이터베이스로 전환한 뒤 11:30 무렵 운영에서 데이터 이상이 보였다. 이전 직전에 쓴 짧은 기간의 데이터가 새 데이터베이스로 복제되지 않았고, 서비스는 전환 때부터 약 3시간 저하됐다.

    촉발

    2026-04-20 16:20 BST 무렵 관련 없는 설정 수정 작업 중에 자격 증명을 교체했다. 그 자격 증명으로 데이터베이스 연결을 잡고 있던 임시 일회성 복제 프로세스가 죽었고, 그 순간 처리 중이던 데이터 묶음이 버려진 뒤 다시 재생되지 않았다.

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

    2026-04-28 11:30 BST 무렵 운영에서 데이터 이상을 발견하고 조사를 시작했다. 8일 전의 손실은 그때까지 아무 신호도 없었다.

    조치
    • 근본 원인을 찾는 일보다 서비스의 정상 동작을 되살리는 일을 먼저 했고, 전환 약 3시간 뒤인 13:30 BST 무렵 정상 동작이 돌아왔다.
    • 버려진 묶음을 다시 재생할 원본으로 쓰려고 이전 사업자에게 지운 원본 데이터베이스의 복원을 요청했다.
    • 2026-04-29부터 2026-04-30까지 원본 데이터베이스를 복원하고 영향을 받은 사용자의 기록을 다시 재생했다. 이 동안 서비스는 더 멈추지 않았다.
    후속 조치
    • 위험도가 비슷한 기술 변경은 라이브 전환 대신 계획된 유지보수 시간 안에 한다. 트래픽을 다시 받기 전에 무결성을 확인할 수 있도록 짧은 계획 중단을 받아들인다.
    • 이런 변경에는 전환 전 점검표를 두고, 전환 직전에 데이터 복제나 동기화 프로세스가 살아 있고 따라잡았는지 확인한다.
    • 오래 도는 프로세스가 쓰는 서비스 계정의 자격 증명을 교체할 때는 그 뒤에 영향을 받을 곳을 명시적으로 검토한다.
    • 전환 뒤 대상 쪽의 무결성을 따로 확인하기 전에는 원본 시스템을 내리거나 지우지 않는다.
    • 계획된 유지보수와 이전을 고객에게 알릴 때 Discord와 함께 웹 콘솔에서 보이는 제품 안 News 피드에도 올리고, 영향을 분명히 적고, 이번보다 훨씬 일찍 알린다.
    교훈

    이전 작업 자체는 문제가 없었고, 실패는 8일 전 관련 없는 변경이 조용히 남긴 부작용이었다. 복제 프로세스가 다시 살아나 정상으로 돌았기 때문에 데이터를 잃었다는 신호가 없었고, 전환 전에 데이터 무결성을 확인했다면 트래픽을 다시 받기 전에 잡았을 것이다. 새 데이터베이스의 무결성을 확인하기 전에 원본 데이터베이스를 지운 탓에 복구가 크게 복잡해졌으므로 앞으로는 전환 뒤 확인이 끝날 때까지 원본을 남긴다. 중단을 줄이려고 고른 라이브 이전에는 트래픽이 돌아오기 전에 무결성을 확인할 틈이 없었다. 그 결과 약 3시간의 서비스 저하와 이틀의 복구가 이어졌고, 이는 계획된 유지보수로 서비스를 잠깐 멈췄을 때보다 훨씬 큰 영향이었다. Discord 공지는 영향이 분명하지 않았고 고객이 대비할 시간을 충분히 주지 못했다.

  2. 증상

    2022년 11월 23일 9:39 UTC 에 트래픽 전부가 새 Aurora PostgreSQL 14.x 클러스터로 넘어갔고, 지연이 나빠져 인프라 팀이 조사를 시작했다. 9:54 UTC 에는 쿼리가 평소보다 훨씬 오래 걸리면서 데이터베이스 연결을 모두 차지하고 있었다.

    촉발

    복제를 이용해 Aurora PostgreSQL 10.x 클러스터에서 새 14.x 클러스터로 트래픽을 넘겼다. 그런데 가장 큰 테이블 하나의 vacuum 이 전환 전에 끝나지 않아, 새 클러스터의 가장 큰 테이블들에 ANALYZE 가 돌지 않은 상태였다.

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

    9:39 UTC 에 트래픽 전부가 새 클러스터로 넘어갔을 때 지연이 나빠 보였고, 인프라 팀이 바로 조사를 시작했다.

    조치
    • 9:54 UTC 에 쿼리가 데이터베이스 연결을 너무 오래 잡지 않도록 데이터베이스 사용자에 statement timeout 을 걸었다.
    • 9:58 UTC 에 로드 밸런서에서 트래픽의 90% 에 503 을 보내 부하를 덜고 시스템이 회복할 여유를 만들었다.
    • 10:00 UTC 무렵부터 오래 걸리는 쿼리에 EXPLAIN 을 돌려 보고, 해만 끼치고 필요 없는 인덱스를 지우기 시작했다.
    • 트래픽을 100% 로 되돌리는 동안 Apple 웹훅을 잠시 받지 않았다.
    • New Relic 이 느린 쿼리마다 돌리는 EXPLAIN 쿼리를 없애려고 New Relic 을 끈 새 릴리스를 냈다.
    • 12:00 UTC 무렵부터 가장 큰 테이블들에 손으로 ANALYZE 를 돌렸다.
    • 미리 준비해 둔 스크립트로 영향받은 시퀀스 값을 자동으로 올려 기본 키 중복을 풀었다.
    • 전환 몇 분 뒤 통합 이벤트 발송 작업이 이벤트 테이블을 갱신하지 못하는 것을 잡고 발송 작업을 손으로 멈췄다.
    • 발송되었지만 데이터베이스에 기록되지 않은 웹훅을 만일에 대비해 다시 보냈다.
    • 13:33 UTC 에 통합 이벤트 발송, ETL, 웹 서버 밖의 작업을 모두 되살렸다.
    후속 조치
    • 사업에 중요한 시기에는 변경 동결을 두는 것을 검토한다.
    • 백엔드 장애 때 SDK 가 얼마나 믿을 만하게 동작하는지 더 잘 알린다.
    • 개발자 대시보드와 기술 담당자에게 보내는 직접 이메일을 써서 유지보수와 장애를 고객에게 더 잘 알린다.
    • 사전 연습에서 트래픽 일부를 재생해 전환 당일과 더 비슷한 조건을 만든다. 이번 연습은 쓰기 트래픽을 재생하지 않았다.
    • API 를 빠르고 안정적으로 유지하려고 비용이 큰 작업을 최대한 비동기로 옮기는 데 더 투자한다.
    • 테이블 인덱스를 다시 검토한다. 쓰이지 않는 인덱스가 있고, 데이터베이스가 쿼리에 그 인덱스를 고르면 성능이 떨어질 수 있다.
    • 데이터베이스 대시보드에서 엔드포인트와 시스템별 부하를 더 잘 보여 줘 부하가 어디서 오는지 빨리 찾게 한다. 이번에는 Apple 웹훅 부하가 복구를 막는다는 것을 아는 데 너무 오래 걸렸다.
    • 장애 중에 고객 지원과 고객 커뮤니케이션 담당을 불러 소통을 맡긴다.
    교훈

    RevenueCat 은 처음부터 롤백했으면 더 나았다고 돌아봤다. 사전 연습에서는 데이터 일관성과 쿼리 성능만 보고 쓰기 트래픽을 재생하지 않았다. 쓰기는 인덱스가 얽히지 않아 읽기보다 단순하다고 여겼기 때문이다. 복제를 멈추고 평소처럼 쓰기를 해 봤다면 문제를 찾을 수 있었다. 시퀀스 상태가 복제되지 않는다는 한계를 놓치고 상태도 함께 복제된다고 가정했다. 사전 연습 때는 새 클러스터가 오래 떠 있어 vacuum 과 통계가 이미 끝나 있었기 때문에 ANALYZE 가 없는 문제를 보지 못했다. 시기로는 추수감사절과 블랙 프라이데이 전에 끝내려 했지만, 미국 지원팀 일부가 이미 휴가 중인 민감한 때였으므로 그다음 주로 미뤘어야 했다고 밝혔다.

  3. 증상

    2018년 10월 21일 22:54 UTC 에 내부 모니터링 시스템이 여러 시스템에서 장애가 났다는 알림을 쏟아내기 시작했다. 23:02 UTC 에 첫 대응 팀은 여러 데이터베이스 클러스터의 토폴로지가 예상하지 못한 상태라는 것을 확인했다.

    촉발

    10월 21일 22:52 UTC 에 고장 난 100G 광 장비를 교체하는 정기 유지보수 작업 중 미국 동부 네트워크 허브와 동부 주 데이터센터 사이의 연결이 끊겼다. 연결은 43초 만에 돌아왔다.

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

    22:54 UTC 에 내부 모니터링 시스템이 알림을 내기 시작해 여러 엔지니어가 알림을 분류했다. 23:02 UTC 에 첫 대응 팀이 Orchestrator API 를 조회해 복제 토폴로지에 서부 데이터센터 서버만 남은 것을 확인했다.

    조치
    • 23:07 UTC 에 내부 배포 도구를 수동으로 잠가 더는 변경이 들어오지 않게 했다.
    • 푸시 같은 메타데이터를 쓰는 작업을 멈추려고 웹훅 전송과 GitHub Pages 빌드를 일시 중지했다.
    • 10월 22일 06:51 UTC 까지 여러 클러스터를 미국 동부 데이터센터에서 백업으로 복원했고, 복원된 서버는 서부에서 새 데이터를 복제받기 시작했다.
    • 외부 저장소에서 내려받는 처리량 한계를 피하려고 서부 데이터센터에서 직접 복원하는 방법을 찾았다.
    • 11:12 UTC 에 모든 데이터베이스 프라이머리를 다시 미국 동부에 세웠다.
    • 미국 동부 퍼블릭 클라우드에 MySQL 읽기 복제본을 추가로 띄워 읽기 요청을 더 많은 서버로 나눴고, 복제본 전체의 사용률이 내려가 복제가 따라잡았다.
    • 복제본이 맞춰진 뒤 16:24 UTC 에 원래 토폴로지로 페일오버했다.
    • 밀린 웹훅 이벤트와 Pages 빌드를 처리했다. 웹훅 페이로드 약 200,000건이 내부 TTL 을 넘겨 버려진 것을 발견하자 처리를 멈추고 TTL 을 당분간 늘리는 변경을 배포했다.
    후속 조치
    • 각 클러스터에서 서부로 복제되지 않은 쓰기를 담은 MySQL 바이너리 로그를 분석해, 자동으로 맞출 수 있는 쓰기와 사용자에게 연락해야 하는 쓰기를 가린다.
    • GitHub Pages 빌드가 멈춘 상황에서도 공지 글을 낼 수 있게 한다.
    • 장애 중 복구 예상 시간을 더 정확하게 알린다.
    • Orchestrator 설정을 고쳐 데이터베이스 프라이머리가 리전 경계를 넘어 승격되지 않게 한다.
    • 녹색, 노란색, 빨간색 세 단계만 있던 상태 표시를 새 상태 보고 방식으로 옮겨 플랫폼 구성 요소마다 상태를 보여 준다.
    • 여러 데이터센터에서 트래픽을 받는 active/active/active 구성으로 옮기는 일을 앞당겨, 시설 단위 N+1 이중화로 데이터센터 하나가 통째로 망가져도 사용자에게 영향이 없게 한다.
    • 시스템이 기대는 가정을 더 적극적으로 시험한다.
    • 장애 시나리오를 사용자에게 닿기 전에 검증하는 관행을 들이고, 장애 주입과 카오스 엔지니어링 도구에 투자한다.
    교훈

    GitHub 은 Orchestrator 가 설정대로 움직였지만 애플리케이션 계층은 그 토폴로지 변경을 견디지 못했다고 봤다. 리전 안의 리더 선출은 대체로 안전하지만, 갑자기 생긴 대륙 간 지연이 이번 장애를 키운 큰 요인이었다. 자동 페일오버 설정은 애플리케이션이 기대하는 것과 맞춰야 한다. GitHub 은 이만큼 복잡한 서비스 체계에서는 운영 통제를 조이거나 대응을 빠르게 하는 것만으로는 안정성을 지킬 수 없다고 판단했다. 그래서 가정을 더 적극적으로 시험하고, 장애 시나리오를 사용자에게 닿기 전에 검증하기로 했다. 복구 예상 시간은 모든 변수를 고려하지 못해 틀렸다.

  4. 증상

    2017년 1월 31일 19:00 UTC 무렵 GitLab.com 의 데이터베이스 부하가 올랐고, 많은 사용자가 이슈와 머지 리퀘스트에 댓글을 달지 못했다. 스팸으로 의심되는 부하였고, 잡는 데 몇 시간이 걸렸다.

    촉발

    1월 31일 23:00 UTC 무렵 데이터베이스 부하로 세컨더리의 복제가 멈췄고, 세컨더리를 다시 맞추던 엔지니어가 세컨더리가 아니라 프라이머리에서 PostgreSQL 데이터 디렉터리를 지웠다.

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

    프라이머리에서 데이터 디렉터리를 지운 엔지니어가 스스로 실수를 알아채고 1~2초 만에 삭제를 멈췄다.

    조치
    • pg_basebackup 이 복제 연결이 모자라다고 알리자 max_wal_senders 를 기본값 3 에서 32 로 잠시 올렸고, PostgreSQL 이 재시작을 거부하자 max_connections 를 8000 에서 2000 으로 낮췄다.
    • 엔지니어가 프라이머리에서 데이터를 지우고 있다는 것을 알아채고 1~2초 만에 삭제 작업을 멈췄지만, 약 300 GB 가 이미 지워졌다.
    • 데이터 손실을 가장 줄일 수 있는 유일한 방법으로 장애 6시간 전에 만든 LVM 스냅샷을 쓰기로 하고, 스테이징의 PostgreSQL 데이터 디렉터리를 약 18시간 동안 운영으로 복사해 복원했다.
    • 웹훅 삭제를 거치지 않은 별도 스테이징 데이터베이스를 LVM 스냅샷으로 띄워 웹훅 테이블의 SQL 덤프를 만들고, 복원한 GitLab.com 데이터베이스에 가져왔다.
    • 장애 전에 쓰였을 수 있는 ID 를 다시 쓰지 않도록 모든 데이터베이스 시퀀스를 100,000 씩 올렸다.
    • GitLab.com 을 차례로 다시 열었다.
    • 17:20 UTC 이후에 만든 프로젝트는 NFS 클러스터에 남은 Git 저장소로 가장 기본적인 형태만 복원했고, 이슈와 머지 리퀘스트 같은 데이터는 되살리지 못했다.
    후속 조치
    • 모든 호스트의 셸 프롬프트인 PS1 을 고쳐 호스트와 환경을 더 분명히 구분한다.
    • 백업을 Prometheus 로 모니터링한다.
    • PostgreSQL 의 max_connections 를 알맞은 값으로 둔다.
    • PostgreSQL 의 시점 복구와 연속 아카이빙을 검토한다.
    • 운영 데이터베이스의 LVM 스냅샷을 매시간 뜬다.
    • 운영 데이터베이스에 Azure 디스크 스냅샷을 켠다.
    • 스테이징을 ARM 환경으로 옮긴다.
    • 운영 복제본을 되살린다.
    • PostgreSQL 백업 복원을 자동으로 시험한다.
    • PostgreSQL 복제 문서와 런북을 고친다.
    • PostgreSQL 백업에 pgbarman 을 쓸지 검토한다.
    • 데이터베이스 백업과 실시간 복제에 WAL-E 를 쓸지 검토한다.
    • 스트리밍 방식의 데이터베이스 복원을 만든다.
    • 데이터 내구성을 책임질 담당자를 정한다.
    • 세컨더리를 여러 대 두고 부하를 나누도록 pgpool-II 3.6.1 을 묶고 PostgreSQL 연결 풀링과 부하 분산을 구성한다.
    • 개발자가 데이터베이스 마이그레이션을 시험할 수 있도록 스테이징에서 Rails 마이그레이션을 실행하고 되돌리는 도구를 만든다.
    • 데이터베이스뿐 아니라 GitLab.com 인프라 전체의 복구 절차를 만들고 그 절차의 담당자를 정한다.
    • 공개 백업 모니터링 대시보드를 만들었고, 지금은 pg_dump 백업 데이터만 있지만 데이터를 더 넣는다.
    • 어뷰징 신고와 대응 시스템을 고쳐 스팸 신고로 사용자를 지울 때 데이터를 바로 영구 삭제하지 않게 한다.
    • 앞으로 공개하는 장애 문서에서는 엔지니어의 이름을 가린다.
    교훈

    GitLab 은 장애를 GitLab.com 이 약 18시간 멈춘 문제와 복원이 18시간 넘게 걸린 문제로 나눠 5 Whys 로 분석했다. 세컨더리를 다시 만드는 작업은 자동화되지도 제대로 문서화되지도 않아 손으로 해야 했다. 표준 백업은 PostgreSQL 버전이 맞지 않아 조용히 실패했고, 실패 알림 메일은 DMARC 서명이 없어 거부됐다. 다른 백업 절차를 믿고 Azure 디스크 스냅샷을 켜지 않았다. 백업 절차를 맡은 사람이 없어 아무도 정기적으로 시험하지 않았다. GitLab 은 운영 엔지니어가 특정 명령을 못 쓰게 막는 것보다 재해 복구를 고치고 지금 어느 호스트를 쓰는지 더 분명히 보이게 하는 데 집중하기로 했다. rm 을 더 안전한 별칭으로 바꾸면 실수로 지우는 것은 막지만 디스크 손상처럼 데이터를 잃는 다른 경우는 막지 못한다. 이상적인 환경은 실수해도 영향이 거의 없이 빠르게 복구할 수 있는 곳이고, 그러려면 복구 절차를 정기적으로 해 보고 변경을 쉽게 시험하고 되돌릴 수 있어야 한다.

  5. 증상

    WORKER_JOB_ERROR 오류가 늘었다는 신고가 들어왔다. 이 오류는 파일을 받아 Assembly 를 조율하는 Uploader 와 인코딩을 실행하는 Drone 사이의 통신에 문제가 있다는 뜻이다.

    촉발

    HLS 트래픽이 가파르게 늘었고, 같은 양을 더 빨리 처리하려고 Drone 을 더 많이 띄울 수 있게 되면서 중앙 노드가 바빠졌다. 이를 설명할 코드나 인프라 변경은 찾지 못했고, 이 두 변화가 겹쳐 Redis 병목이 드러났다.

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

    WORKER_JOB_ERROR 오류가 늘었다는 신고가 들어와 문제를 알았다. 모니터링은 Redis 명령 수, 연결 수, 스왑 사용량을 보고 있었지만 대역폭은 보지 않아 포화를 잡지 못했다.

    조치
    • 잃은 메시지를 다시 넣고 하트비트 감시를 느슨하게 하는 임시 조치를 했다. 증상만 막는 조치였고 Assembly 실행 시간이 늘었다.
    • 놓친 Redis 패치가 있는지 확인하고 Redis 를 최신 안정 버전으로 올렸다.
    • 대역폭 제한에 걸린 것을 알고 Redis 클러스터를 두 배인 여섯 대로 늘렸다. 곧 다시 포화되자 세 대를 더 붙였지만 상황은 더 나빠졌다.
    • 읽기 replica 를 하나로 줄였다. 트래픽과 실패율이 바로 떨어졌고 Assembly 가 다시 빨라졌다.
    • 리전마다 Drone 확장에 상한을 두었다. 큰 배치 가져오기는 시간이 더 걸릴 수 있지만 시스템은 안정을 유지한다고 밝혔다.
    후속 조치
    • 포화 수준에 다시 가까워지면 알 수 있도록 로그와 알림을 더 둔다.
    • Redis 노드와 Drone, Uploader 사이의 트래픽을 한곳에 몰리지 않게 나눌 방법을 찾는다.
    • 이미 하고 있는 리전별 샤딩에 더해 Uploader 별 샤딩을 추가한다.
    교훈

    Redis 노드를 늘린 것은 잘못된 판단이었다. 모든 쓰기를 리더 한 대가 받는 구조에서는 노드가 늘수록 리더가 복제로 내보낼 트래픽이 늘어, 더 많은 트래픽을 감당하려면 노드를 오히려 줄여야 했다. 잃은 데이터를 다시 넣을 수 있으므로 팀은 복제가 꼭 필요한지 다시 따져 봤다. 지표는 이미 많이 지켜보고 있었지만 알림을 제대로 걸 수 있는 지표는 몇 개뿐이어서, 고른 지표가 모자랐을 수 있다. 대역폭도 빠져 있었다. 쓰기를 받는 Redis 노드가 하나뿐이면 replica 를 줄이거나 노드를 키워도 시간을 조금 벌 뿐이고, 성장을 버티려면 트래픽을 나눠야 한다.

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

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

원인별5

인증서·자격 증명 만료1건

  1. IL-0490 관리형 데이터베이스에서 자체 MySQL로 옮긴 뒤 이전 직전에 쓴 기록이 새 데이터베이스에 없어 LootLocker 서비스가 저하됐다

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

  1. IL-0308 RevenueCat 이 Aurora PostgreSQL 10 에서 14 새 클러스터로 넘어간 직후 쿼리가 극도로 느려져 대시보드와 SDK 엔드포인트가 세 시간 넘게 실패했다

DNS·네트워크 장애1건

조직
  1. IL-0210 43초 네트워크 단절 뒤 MySQL 프라이머리가 미국 서부로 넘어가 GitHub.com 이 24시간 11분 동안 느려지고 오래된 데이터를 보여 줬다
    GitHub2018

운영 실수2건

  1. IL-0218 복제를 다시 맞추다 PostgreSQL 프라이머리의 데이터 디렉터리가 지워지고 백업이 작동하지 않아 GitLab.com 이 약 18시간 멈추고 데이터를 잃었다
    GitLab2017
  2. IL-0319 mysql2 를 다시 적재하려고 데이터베이스를 지우는 동안 mysql1 의 데이터베이스도 함께 지워졌다

용량 한계1건

  1. IL-0296 Transloadit 의 us-east 리전 Redis 클러스터가 대역폭에 막혀 작업과 하트비트를 잃었다