Incident Library
적용된 필터 증상노드 디스크 가득 참기여 요인수동 조치 악화모두 풀기검색어 없이 필터만 적용한 목록입니다. 최근 사례부터입니다.
추천 필터 검색하면 검색어에서 찾은 분류 값이 여기에 나옵니다.

그래프

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

사례3건

3건 중 1~3번째

  1. 증상

    learn.mit.edu 가 멈췄다는 보고가 Sentry 이슈 링크와 함께 올라왔다. MIT Learn 의 운영 데이터베이스인 RDS PostgreSQL 인스턴스가 쓸 수 있는 저장 공간을 모두 써 버린 상태였고, 사이트는 503 과 504 오류를 냈다.

    촉발

    정기 릴리스 절차로 배포한 변경이 페이지 응답의 메인 쿼리 안에 집계를 넣었다. DRF 는 페이지 응답의 count 칸을 SELECT COUNT * ($QUERY) 로 계산하므로, 운영의 데이터 규모에서 이 쿼리가 임시 파일을 대량으로 만들었다.

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

    엔지니어가 장애를 보고하며 Sentry 이슈를 연결했다. 이어 다른 엔지니어가 운영 데이터베이스의 저장 공간이 바닥난 것을 확인했고, FreeStorageSpace 지표와 Sentry 에 쌓인 504 도 같은 상황을 보여 줬다.

    조치
    • 쿼리 패턴 변경을 쓴 엔지니어가 그 변경이 원인임을 확인하고 릴리스를 롤백했다.
    • 데이터베이스가 버퍼에 쌓인 WAL 파일을 따라잡아 비울 여유를 주려고 읽기 복제본을 삭제했다.
    • AWS 지원의 도움을 받아 백업이 끝난 뒤 오래 돌던 쿼리를 안전하게 종료했다. pg_stat_activity 에서 state = 'active' 이고 시작한 지 10분이 넘은 쿼리를 pg_terminate_backend(pid) 로 끝내자 저장 공간과 처리 여유가 돌아왔다.
    후속 조치
    • 운영 learn 데이터베이스에 enhanced analytics 를 켜는 방안을 검토한다.
    • 플랫폼 엔지니어링 문서 사이트에 롤백 절차를 적는다.
    • 장기적으로는 새로 만드는 릴리스 관리 체계에서 롤백을 쉽게 할 수 있게 한다.
    • 운영 데이터베이스의 DiskQueueDepth 에 알림을 걸되 너무 자주 울리지 않게 한다.
    • API 와 사이트의 응답 시간이 평소보다 30% 넘게 높아지면 알림을 보낸다.
    • 운영 데이터베이스 장애를 예제로 삼아 게임데이 훈련을 한다.
    • 장애 관리 도구 Rootly 를 써서 장애 때 소통을 한 채널에 자동으로 모으고 장애 기록을 자동으로 남긴다.
    • 장애 대응 런북을 가볍게 만든다. 장애가 나면 Zoom 통화를 열고, 당번 엔지니어가 지표가 평소 수준으로 돌아오는지 지켜보며, 소통 담당을 따로 두어 이해관계자의 문의가 핵심 대응자를 방해하지 않게 한다.
    • 오래 도는 쿼리를 종료하는 SQL 과, 이 SQL 을 고쳐 아주 오래 도는 쿼리만 골라 종료하는 SQL 을 운영 Postgres 런북에 넣는다.
    • Learn Resource View Event 모델이 지금은 건수를 세는 데만 쓰이므로 다시 설계해야 한다는 이슈를 쓴다.
    • 익명화한 운영 데이터 생성 도구로 RC 환경의 데이터 양을 운영 수준까지 늘린다. 운영 데이터를 익명화해 담은 운영 규모의 부하 시험 환경을 만들고, 이해관계자도 시험에 쓰는 RC 에 영향이 없도록 인프라를 분리한다.
    • 조회 수를 미리 계산해 둔 열에서 읽도록 고쳐 배포했다. 영향을 받던 API 의 운영 응답 시간이 약 13~15초에서 150~200ms 로 줄었다.
    교훈

    이 변경은 가장 시니어인 엔지니어 두 명이 꼼꼼히 리뷰했지만 로컬과 RC 환경에서는 아무 문제도 드러나지 않았다. 운영의 데이터 규모와 시스템 부하가 크게 달랐고, 효율적이라고 여긴 COUNT 집계가 디스크 사용량을 폭증시킬 것이라는 점은 당시 시스템 상태만 보고는 알기 어려웠다. 그래서 운영과 같은 규모의 데이터로 부하를 시험할 환경이 필요하다고 팀은 결론지었다. AWS 지원은 ORM 쿼리 변경을 운영 수준의 데이터를 담은 스테이징에서 시험하고, EXPLAIN ANALYZE 로 실행 계획과 예상 자원 사용을 보며, 시험 중 log_temp_files 로 임시 파일 생성을 지켜보라고 권했다. 폭주하는 쿼리를 막도록 temp_file_limit 를 설정하고, 실행 계획에 따라 work_mem 이나 shared_buffers 를 조정하되 메모리를 너무 쓰면 out of memory 로 장애 조치가 일어날 수 있다는 점도 짚었다. 임시 파일을 많이 쓰는 작업에는 임시 파일을 EBS 대신 로컬 NVMe 에 두는 RDS Optimized Reads 를 고려하라고 했다.

  2. 증상

    가용 영역 장애 대비 훈련을 마친 뒤 정리 단계에서 런북대로 Kafka 브로커를 없애자, 운영 환경의 여러 토픽 파티션이 리더 없이 남았다. 망가진 파티션만 배정된 팀과 환경은 데이터 수집이 실패했다.

    촉발

    12월 5일 운영 환경에서 가용 영역 장애 훈련을 마친 뒤, 워크로드 균형을 되돌리는 정리 단계를 런북대로 진행하다 Kafka 브로커를 일부러 없앴다. 이때 동기화가 끝나 있던 기존 브로커까지 함께 없어졌다.

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

    대응자들은 알림이 쏟아지는 가운데 수집 서비스 Shepherd 의 크래시 루프를 한 시간 넘게 지나서야 알아챘다. 토요일 아침에는 대응자들이 Kafka 밸런싱 작업이 나아가지 않고 디스크 사용량이 줄지 않는 것을 봤다. 메타데이터 토픽을 고치자 SLO 처리 트리거가 약 18시간 늦은 데이터를 알렸다.

    조치
    • 망가진 파티션을 프로듀서 쪽에서 읽기 전용으로 돌려 수집 서비스의 크래시 루프를 멈췄다.
    • 파티션 재배치를 돌려 고객들의 수집을 정상으로 되돌렸다.
    • Kafka autobalancer 를 끄고, 균형을 일부 되찾는 수동 재배치 계획을 세워 밤새 돌렸다.
    • 자정 무렵 PT 에 브로커 디스크가 너무 빨리 차자 Kafka 의 로컬 보존 기간을 줄이고 긴 보존은 S3 tiered storage 에 맡기려 했다.
    • _confluent-tier-state 와 __consumer_offsets 토픽의 깨진 파티션을 고쳤다. 그러자 막혀 있던 SLO 처리 서비스가 늦은 데이터를 따라잡기 시작했다.
    • 토요일 아침 7시 PT 에 디스크 여유 공간이 5.07% 일 때 수집을 껐다. 디스크 사용량은 멈췄지만 줄지 않았다.
    • tiered storage 를 끄자 디스크 공간이 바로 돌아왔다. 2021년 예전 장애 때 통했던 방법이었다.
    • 수집을 다시 열었고, 이때 고객 영향이 끝났다.
    • 그날 늦게 완전히 망가진 Retriever 토픽 파티션을 손으로 고쳐 잘라 내고 읽기 전용으로 두었다. Retriever 가 offset 초기화를 감당하지 못해 오래된 데이터를 한동안 조회할 수 없었지만 데이터를 잃지는 않았다.
    • Activity Log 가 Kafka 로 이벤트를 보내지 못하게 되자 Honeycomb MySQL 읽기 전용 복제본의 binlog 보존 기간을 늘렸다.
    • offset 이 망가졌어도 Retriever 노드가 죽지 않고 대기 상태로 남아 오래된 데이터를 조회할 수 있게, 작은 수정 여러 개를 넣었다.
    • 금요일 정오 무렵 Storage 팀이 Retriever 의 offset 초기화 장치가 동작하게 만들었다.
    • 새 Kafka 클러스터로 옮기는 마이그레이션을 화요일에 두 시간 만에 큰 문제 없이 끝냈고, 신호 지연은 많아야 한 시간이었다.
    • 새 복제본으로 binlog 보존 기간을 늘리려던 방법이 통하지 않자, 12월 9일 화요일 시점의 인스턴스를 띄워 그때부터 복제해 Activity Log 손실을 줄였다.
    • 옛 Kafka 클러스터를 정리하고 EU 리전의 Activity Log 일부를 따라잡았다.
    후속 조치
    • 조직이 커지는 만큼 여러 곳에 흩어진 정보를 더 잘 모은다.
    교훈

    Honeycomb 은 "다음에는 Kafka 클러스터를 없애지 말자" 는 설명에서 멈추지 않고 더 넓은 영향을 봐야 한다고 밝혔다. 사전 운영 클러스터는 노드가 적어 구조상 이 문제를 재현하기 어려웠고, 운영과 더 닮은 클러스터에서 시험했다면 잡을 가능성이 훨씬 높았다. 이번 장애에 얽힌 요소 상당수는 이미 알려져 있었고 우회 계획, RFC, 안전하게 훈련하는 절차를 적은 문서도 있었지만, 쓴 사람 말고는 그런 문서가 있는지 몰랐거나 검색으로 찾을 수 없었다. 마감이 멀고 범위가 불확실한 내부 작업은 급한 작업에 밀려 거듭 미뤄지기 쉽다. 핵심 개입 상당수는 이제 그 구성 요소를 맡지 않는 사람들에게서 나왔고, 이는 팀 구성과 기술 구성 사이에 틈이 벌어졌다는 뜻이다. 에스컬레이션을 더 빨리 했어야 했다는 의견과 대응을 지속 가능하게 해야 한다는 의견이 함께 나왔다. 선임 엔지니어들이 들어오자마자 저절로 지휘를 잡는 문제와, 베타 기능의 손실을 너무 자세히 알린 대외 소통도 과제로 남았다.

  3. 증상

    한 셀의 Kafka 브로커가 응답하지 않았다. 몇 시간 뒤 여러 셀의 Kafka 브로커 디스크가 차면서 브로커가 하나둘 멈췄고, US 리전의 많은 고객이 데이터 수집과 알림을 쓸 수 없었다.

    촉발

    엔지니어가 응답하지 않는 Kafka 브로커를 수동으로 재시작했는데, 같은 시각 자동 복구도 돌아 클러스터가 오래 성능 저하 상태에 머물렀다. 엔지니어는 밀린 데이터를 지키려고 장애 대응 도구로 Kafka 데이터 보존 기간을 크게 늘렸고, 이 변경이 문제가 난 셀뿐 아니라 모든 셀에 적용됐다.

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

    7월 29일 아침 엔지니어링 팀이 한 셀의 Kafka 브로커가 응답하지 않는 것을 봤다. 나중에 디스크 여유 공간이 줄어들 때 모니터링 시스템이 알림을 보냈지만, 같은 시각 다른 여러 시스템이 관계없는 경고를 내고 있어 엔지니어들은 이 알림을 놓쳤다.

    조치
    • 엔지니어링 팀이 응답하지 않는 Kafka 브로커를 수동으로 재시작했다. 같은 시각 자동 복구도 돌았고, 두 작업 모두 결국 무사히 끝났다.
    • 브로커의 디스크 공간 문제를 해결했다. 그 뒤에도 Kafka 문제가 여러 셀에 넓게 퍼져 있어 서비스 복구에 시간이 걸렸다.
    교훈

    셀 격리는 넓은 장애를 막는 가장 강한 보호 수단이다. 평소 운영뿐 아니라 긴급 도구도 이 격리를 지켜야 한다. 긴급 대응 도구는 혼란스러운 상황에서도 안전하게 쓸 수 있어야 하고, 그러면서도 필요한 기능은 빠짐없이 갖춰야 한다. 사람의 주의력은 한정되어 있으므로 장애 대응 절차와 알림을 계속 다시 따져 엔지니어의 주의가 가장 급한 신호로 가게 해야 한다.

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

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

원인별2