Mastering MediaWiki Caching: Strategies for High-Traffic Sites
Why “Caching” Is the Lifeblood of a Busy Wiki
When a MediaWiki installation starts to see a few thousand page‑views per minute, the server’s CPU and DB threads begin to scream “slow down!”. The first thing most sysadmins learn—sometimes the hard way—is that raw PHP execution alone won’t cut it. A well‑tuned cache stack turns “render‑on‑the‑fly” into “serve‑a‑snapshot”, shaving milliseconds off each request and, more importantly, keeping the database from turning into a bottleneck.
Two‑level mental model
- Object cache – stores parsed wikitext, user sessions, parser output fragments, etc. Think of it as a “key‑value locker” that PHP talks to directly.
- Page view cache – holds fully‑rendered HTML for anonymous readers. This lives either on the filesystem or behind a reverse‑proxy like Varnish.
Both levels have to talk the same language, but they solve different problems. Mixing them up is a common rookie mistake, so keep them straight in your head.
Bytecode First: Let PHP Do Less Work
Before we even touch MediaWiki‑specific settings, make sure OPcache is enabled. It’s the cheapest performance win you can get—just a few lines in php.ini and PHP stops recompiling the same files on every request.
[opcache]
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.validate_timestamps=1
opcache.revalidate_freq=2
On a typical 8‑core VM, 256 MiB of cache is plenty. If you notice “Out of shared memory” warnings in your logs, bump the number up; the extra RAM is usually worth it.
Object Caching – The “Middle‑Man”
MediaWiki calls the key‑value store the “object cache”. You have three main choices, each with its quirks.
APCu (local, single‑server)
For a modest wiki on one web node, APCu is like a coffee shop where the barista knows every regular by name. It lives inside PHP’s process, so latency is effectively zero.
$wgObjectCacheEnable = true; // default on newer MediaWiki releases
$wgCacheType = CACHE_ACCEL;
Note: APCu works only with PHP 7+. If you’re still on PHP 5.6, you’ll need to fall back to eAccelerator or upgrade.
Memcached (distributed, multi‑server)
When you add a second web front‑end, APCu stops being shared. Memcached steps in as the “central pantry” that every server can pull from.
$wgObjectCaches[ 'memcached' ] = [
'class' => 'MediaWiki\\Cache\\MemcachedPhpBagOStuff',
'servers' => [
'10.0.1.12:11211',
'10.0.1.13:11211',
],
];
$wgMainCacheType = CACHE_MEMCACHED;
Make sure to set memcached.sess_locking = 1 in php.ini if you rely on PHP sessions; otherwise you’ll see “session hijack” warnings under load.
Redis (future‑proof)
Redis isn’t mentioned in the official MediaWiki docs as often, but many large wikis have migrated there for its richer data types. The configuration mirrors Memcached, just swap the class name:
$wgObjectCaches['redis'] = [
'class' => 'MediaWiki\\Cache\\RedisBagOStuff',
'servers' => [ 'redis01:6379' ],
];
$wgMainCacheType = CACHE_REDIS;
Redis also gives you built‑in expiration handling, which can simplify cache‑purge scripts.
Page View Caching – Serve “Static” HTML
Even with a blazing‑fast object cache, every request still has to run through MediaWiki’s parser. For anonymous traffic, that overhead is unnecessary. Two common approaches exist:
- File cache – MediaWiki writes
*.htmlfiles into/cache. It’s simple, works out of the box, but can become I/O bound on spinning disks. - Varnish – a reverse‑proxy that holds the HTML in RAM. Ideal for high‑traffic portals, but requires a bit more networking know‑how.
Enabling the file cache
Set the following in LocalSettings.php:
$wgUseFileCache = true;
$wgFileCacheDirectory = "$IP/cache";
$wgCachePages = true; // default, but make it explicit
Make sure the cache directory is writable by the web‑user, and consider mounting it on an SSD for best performance.
Varnish in front of MediaWiki
If you decide to go “full‑size”, the MediaWiki manual recommends a few headers to respect. Add this snippet to LocalSettings.php so Varnish knows when to bust the cache:
$wgVarnishServers = [ '10.0.2.100:6081' ];
$wgUseCdn = true;
$wgCdnServers = $wgVarnishServers;
$wgCdnReboundPurgeDelay = 30; // seconds
Then, in your Varnish VCL, honour the X‑MediaWiki‑Cache‑Tag header that MediaWiki emits on edits. The trick is to purge only the affected pages, not the whole cache:
sub vcl_deliver {
if (obj.hits > 0 && resp.http.X-MediaWiki-Cache-Tag) {
set beresp.http.X-Purge-Tag = resp.http.X-MediaWiki-Cache-Tag;
}
}
Remember to restart Varnish after editing the VCL; a simple typo can bring down the entire front‑end, so double‑check the syntax.
Balancing Act – When Too Much Caching Hurts
It’s tempting to “cache everything”. In practice, you’ll find that over‑caching at both layers cause stale content to linger, and the purge logic can become a maintenance nightmare.
Some practical guidelines:
- Keep
$wgCachePagesturned on for anonymous users, but disable it for logged‑in sessions where personalization matters. - Set a short TTL (time‑to‑live) for user‑specific objects in Memcached (e.g., 300 seconds). That way a password change propagates quickly.
- Use
$wgUseCdnPurgeonly if you have a CDN in front of Varnish; otherwise you’ll be sending purge requests into a void.
In one real‑world case (a fandom wiki with ~12 M page‑views/day) the team reduced the average page‑render time from 1.2 s to 0.4 s simply by lowering the Memcached maxmemory from “unlimited” to “2 GB”. The cache was previously thrashing, causing lots of “cache‑miss” rebuilds.
Monitoring and Tuning – You Can’t Fix What You Don’t See
All the $wg* flags in the config are great, but you need visibility. A few tools that integrate nicely with MediaWiki:
- Profiler – enable with
$wgProfiler['class'] = 'ProfilerSimple';and read the HTML comments on each page. - APCu/Redis/Memcached UI –
apc.php,phpRedisAdminor thememcached-toolsuite give you hit/miss ratios at a glance. - Varnishstat –
varnishstat -1shows request rates, cache‑hit percentages and eviction counts.
When you see the miss ratio creeping above 30 % for the object cache, it’s time to either add more memory or shrink the stored data (e.g., disable $wgUserLanguageCache if you don’t need per‑language userprefs).
Putting It All Together – A Sample Minimalist Setup
Below is a trimmed‑down LocalSettings.php that would get a 4‑core VM with 8 GiB RAM running a Medium‑traffic wiki (<≈200 k page‑views per day) into a respectable speed range.
# Bytecode cache – PHP built‑in OPcache already enabled in php.ini
# Object cache – APCu for single‑server, Memcached fallback for future scaling
$wgObjectCacheEnable = true;
if (extension_loaded('apcu')) {
$wgCacheType = CACHE_ACCEL; // APCu
} else {
$wgObjectCaches['memcached'] = [
'class' => 'MediaWiki\\Cache\\MemcachedPhpBagOStuff',
'servers' => [ '127.0.0.1:11211' ],
];
$wgMainCacheType = CACHE_MEMCACHED;
}
# Page view cache – file cache on fast SSD
$wgUseFileCache = true;
$wgFileCacheDirectory = "$IP/cache";
$wgCachePages = true;
# Varnish – optional, uncomment if you have it
# $wgVarnishServers = [ '10.0.2.100:6081' ];
# $wgUseCdn = true;
# $wgCdnServers = $wgVarnishServers;
# Misc performance tweaks
$wgReadOnly = false;
$wgEnableCompressedMessages = true; // gzip JS/CSS
$wgShowExceptionDetails = false; // hide stack traces in prod
# Profiler – useful in dev, disable in prod
# $wgProfiler['class'] = 'ProfilerSimple';
That’s it. Adjust the numbers (memory size, number of Memcached nodes, TTLs) to match your traffic pattern, and you’ll have a solid baseline.
Final Thoughts
Mastering MediaWiki caching isn’t about flipping a single switch; it’s a layered discipline. Start with OPcache, add the right object cache for your architecture, then decide whether a file cache or a full‑blown Varnish front‑end makes sense. Keep an eye on hit ratios, and don’t be afraid to prune a layer if it starts to cause more churn than benefit.
In the end, a well‑cached wiki feels almost instantaneous to the end‑user, while the back‑ends stay breezy even when the traffic spikes after a hot‑topic article goes viral. That, more than any fancy code snippet, is the real reward for a diligent SysAdmin.