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개가 울리고 있어서, 그 알림이 울렸더라도 부수 증상으로 보고 넘겼을 가능성이 컸다.
조치
- 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 도 장애 중에 쓰지 않았다.
출처
관련 사례
같은 원인 · 공통 CI 시스템, 데이터베이스
IL-0136Sweden Central 리전에서 내부 서비스 배포가 캐시를 비워 메타데이터 백엔드에 평소 20배의 트래픽이 몰렸고, 데이터베이스 연결에 기대는 헬스 체크가 인스턴스를 계속 재시작시켜 Azure OpenAI 요청이 6시간 가까이 실패했다Microsoft Azure · 2026같은 원인 · 공통 데이터베이스, 인메모리 캐시
같은 원인 · 공통 CI 시스템, 데이터베이스
같은 원인 · 공통 Helm, 컨피그맵과 시크릿
같은 원인 · 공통 데이터베이스
IL-0234내부 배포 자동화가 개발용 애플리케이션을 고객의 Managed Kubernetes 클러스터들에 잘못 설치해 컨트롤 플레인 연결과 쿠버네티스 기능에 문제가 났다IONOS Cloud · 2026같은 원인 · 공통 CI 시스템
IL-0510MIT Learn 운영 RDS PostgreSQL 의 저장 공간이 임시 파일로 가득 차 learn.mit.edu 가 세 시간 동안 503 과 504 를 냈다MIT Open Learning · 2026같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0547Buildkite 의 Agent API, REST API, GraphQL 이 annotations 테이블 쿼리 타임아웃으로 4시간 가까이 저하됐다Buildkite · 2025같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0307Supabase us-east-1 에서 Supavisor 2.0 업그레이드 뒤 Postgres 연결 풀러가 테넌트 약 80% 의 연결을 끊었다Supabase · 2025같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0523TANF-app 의 운영 배포가 PostgreSQL 마이그레이션 실패로 두 달 동안 막힘U.S. Department of Health and Human Services · 2023같은 원인 · 공통 데이터베이스
IL-0567쿠키런: 오븐브레이크의 패키지 매출 랭킹 기능을 배포한 뒤 Aurora MySQL CPU가 100%에 이르러 유저가 게임에 접속하지 못했다Devsisters · 2023같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0524인덱스를 다시 만드는 마이그레이션이 운영에서 Transactions 테이블을 잠가 Open Collective 서비스가 느려짐Open Collective · 2023같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0467Prow 빌드 클러스터의 노드 업그레이드 중 Boskos 파드가 크래시 루프에 빠져 GCP 프로젝트가 필요한 테스트 작업이 9시간 넘게 모두 실패했다Kubernetes project · 2019같은 원인 · 공통 CI 시스템
같은 원인 · 공통 CI 시스템
같은 원인 · 공통 인메모리 캐시
같은 원인 · 공통 데이터베이스
내 클러스터에도 있는지 확인하기
AI 도구와 스크립트용
- 이 사례의 JSON: https://incidentlib-api.benchlet.com/cases/IL-0324
- 가장 비슷한 사례들: https://incidentlib-api.benchlet.com/cases/IL-0324/similar
- MCP 서버(Streamable HTTP, 키 없음):
https://incidentlib-mcp.benchlet.com/mcp
API 는 키가 필요 없습니다. MCP 서버는 search_incidents, get_incident, list_incidents, get_topic, vocab 도구를 내놓습니다. 사용법은 API 와 MCP.