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

사례3건

3건 중 1~3번째

  1. 증상

    2025-03-12 10:58 UTC 부터 백엔드 응답 시간이 높다는 알림이 들어왔다. 3월 12일과 13일 이틀 동안 mw-api-int, mw-parsoid, mw-jobrunner 에서 지연이 커지고 데이터베이스 오류가 늘었다. External Storage 클러스터의 부하와 연결 수도 크게 늘었다.

    촉발

    mw-api-int, mw-parsoid, mw-jobrunner 를 PHP 8.1 로 옮기는 예정된 Scap 배포가 장애를 일으켰다. 3월 12일 10:44 UTC 에 1126607[puppet] 과 1126650 [deployment-charts] 를, 3월 13일 11:15 UTC 에 1127476[puppet] 과 1127478[deployment-charts] 를 배포했다.

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

    3월 12일 10:58 UTC 에 백엔드 응답 시간이 높다는 알림이 들어오기 시작했다. 처음 세운 가설은 특정 네트워크나 클라이언트의 많은 트래픽, 잘못 실행된 예약 작업, 자원을 많이 먹는 changeprop-jobqueue 작업이었다. 원인을 가리켰을 MediaWikiMemcachedHighErrorRate 알림은 logstash-prometheus 파이프라인이 밀려 빠지거나 곧바로 회복됐다. 장애 중에는 알림 78개가 울리고 있어서, 그 알림이 울렸더라도 부수 증상으로 보고 넘겼을 가능성이 컸다.

    조치
    • 3월 12일 13:19 UTC 에 cirrus-streaming-updater 의 SUP 병렬도를 낮추는 패치 1126988[deployment-charts] 를 배포했다.
    • 13:33 에 1127000[deployment-charts] 로 changeprop-jobqueue 의 categoryMembershipChange 작업 동시성을 낮췄다.
    • 13:44 에 1126607[puppet] 과 1126650 [deployment-charts] 를 되돌리고 Scap 을 다시 돌렸다.
    • 3월 13일 11:34 UTC 에 changeprop-jobqueue 를 롤링 재시작했다.
    • 11:43 에 mw-api-int 를 롤링 재시작했다.
    • 11:44 에 1127500[deployment-charts] 로 changeprop-jobqueue 의 categorymembership 작업을 껐다.
    • 11:46 에 1127476[puppet] 과 1127478[deployment-charts] 를 되돌렸다.
    • 11:58 에 되돌린 내용을 반영하려고 mw-api-int 를 다시 배포했다.
    • 12:07 에 mw-api-int 의 레플리카 수를 늘렸다.
    • 12:28 에 되돌린 내용을 반영하려고 mw-jobrunner 를 다시 배포했다.
    • 14:06 에 되돌린 내용을 반영하려고 mw-parsoid 를 다시 배포했다.
    후속 조치
    • 장애 때 channel:Memcached 로 보내는 메시지 양을 줄인다.
    • Scap 에 helm 롤백 기능을 넣는다.
    • -Dbuild_mw_container_image:False 로 실행할 때도 Scap 이 helmfile-defaults 를 갱신해야 하는지 검토한다.
    • MediaWiki 이미지에서 envvars.inc 를 뺄지 검토한다.
    • 서로 관련된 구성 요소를 한꺼번에 보여 주고 따라갈 링크를 담은 "Why" 대시보드를 만들지 검토한다.
    • 장애 대응 조율을 개선한다. 누가 무엇을 맡았는지, 누가 대응에 들어오고 나갔는지 장애 조율자가 알 수 있어야 한다. 또 맥락 없는 의견과 대응과 관계없는 논의로 채널이 시끄러워지지 않아야 한다.
    • 장애 중에 MediaWiki 개발자와 연락해 개발자의 관점을 바로 들을 수 있게 한다.
    교훈

    Wikimedia 는 기술적 원인보다, 3월 12일 장애 때부터 MediaWiki 배포 세 곳이 Memcached 클러스터에 닿지 못하고 있다는 것을 알아채지 못한 이유가 더 중요하다고 봤다. 알림에 연결된 대시보드는 무엇이 일어나는지만 보여 줬다. Wikimedia 는 서로 의존하거나 영향을 주는 구성 요소를 함께 보여 주는 대시보드가 있었다면 달랐을 것이라고 적었다. 예를 들어 SQLBlobStore 키는 External Storage 와 바로 이어져 있다. 원인을 가리킬 알림은 곧바로 회복됐다. 그 알림이 울렸더라도 알림 78개 사이에서는 부수 증상으로 봤을 수 있었다. 응답자가 많았지만 누가 무엇을 하는지, 누가 대응에 들어오고 나갔는지 분명하지 않아 장애 조율자가 조율하기 어려웠다. 외부 사용자 영향을 제대로 가늠하지 못해 실제보다 심각하게 여겼다. trace.wikimedia.org 도 장애 중에 쓰지 않았다.

  2. 증상

    스마트리스트 프리셋 데이터를 고쳐 쓰는 배치를 20분쯤 돌린 시점에 504 Gateway Timeout 에러가 갑자기 늘었다는 알림이 왔다. 작업은 03:00 UTC 조금 넘어 시작했다.

    촉발

    검색 사양 변경에 맞춰 스마트리스트 프리셋 데이터인 初回予約の顧客 와 要フォロー顧客 의 검색 조건을 새 조건으로 고쳐 쓰는 배치를 실행했다. 프리셋 이름은 그대로였지만 검색 파라미터가 달라져 새 검색 쿼리를 타게 됐다.

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

    고쳐 쓰기 배치를 시작하고 20분쯤 지나 504 에러가 늘었다는 알림으로 알았다. 작업 중 보던 라이터 인스턴스 지표에는 변화가 없었다.

    후속 조치
    • DB 설계부터 다시 봤고, 이번 글의 인라인 뷰 검색 로직은 더 이상 쓰지 않는다.
    • 이 API의 EXPLAIN을 확인해 훑는 행 수가 예상보다 많지 않은지 검사하는 테스트를 더했다.
    • 해당 로직의 실제 실행 시간을 재기 쉬운 환경을 갖췄다.
    교훈

    실행 계획을 보고 실제 데이터로 동작을 확인해도, 멀티테넌트 환경에서는 테넌트 인덱스만으로 크게 좁혀지는 것처럼 보여 실제로 훑는 양을 놓칠 수 있다. 검증은 양극단만이 아니라 일부만 느린 경우까지 봐야 한다. 작업 중 모니터링하는 대상이 실제 부하가 걸리는 곳인지도 확인해야 한다. 일정을 너무 서두르면 이런 부분이 빠지기 쉽고, 결국 일정이 늦어지고 사용자에게 피해를 준다.

  3. 증상

    2021년 3월 6일 11시 길드 업데이트 점검을 마친 뒤 데이터베이스 CPU 사용량이 예상보다 조금 높았다. 11시 30분쯤 24코어 머신인 데이터베이스 노드 하나가 24코어를 모두 쓰며 CPU 사용량이 최대치에 이르렀고, 같은 시각 서버 지표에서 상당한 양의 에러가 보이기 시작했다. 곧 다른 두 노드에서도 CPU 사용량 이상이 나타났다.

    촉발

    길드 업데이트 점검 뒤 서비스를 열자 모든 유저가 곧바로 새 기능을 썼고, 분석용 테이블에 guild-<uuid> 형식의 Primary Key가 매우 빠르게 쓰였다. 리팩토링으로 Primary Key 형식이 바뀐 테이블도 있었다.

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

    모니터링 중 한 노드의 CPU 사용량이 최대치에 이르렀다는 소식과 함께 서버 지표에서 에러가 관측돼 알았다. 이후 노드 문제는 Host Status Check 실패 슬랙 알림과 이상 로그 감지 채널의 알림으로 알았다.

    조치
    • 기존 유저를 내보내지 않고 새 로그인만 막아 입장 인원을 0명으로 둔 대기열처럼 썼고, 지표를 보며 막고 풀기를 반복해 동시 접속자 수를 조절했다.
    • 오후 2시 50분 노드 여러 대가 health check를 통과하지 못하자 아무도 게임을 할 수 없는 전체 긴급 점검에 들어갔다.
    • 전체 데이터베이스 백업이 멈추자 테이블 단위로 백업했다. 부하가 몰린 것은 특정 테이블의 일부 Range였고 그 테이블은 다른 테이블로 복구할 수 있었기 때문이다.
    • 서비스를 열기 전에 데이터베이스 부하를 최대한 줄이려고 플레이 기록 저장을 잠시 멈췄다.
    • 오후 6시 반쯤 문제가 된 테이블들에 Split 작업을 시작해 부하가 모든 노드에 고르게 나뉘도록 했다.
    • Host Status Check에 실패하고 filemap_fdatawait_range_keep_errors 로그가 나온 노드를 클러스터에서 빼기로 하고, Range 분리와 그 노드의 Decommission을 함께 진행했다. Decommission이 끝나자 복제되지 않은 Range가 0이 되고 지표가 안정됐다.
    • 서비스를 다시 연 뒤 한 노드가 CPU를 100% 쓰자 다시 대기열 방식으로 접속을 조절해 CPU 사용량을 안정시켰다.
    • 같은 노드가 거듭 CPU 100%에 이르러 노드 자체의 문제로 보고 그 노드를 종료해 문제를 끝냈다.
    교훈

    일반 RDBMS에서는 Primary Key prefix를 바꿔도 큰 문제가 되지 않지만, 분산 처리를 하는 CockroachDB의 프로덕션 클러스터에서는 이런 변경에 상당한 주의가 필요하다. 팀은 CockroachDB 스터디에서 문서와 자료를 읽어 이 내용을 알고 있었다. 그러나 직접 겪어 보니 글로 읽어 알던 것보다 훨씬 큰 일이었다.

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

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

원인별1