Skip to content

About

Fast WordPress object cache plugin that uses the Yac cache

Topics

Resources

Stars

5 stars

Watchers

0 watching

Forks

Repository files navigation

Yac Object Cache For Wordpress

CI Live WordPress

A Yac backed object cache for WordPress.

Yac stores the cache in lock-free shared memory accessible to all PHP workers: no cache server, no socket, no network round trips. A get() is one hash lookup in local memory.

On the author's own site (www.laruence.com, PHP 8.1 FPM, 8 cores) it came out ~19% higher throughput and ~15% lower latency than the classic Memcached drop-in across 20/50/100 concurrent users — see Benchmarks.

Best fit is single-node (or few-node) WordPress installs.

Features

  • Fast — a get() is a hash lookup in memory the worker already has mapped: no socket, no network, no global lock (per-slot CAS, so throughput scales with worker count). On the author's own site the admin page measures the round trip at 0.004 ms and full page renders came out ~19% faster than the Memcached drop-in, see Benchmarks
  • Nothing to operate — no cache server to install, configure, secure, monitor or restart. The cache is shared memory the PHP workers attach to, so the only moving part is PHP itself
  • Health you can read — hit rate, hits and misses charted over Today / Yesterday / Last 7 days, and a diagnosis that also says when not to add memory. Every key clicks through to its stored value, see Screens
  • Fails soft — no Yac extension, or yac.enable=0, and the drop-in falls back to a per-request cache; the site keeps serving instead of dying on a missing backend

Storage behaviour worth knowing: keys are stored verbatim while they fit Yac's 48-byte limit (over-long ones keep the group and hash only the key part, so dumps stay attributable by group); empty negative results expire after YAC_OCACHE_EMPTY_TTL instead of occupying a slot forever; and a stored false is written as 0, because Yac's get() cannot tell a stored false from a miss — readers comparing by value see 0.

Multisite is supported via per-blog namespacing. On multisite the Yac instance prefix is YAC_OCACHE_KEY_PREFIX + the current blog id (ids up to 9999 verbatim, larger ids a 4-hex crc32b digest), and switch_to_blog() re-namespaces — blogs of one install never read each other's entries. Installs sharing one PHP pool still need different YAC_OCACHE_KEY_PREFIX values; upgrading to the per-blog namespace is a one-time cold start.

Screens

The Dashboard widget summarises the cache without opening anything:

Dashboard widget

Tools → Yac Object Cache opens with the status bar — active backend, shared-memory uptime and the live round trip:

Status

Below it, the detail:

Cache status

Hit rate, hits and misses over Today / Yesterday / Last 7 days, with the window's kicks, recycles and failures. Counters are sampled every 15 minutes into a ~7-day ring; hovering the verdict gives the capacity diagnosis — including when not to add memory.

Shared memory contents

What the shared memory actually holds: keys-by-group pie, occupancy totals and the largest (or hottest) entries. Every key clicks through to the entry inspector — deserialized value, padded size, expiry, delete, plus hits and storage location: embedded-in-slot on Yac 2.4.x, block / inline on Yac 3.0+.

Below those: Configuration (wp-config knobs with current values), Diagnostics (versions, PHP/Yac runtime facts) and Actions (flush / deploy / update / remove the drop-in).

Requirements

  • PHP 7.2+
  • WordPress 5.6+
  • The Yac extension, installed by any of the three ways below

Installing Yac

PECL

pecl install yac

