Incident Library

IL-0324 Wikimedia Foundation · 2025-03-12databasekubernetesobservability

External Storage 데이터베이스 클러스터에 과부하가 걸려 mw-api-int, mw-parsoid, mw-jobrunner 의 지연과 데이터베이스 오류가 늘었다

Wikimedia 는 2025-03-12 와 2025-03-13 에 MediaWiki 의 비사용자 대상 배포인 mw-api-int, mw-parsoid, mw-jobrunner 를 PHP 8.1 로 옮기려고 Scap 으로 배포했다. Scap 은 MediaWiki 배포 도구다. Scap 은 MediaWiki 이미지를 빌드해 올리고, 배포와 릴리스마다 helmfile-defaults 의 이미지 태그를 갱신하고, MediaWiki 를 돌리는 모든 배포에 helmfile 을 실행한다. 이번 배포는 패치 두 개로 이뤄졌다. puppet 패치는 이미지 종류를 publish-74 에서 publish-81 로 바꾸고, deployment-charts 패치는 mediawiki-main-php-envvars ConfigMap 의 마운트 위치를 /etc/php/7.4/fpm/env/envvars.inc 에서 /etc/php/8.1/fpm/env/envvars.inc 로 바꿨다.

Scap 은 SRE 들이 흔히 쓰는 -Dbuild_mw_container_image:False 플래그로 실행됐다. 이 플래그가 이미지 빌드뿐 아니라 helmfile-defaults 갱신까지 건너뛴다는 것은 바로 드러나지 않았다. 그 결과 세 배포는 publish-74 이미지로 도는데 ConfigMap 은 8.1 경로에 마운트된 상태가 됐다. PHP-FPM 은 PHP 버전에 따라 정해진 경로에서 환경 변수를 읽으므로 7.4 경로의 기본값을 읽었다. 그래서 memcached 와 mcrouter 주소인 MCROUTER_SERVER 는 기본값 127.0.0.1:11213 이 됐고 STATSD_EXPORTER_PROMETHEUS_SERVICE_HOST 는 비어 있었다. MediaWiki 는 통계를 Graphite 로도 보내고 있어 statsd 주소가 없는 것은 영향이 없었다. 하지만 Memcached 에 닿지 못한 MediaWiki 는 평소 캐시에 있던 객체를 데이터베이스에 물었다. 위키 페이지 리비전의 압축된 본문을 저장하는 External Storage 클러스터의 부하와 연결 수가 크게 늘었고, 그 결과 세 배포에서 지연과 데이터베이스 오류가 났다.

channel: memcached 오류 이벤트가 분당 약 200만 건 쏟아져 logstash 가 따라가지 못했다. 그 때문에 MediaWikiMemcachedHighErrorRate 알림이 빠지고 Grafana 그래프는 데이터가 없다고 나왔다. 3월 12일 팀은 cirrus-streaming-updater 의 SUP 병렬도와 categoryMembershipChange 작업의 동시성을 낮췄고, 13:44 에 두 패치를 되돌려 Scap 을 다시 돌렸다. 3월 13일 11:15 에 같은 롤아웃을 다시 배포하자 장애가 되풀이됐다. 이번에는 changeprop-jobqueue 와 mw-api-int 를 롤링 재시작하고 categorymembership 작업을 껐다. 그다음 패치를 되돌린 뒤 세 배포를 다시 배포하고 mw-api-int 의 레플리카를 늘렸다. 사용자에게 보이는 영향은 작았다. 전체 트래픽 오류율은 약 0.03~0.04% 였고, 편집은 아주 짧은 동안 영향을 받았으며, 웹과 외부 API 의 p50, p75 지연은 그대로였다.

심각도
–
영향 범위
mw-api-int, mw-parsoid and mw-jobrunner had high latency and database errors on 12 and 13 March; global traffic had about a 0.03-0.04% error rate and edits were affected very briefly
영향 사용자
–
지역
–
감지까지
14m
복구까지
3h

증상

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

그때 channel: error 에 찍힌 MediaWiki 오류는 대부분 데이터베이스 오류였다. External Storage 의 QPS 와 연결 수가 급격히 늘었고 서킷 브레이커가 데이터베이스가 무너지는 것을 막았다. 코어 데이터베이스에서도 비슷한 추이가 보였다. 사용자 대상 배포인 mw-web 과 mw-api-ext 는 거의 영향을 받지 않았고, 전체 트래픽의 오류율은 약 0.03~0.04% 였다.

Memcached 트래픽과 mcrouter 요청이 급격히 떨어졌다. WANObjectCache 와 SQLBlobStore 키 그룹에서 miss.compute 키 비율이 높았다. 이 키 그룹의 메타데이터는 Memcached 에 있는데, 세 배포가 Memcached 에 닿지 못했기 때문이다.

channel: memcached 오류 이벤트가 분당 약 200만 건 쏟아져 logstash 가 제때 처리하지 못했다. channel:memcached 대시보드는 장애가 끝나 logstash 가 밀린 이벤트를 다 처리할 때까지 그려지지 않았던 것으로 보였다. mw→logstash→prometheus-es-exporter→prometheus 파이프라인이 밀려 MediaWikiMemcachedHighErrorRate 알림이 빠졌다. 해당 Grafana 그래프는 장애 중 데이터가 없다고 나왔다. Prometheus 가 모은 Memcached 오류는 분당 5만 건까지 올랐지만 알림은 울렸다가 곧 회복됐다.

처음에는 특정 네트워크나 클라이언트의 많은 트래픽, 잘못 실행된 예약 작업, 자원을 많이 먹는 changeprop-jobqueue 작업을 의심했다. MediaWiki 지연과 데이터베이스 부하가 보일 때 늘 의심하던 것들이었다. 3월 12일에는 Scap 배포가 문제가 아니라고 봤다. 3월 13일에야 Scap 배포가 원인이라고 확신했지만, 그 배포가 어떻게 장애로 이어졌는지는 이해하기 어려웠다. 장애 중에 알림 78개가 울리고 있었다.

증상 데이터베이스 과부하지연 시간 증가오류율 상승로그 폭증모니터링 중단

원인

촉발
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개가 울리고 있어서, 그 알림이 울렸더라도 부수 증상으로 보고 넘겼을 가능성이 컸다.

조치

후속 조치

교훈

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

출처

관련 사례

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

kubegap 은 Claude Code 나 Codex 에서 쿠버네티스 클러스터를 읽기만 하며 이 사례와 같은 상태를 점검합니다. 이 사례의 구성 요소: 데이터베이스, 인메모리 캐시, 컨피그맵과 시크릿. 점검 항목의 근거는 이 사례 같은 공개 보고서입니다.

AI 도구와 스크립트용

API 는 키가 필요 없습니다. MCP 서버는 search_incidents, get_incident, list_incidents, get_topic, vocab 도구를 내놓습니다. 사용법은 API 와 MCP.