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

그래프

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

사례6건

6건 중 1~5번째

  1. 증상

    2023-08-11 13:36 BST 에 여러 서비스에서 모든 데이터베이스 트랜잭션이 실패한다는 알림이 들어왔다. 데이터베이스를 다시 시작하려 했지만 공간이 없다며 올라오지 않았다. 메일도 나가지 않았다.

    촉발

    13:15 BST 에 cron 인스턴스 메모리를 1gb 에서 8gb 로 늘려 밀려 있던 보존 기간 정리 작업을 돌렸다. destroy_all 이 연결된 레코드까지 한꺼번에 많이 지우면서 데이터베이스 디스크가 빠르게 찼다.

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

    13:00 BST 정기 점검에서 데이터베이스가 평소보다 큰 것을 먼저 봤다. 13:36 에는 여러 서비스에서 모든 데이터베이스 트랜잭션이 실패한다는 알림이 곧바로 들어왔다. 상태 페이지 두 개는 장애를 잡지 못했다. 업스트림 제공자는 저장 공간이 99% 찼을 때 자동으로 알림을 받았다.

    조치
    • Postgres 가 관리형 서비스였으므로 13:37 BST 에 곧바로 업스트림 제공자 지원팀에 연락했다.
    • 13:40 에 Twitter 와 Mastodon 으로 사용자에게 장애를 알렸다. 상태 페이지가 자동으로 바뀔 것으로 생각했지만 바뀌지 않았다.
    • 제공자의 답을 기다리는 동안 13:45 에 전체 장애 복원 절차를 시작해 6시간 전 오프사이트 백업을 새 데이터베이스 인스턴스에 준비했다.
    • 15:50 에 제공자의 이전이 끝나 더 큰 데이터베이스 인스턴스로 옮겨졌고 메일이 다시 나갔다.
    • 백업에서 시험해 고친 쿼리로 운영의 오래된 데이터를 하루 단위로 직접 지웠다. 그동안 메모리, 데이터베이스 크기, 지표를 가까이 지켜봤다.
    후속 조치
    • 매일 도는 정리 작업을 in_batches(of: 50) 로 바꿔 한 번에 50건씩만 지우게 했다. ruby 메모리 요구량과 postgres 부하가 줄었다.
    • 정리 작업을 하루 한 번이 아니라 네 번 돌게 바꿔 한 번 실행의 영향을 줄였다.
    • 성장 여유가 훨씬 많은 더 큰 데이터베이스 인스턴스로 옮겼다.
    • 모든 cron 작업에 cron 모니터링을 적용했다.
    • 상태 페이지가 헬스 체크 엔드포인트 /health 를 보게 바꿨다. 이 엔드포인트는 데이터베이스 접근을 포함해 여러 가지를 확인하고 하나라도 실패하면 500 오류로 응답한다.
    • 자동 장애 조치를 위한 핫 레플리카 데이터베이스를 검토한다.
    교훈

    장애는 여러 원인이 겹쳐 났다. 오래된 데이터를 지우는 cron 작업이 조용히 실패해 데이터가 쌓였다. 이 작업은 평소 하루치 양이었다면 문제없었겠지만 지나치게 단순하게 짜여 있었다. 데이터베이스 요금제는 처음부터 성장 여유가 부족했다. 상태 페이지는 장애를 잡지 못했다. MailPace 는 중요한 서비스마다 제공자를 여럿 두라고 권했다. 또 장애를 감지해 메일을 예비 제공자로 보내는 오픈 소스 아웃바운드 SMTP 프록시 Outgoer 를 만들고 있다고 밝혔다.

  2. 증상

    2022년 3월 16일 14:09 UTC, 최대 부하 시간대에 mysql1 데이터베이스의 부하가 늘면서 데이터베이스 프록시가 최대 연결 수에 닿았다. GitHub 의 모든 쓰기 작업이 동작하지 않았다.

    촉발

    최대 부하 시간대에 공용 MySQL 클러스터 mysql1 의 부하가 늘어 데이터베이스 프록시가 최대 연결 수에 닿았다.

    원인
    구성 요소
    기여 요인
    조치
    • 정상인 복제본으로 페일오버해 3월 16일 장애에서 복구했다.
    • 3월 17일 미리 한 페일오버 뒤 새 주 노드에 생긴 연결 문제를 풀려고 연결을 재설정했다.
    • 3월 17일 장애 중에 부하 패턴을 찾아 인덱스를 추가해 주된 성능 문제를 고쳤다.
    • 3월 22일 클라이언트 연결이 실패하자 다시 주 노드를 페일오버해 복구했다.
    • 3월 23일 같은 부하 특성으로 클라이언트 연결이 실패하자 다시 주 노드를 페일오버해 복구했다.
    • 3월 23일 부하를 줄이려고 웹훅 트래픽을 제한했다.
    후속 조치
    • 다른 대책을 더 찾는 동안 최대 부하 시간대에 웹훅 트래픽 제한을 계속 써서 같은 장애가 다시 나지 않게 한다.
    • 최대 부하 시간대의 mysql1 부하 패턴을 점검하고, 그 결과에 따라 성능 수정을 차례로 한다.
    • 부하를 줄이고 페일오버 시간을 줄이려고 mysql1 의 트래픽을 다른 데이터베이스로 옮긴다.
    • 변경 관리 절차를 검토한다. 특히 운영 환경에 부하가 높을 때의 모니터링과 변경을 살핀다.
    • 플랫폼 성장에 맞춰 데이터베이스 샤딩과 하드웨어 확장을 비롯한 인프라 확장을 이어 간다.
  3. 증상

    2019년 2월 4일 05:35 UTC 부터 Mandrill 이 대기열에 쌓인 메일의 80% 만 보냈다. 첫 예외는 일요일 밤에 로그에 남았지만 다른 시스템의 관계없는 예외에 묻혀 중앙 오류 보고에서 눈에 띄지 않았다.

    촉발

    Mandrill 의 키 해시 알고리즘이 shard4 에 쓰기를 더 많이 몰아 이 샤드의 autovacuum 이 밀렸거나 실패했고, 2019년 2월 4일 05:35 UTC 에 XID 가 상한에 닿아 데이터베이스가 안전 종료 모드로 들어갔다.

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

    첫 예외는 일요일 밤에 로그에 남았지만 다른 시스템의 관계없는 예외에 묻혀 중앙 오류 보고에서 늦게 발견됐다. 11:58 UTC 에 Mandrill 엔지니어가 조사를 시작했고, shard4 의 부하 급증을 쫓다가 12:56 UTC 에 랩어라운드를 찾았다.

    조치
    • 14:16 UTC 에 shard4 를 단일 사용자 모드로 띄우고 VACUUM 을 시작했다.
    • VACUUM 이 며칠 걸릴 것으로 보여 설정을 바꿔 속도를 높인 뒤 다시 시작했다.
    • VACUUM 이 도는 동안 데이터베이스 덤프와 복원을 시작했고, 속도를 높이려고 TB 단위인 Search 와 Url 테이블을 뺐다.
    • 실패한 작업과 로그로 디스크가 모자라자 Mandrill 앱 서버들의 스토리지 볼륨을 교체했다.
    • shard4 에 있던 작업 대기열 테이블을 살아 있는 다른 샤드로 옮겨 작업이 처리되게 하려 했다.
    • 잠긴 데이터베이스에서 테이블을 비우면 그 XID 가 풀린다는 것을 확인한 뒤 2월 5일 19:12 UTC 에 Search 와 Url 테이블을 비웠고, VACUUM 이 약 한 시간 뒤에 끝났다.
    • 21:36 UTC 에 밀린 메일 발송을 시작했다.
    • 22:40 UTC 에 XID 랩어라운드 알림을 새로 걸었다.
    교훈

    Mailchimp 는 대응을 늦춘 요인으로 다섯 가지를 들었다. Mandrill 시스템과 모니터링을 알고 접근할 수 있는 사람이 몇 명뿐이었다. Mandrill 의 로그 기록은 로컬에 쓸 수 있는 디스크에 기댔다. 잘못된 API 요청 로그와 실제 애플리케이션 오류를 구분하기 어려웠다. 작업 상태가 잘 보이지 않았다. 디스크 공간 문제로 원인 분석을 돕는 부분 배포가 위험했다. 잘된 점으로는 인시던트 지휘관을 중심으로 한 긴밀한 조율, 3시간 교대와 인수인계, 기록 담당과 기술 연락 담당 같은 역할 지정, 주기적인 요약과 결정 목록을 들었다. 화상 회의로 다시 모여 상황을 따져 본 것이 테이블을 비우는 해법으로 이어졌다. 대기 메일을 48시간 뒤에 지우는 기본 동작이 다가오자 더 과감한 방법을 검토하게 됐다. Mandrill 이 클라우드에서 돌아 스토리지를 빨리 늘릴 수 있었던 것은 운이었다. 지울 수 있는 데이터가 있었고 그 가운데 VACUUM 을 붙잡던 가장 큰 테이블이 있었던 것도 운이었다.

  4. 증상

    Basecamp 3 가 읽기 전용 상태가 되었다. 사용자는 기존 메시지, 할 일 목록, 파일을 볼 수 있었지만 새 내용을 넣을 수 없었고 기존 내용도 고칠 수 없었다.

    촉발

    사용량이 아주 많은 events 테이블이 데이터베이스의 한도인 2,147,483,647 에 닿아, 이 테이블에 새 이벤트를 쓸 수 없게 되었다.

    원인
    구성 요소
    기여 요인
    조치
    • Rails 5.1 이 모든 테이블의 새 기본값으로 바꾼 것과 같은 변경을 Basecamp 의 테이블에 적용해 레코드 한도를 9,223,372,036,854,775,807 로 올렸다.
    교훈

    37signals 는 이 장애를 피할 수 있었다고 밝혔다. 장애 전 며칠 동안 events 테이블의 용량을 늘리는 작업을 하면서도 여유가 줄어드는 속도를 제대로 따지지 않았다. 37signals 의 CTO 는 Rails 5.1 이 새 기본값을 발표했을 때 회사의 데이터베이스 스키마를 더 주의 깊게 살폈어야 했다고 썼다. 해결 작업을 시작한 뒤에도 끝까지 챙기며 꼭 필요한 질문을 했어야 했다고 덧붙였다.

  5. 증상

    2월 9일 수요일 12:30PM PT 부터 Instapaper 사용자가 저장한 글을 담는 MySQL 의 bookmarks 테이블에 새 항목을 넣으면 오류가 나기 시작했다. Instapaper 서비스는 2월 10일 목요일 7:30pm PT 까지 멈췄다.

    촉발

    2월 9일 수요일 12:30PM PT 에 bookmarks 테이블이 2TB 파일 크기 한도를 넘었다.

    원인
    구성 요소
    기여 요인
    조치
    • Pinterest SRE 팀의 안내로 Instapaper 운영 데이터베이스를 i2.8xlarge 인스턴스의 5.5TB RAID-0 디스크에 덤프했다. 첫 시도는 24시간, 병렬로 돌린 두 번째 시도는 10시간이 걸렸다.
    • 덤프가 너무 오래 걸리자 아카이브 접근을 제한한 채 동작하는 인스턴스를 약 6시간 만에 만들어, 31시간의 다운타임 끝에 운영에 올렸다.
    • 옛 데이터베이스의 Aurora 읽기 복제본을 만들었다. Aurora 는 Instapaper 코드로 충분히 시험해 보지 않아 위험하다고 봤지만 만들기는 쉬웠다. 약 24시간 만에 끝났다.
    • 새 MySQL RDS 인스턴스를 만들어 보조 인덱스 없이 데이터를 모두 넣었다. 8시간이 걸렸다. 그 뒤 보조 인덱스 세 개를 하나에 약 16시간씩 만들었다.
    • Amazon 엔지니어가 실패한 운영 데이터베이스에 ext4 파일 시스템을 마운트하고 ext3 파일 시스템에서 ext4 파일 시스템으로 rsync 를 약 8시간 돌려, 데이터와 인덱스가 모두 있는 ext4 데이터베이스 인스턴스를 만들었다.
    • RDS 엔지니어들이 임시 운영 데이터베이스의 바이너리 로그로 새 ext4 데이터베이스에 행 기반 복제를 걸어 목요일부터 월요일까지의 변경을 맞췄다. 약 3시간이 걸렸다.
    • 새 데이터베이스를 마스터로 승격하고 애플리케이션 코드가 새 데이터베이스를 가리키도록 배포했다.
    후속 조치
    • Instapaper 전체 장애가 나면 Pinterest 의 SRE 팀에 바로 에스컬레이션하는 절차를 만든다.
    • MySQL 백업 시험 주기를 석 달에 한 번에서 한 달에 한 번으로 늘린다.
    • Pinterest 의 SRE 팀과 함께 이런 장애가 다시 나면 복구할 수 있는 절차를 마련한다.
    교훈

    팀이 알지 못했고 볼 수도 없었던 파일 시스템 한도 때문에 운영 데이터베이스뿐 아니라 모든 백업까지 쓸 수 없게 됐다. 호스팅된 인스턴스에는 MySQL 로만 접근할 수 있어서 rsync 같은 파일 시스템 수준의 해결책은 Amazon 엔지니어의 도움 없이는 쓸 수 없었다. 완벽하게 대응했어도 진단부터 데이터베이스 재구축까지 다운타임은 최소 10시간이었을 것이다. 이 문제는 미리 내다보고 막기 어려웠지만, 이런 장애를 위한 재해 복구 계획이 없어 다운타임과 복구 시간이 필요 이상으로 길어졌다. 데이터베이스를 다시 만드는 데 며칠이 걸린다는 것을 알았다면 곧바로 제한된 서비스 복구로 들어가 첫날의 다운타임을 크게 줄일 수 있었다. Pinterest 안에서, 그리고 AWS 팀과 더 잘 소통했다면 쓸 수 있는 자원을 더 잘 활용했을 것이다. 글쓴이는 다른 회사가 호스팅하는 기술이라도 매일 운영에 쓰는 기술의 한도를 이해하는 것이 자신의 책임이라고 밝혔다.

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

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

원인별1

용량 한계6건

  1. IL-0326 MailPace 의 관리형 Postgres 데이터베이스 디스크가 가득 차 데이터베이스가 두 시간 넘게 내려갔다
  2. IL-0302 GitHub 의 공용 MySQL 클러스터 mysql1 이 최대 부하 시간대에 연결이 바닥나 쓰기 작업이 네 번 멈췄다
    GitHub2022
  3. IL-0211 Mandrill 의 PostgreSQL 샤드 하나가 트랜잭션 ID 랩어라운드를 막으려고 쓰기를 멈춰 약 40시간 동안 메일 발송이 줄었다
  4. IL-0300 Basecamp 3 의 events 테이블이 데이터베이스 한도에 닿아 서비스가 다섯 시간 가까이 읽기 전용이 되었다
  5. IL-0334 RDS MySQL 의 bookmarks 테이블이 2TB 파일 크기 한도에 닿아 INSERT 가 실패하고 Instapaper 가 31시간 동안 멈췄다
  6. IL-0320 주 MySQL 서버의 디스크가 가득 차 메일 발송, API, 웹 화면이 지연됐다