PIE (the PHP Foundation's PECL successor)

pie install laruence/yac

From source

Download the latest release, unzip it, then inside:

phpize && ./configure && make && make install

Then enable it in php.ini:

extension=yac.so

Installation

From the WordPress plugin directory (recommended)

Plugins → Add New → search for "Yac Object Cache", or via WP-CLI:

wp plugin install yac-object-cache --activate

Directory page: Yac Object Cache in the WordPress plugin directory

From GitHub releases

Via WP-CLI:

wp plugin install https://github.com/laruence/wp-yac-cache/releases/latest/download/yac-obj-cache.zip --activate

Or download yac-obj-cache.zip from the releases page, then Plugins → Add New → Upload Plugin.

Configuration

None required. Activation deploys the drop-in and WordPress loads wp-content/object-cache.php on its own. Optional switches, in wp-config.php above the "That's all, stop editing!" line:

define( 'YAC_OCACHE_KEY_PREFIX', 'ab' ); // default wp, 0-6 chars; the only isolation between installs sharing a PHP pool
define( 'YAC_OCACHE_EMPTY_TTL', 21600 ); // default 6h; lifetime cap on empty negative results, 0 disables
define( 'YAC_OCACHE_DISABLE', true );    // escape hatch: force runtime-only mode

Check Tools → Yac Object Cache for status, stats and flush actions.

WP-CLI

wp yac status           # deployment status, one line per check
wp yac flush            # flush the object cache (wipes the whole Yac segment)
wp yac update-dropin    # refresh wp-content/object-cache.php from the plugin's copy
wp yac deploy-dropin    # deploy it after it was removed by hand
wp yac remove-dropin    # remove it; the cache falls back to the WordPress default

wp plugin update does not touch the drop-in: wp-content/object-cache.php is a copy, so it stays at the old version until it is rewritten. wp yac status then reports the mismatch. Updating the plugin from the CLI is two steps:

wp plugin update yac-object-cache && wp yac update-dropin

A foreign object-cache.php is never overwritten or deleted; both drop-in commands refuse and say so. With opcache.validate_timestamps=0, reload PHP-FPM after an update — workers keep serving the cached old drop-in.

Tuning

; php.ini
yac.enable = 1
yac.keys_memory_size = 16M     ; ~128K slots (~32K per 4M)
yac.values_memory_size = 64M   ; raise for large sites (alloptions!)

Yac 3.0: serialization is built-in. The pluggable yac.serializer ini (php/json) was removed.

Older Yac (2.x): keep the default php serializer. Do not set yac.serializer=json — WordPress stores PHP objects (WP_Post, WP_Term, option values, …), and a JSON serializer cannot round-trip them. An unknown serializer name falls back to php silently — check php --ri yac (Serializer =>) for what is actually in effect.

Why YAC_OCACHE_EMPTY_TTL exists: bots probe unbounded one-off URLs and WordPress mints a cache entry per query (get_page_by_path:<md5>, comment query hashes), often holding an empty negative result. Written without expiry, each one occupies a slot forever. The TTL keeps them shared — re-reads still hit — but lets them age out.

Benchmarks

Real-site benchmark on laruence.com (WordPress, PHP 8.1 FPM, 8 cores), full homepage renders, ab -t 30 -c <concurrency>, each run starting from a flushed cache and restarted php-fpm. Only the drop-in differs between the two configurations.

Concurrency Yac RPS Memcached RPS Gain Yac p50 Memcached p50
20 141.6 118.7 +19.3% 139ms 167ms
50 140.6 118.5 +18.6% 353ms 420ms
100 142.1 118.4 +20.1% 699ms 840ms

Zero failed requests in both configurations. Cross-checked with a fixed request-count run (ab -n 10000 -c 100): 141.8 vs 120.6 RPS (+17.6%).

Note that wp_cache_flush() calls Yac::flush() and wipes the entire shared memory on the machine, including data written by other Yac users sharing the same PHP pool. The admin page asks for confirmation. Decide before you flush.

Tests

php -d yac.enable_cli=1 tests/smoke.php   # shared-memory path
php -n tests/smoke.php                    # runtime-only fallback path
php tests/shell.php                       # plugin shell (deploy/status)
php tests/cli.php                         # WP-CLI subcommands (drop-in deploy/update/remove)
php tests/render.php                      # admin page render (charts/advice)

License

GPLv2 or later.

About

Fast WordPress object cache plugin that uses the Yac cache

Topics

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages