Incident Library

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

Three MediaWiki deployments lost Memcached after a PHP 8.1 rollout and overloaded the External Storage database cluster

Scap, Wikimedia's MediaWiki deployment tool, builds and pushes MediaWiki images, updates helmfile-defaults with the latest image tag for each deployment and release, and runs helmfile on every MediaWiki deployment. PHP-FPM reads two environment variables from a ConfigMap called mediawiki-main-php-envvars, mounted as /etc/php/<X.Y>/fpm/env/envvars.inc: MCROUTER_SERVER, the Memcached and mcrouter address, which defaults to 127.0.0.1:11213, and STATSD_EXPORTER_PROMETHEUS_SERVICE_HOST, which is unset by default. The include directory is hardcoded per PHP version, /etc/php/7.4/fpm/env/*.inc in the publish-74 image and /etc/php/8.1/fpm/env/*.inc in the publish-81 image. The PHP 8.1 rollout was two patches: 1126607 in puppet switched mw-api-int, mw-parsoid and mw-jobrunner from the publish-74 to the publish-81 image flavour, and 1126650 in deployment-charts moved the envvars.inc mount to the 8.1 path.

Scap was run with -Dbuild_mw_container_image:False, a flag SREs commonly use because most changes need no image rebuild, and publish-81 was already built and cached. Nobody realised that the flag also makes Scap skip the helmfile-defaults update, so the three deployments kept the publish-74 image while the ConfigMap was mounted at the 8.1 path. The 7.4 include directory held only default values, so the pods ran without access to the Memcached cluster and without a valid prometheus StatsD address; the StatsD gap had no effect because MediaWiki also pushed stats to Graphite. Without Memcached, MediaWiki queried the databases for objects that are normally cached, and the load on the External Storage cluster and the core databases rose.

On 12 March responders lowered the load from cirrus-streaming-updater and changeprop-jobqueue and, at 13:44, reverted both patches and re-ran Scap. On 13 March the rollout was attempted again with patches 1127476 and 1127478, and the three deployments again ran without access to Memcached; after rolling restarts of changeprop-jobqueue and mw-api-int and disabling the categorymembership job, the patches were reverted at 11:46, mw-api-int was redeployed and given more replicas, and mw-jobrunner and mw-parsoid were redeployed by 14:06. The write-up names Scap, the php-fpm envvars.inc include file and the logstash-prometheus pipeline as the factors that caused the incident and delayed finding its root cause, and says coordination among the 9 responders was difficult.

Severity
–
Scope
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
Users affected
–
Region
–
Time to detect
14m
Time to resolve
3h

Symptoms

On 2025-03-12 from 10:58 UTC, alerts for high backend response times came in, and the MediaWiki deployments mw-api-int, mw-parsoid and mw-jobrunner, which serve MediaWiki for non-user-facing purposes, showed high latency and database errors. The External Storage cluster, whose hosts store the compressed text of wiki page revisions, had a sharp rise in load and connections. The same happened again on 2025-03-13 from 11:15 UTC.

Most MediaWiki errors in channel: error at the time were database related. External Storage queries per second and connection counts jumped, and circuit breakers kept the databases from collapsing; the core databases followed a similar pattern. WANObjectCache and the SQLBlobStore keygroup showed a high rate of miss.compute keys, while Memcached and mcrouter traffic dropped sharply. User-facing traffic was barely affected: global traffic had an error rate of about 0.03-0.04%, edits were affected for a very short time, and p50 and p75 latency of mw-web and the External API did not change.

The signal that pointed at the cause was hard to see. The deployments produced about 2mil/min memcached error events in channel: memcached, more than logstash could process, so the channel:memcached logstash dashboard probably could not render until logstash worked through its backlog after the incident. Memcached errors collected by Prometheus spiked at 50k/min, but delays in the mw→logstash→prometheus-es-exporter→prometheus pipeline kept the MediaWikiMemcachedHighErrorRate alert from staying up: it went off and recovered quickly, and the matching Grafana graph showed no data during the incidents. 78 alerts were firing during the incident, and the team thought it likely that even a firing MediaWikiMemcachedHighErrorRate would have been taken for a side effect.

Responders first worked through the usual suspects for MediaWiki latency and database load: high traffic from a specific network or client, scheduled jobs gone wrong, and greedy changeprop-jobqueue jobs. On 12 March they reduced SUP parallelism in cirrus-streaming-updater and the concurrency of the categoryMembershipChange job, and assumed the Scap rollout was not the problem. By 13 March they were certain the Scap rollout was the cause, but it took until after the incident to understand how.

Symptom Database overloadHigh latencyHigh error rateLog floodMonitoring outage

Root cause

Trigger
At 10:44 UTC on 12 March a Scap deployment of the PHP 8.1 rollout for mw-api-int, mw-parsoid and mw-jobrunner was run with the flag -Dbuild_mw_container_image:False; the rollout was deployed with Scap again at 11:15 UTC on 13 March.

Detection

Alerts for high backend response times started at 10:58 UTC on 12 March, 14 minutes after the Scap deployment; 2 on-call engineers were paged. The MediaWikiMemcachedHighErrorRate alert that pointed at the cause fired only briefly because its log pipeline was overloaded.

Remediation

Action items

Lessons

The write-up puts the weight not on the technical root cause but on why the team could not see, even after the 12 March incident, that three MediaWiki deployments were running without Memcached. Alert dashboards showed what was happening, such as many busy PHP workers, but not why; dashboards linking components that affect each other, such as SQLBlobStore keys and External Storage, would have helped. The alert that pointed in the right direction did not stay firing and would probably have been lost among 78 others. The incident coordinator could not tell who was working on what or who had joined or left, the channels were noisy, the external impact was judged more critical than it was, and trace.wikimedia.org was not used although it might have helped.

Sources

Related cases

Check your cluster for this

kubegap audits a Kubernetes cluster for conditions like the ones in this case, Database, In-memory cache, ConfigMaps and Secrets among them, read-only, from Claude Code or Codex. Its checks cite public reports like this one.

For AI tools and scripts

The API needs no key. The MCP server offers search_incidents, get_incident, list_incidents, get_topic and vocab; both are explained on API and MCP.