Object Cache Backend Tuning:
Redis vs. Memcached Latency
Profiling cache hit/miss ratios and understanding the memory footprint of different object caching strategies on your server’s RAM architecture.
On a cache HIT, the serialized PHP object is returned directly from RAM in under 1ms, completely bypassing MySQL. On a MISS, the full database query executes (2–50ms), the result is written back to the cache store, then returned. Every percentage point of hit ratio improvement directly compresses average response latency.
Core Mechanism
Object caching intercepts repetitive PHP database calls by storing serialized query results as key-value pairs in an in-memory data structure. When WordPress (or any PHP application) requests a database object — a post, a user record, a transient — the cache backend is queried first. If the key exists and has not expired, the value is deserialized and returned in RAM-speed time, completely bypassing MySQL. The entire performance multiplier of object caching rests on this single architectural guarantee: RAM access is 100–1000× faster than a disk-bound database query.
The “Core Mechanism” distinction between Redis and Memcached lies in their internal data structure models and their persistence architectures. Memcached is a deliberately constrained, multi-threaded slab allocator: it stores only flat string blobs, uses a simple LRU (Least Recently Used) eviction algorithm, and holds no state beyond volatile RAM. Redis, by contrast, is a full data structure server. It supports strings, hashes, lists, sorted sets, and bitmaps natively, implements multiple eviction policies (allkeys-lru, volatile-ttl, allkeys-lfu), and optionally persists data to disk via RDB snapshots or AOF (Append-Only File) journaling. This architectural depth is why Redis is the dominant choice for WordPress object caching in production environments, despite its higher per-process RAM footprint.
The hit ratio — the percentage of cache lookups that return a valid result — is the single most diagnostic metric in cache performance profiling. A hit ratio below 85% indicates a misconfigured TTL strategy, an undersized memory allocation, or an overly aggressive eviction policy that is purging hot keys before they can be reused. Conversely, a ratio above 99% on a low-traffic site may mask a memory bloat problem, where objects are being retained far longer than their data validity window requires, consuming RAM that could serve more concurrent hot keys.
Architecture Comparison Matrix
The following table maps the critical operational dimensions engineers use to select and configure a cache backend. Understanding these axes is prerequisite to interpreting profiler output from tools like redis-cli --stat or Memcached’s stats command, and to making informed eviction policy selections under memory pressure.
| Dimension | Redis | Memcached | Production Verdict |
|---|---|---|---|
| Data Model | Strings, Hashes, Lists, Sets, Sorted Sets, Bitmaps | String blobs only (flat key-value) | Redis wins for structured objects; Memcached for raw scalability |
| Threading Model | Single-threaded event loop (I/O threads in v6+) | Multi-threaded — scales linearly with CPU cores | Memcached outperforms on raw multi-core throughput for simple GET/SET |
| Eviction Policy | allkeys-lru, allkeys-lfu, volatile-ttl, noeviction (6 total) |
LRU only (implicit, slab-level) | Redis offers surgical control; Memcached is “set and forget” LRU |
| Persistence | RDB snapshots + AOF journaling (optional) | None — volatile RAM only | Redis survives server restart; Memcached requires full cold cache warm-up |
| Memory Overhead | Higher — per-key metadata, expiry tracking, type headers | Lower — compact slab allocation, minimal metadata | Memcached uses ~20% less RAM per cached byte at equivalent key counts |
| Replication / HA | Native master-replica, Redis Sentinel, Redis Cluster | No native replication; requires client-side sharding | Redis mandatory for multi-server or high-availability setups |
| Latency (P99) | ~0.2–0.5ms (single-threaded lock contention under heavy write load) | ~0.1–0.3ms (multi-threaded, lower P99 variance under concurrency) | Memcached has lower tail latency; Redis has higher predictability with LFU |
| WordPress Integration | Full support via wp-redis or Redis Object Cache plugin |
Support via memcached PHP extension + drop-in |
Redis is the de facto standard; broader hosting and plugin ecosystem |
Redis Object Cache Eviction & Memory Calculator
This tool is required here because the eviction policy you select in redis.conf directly determines which keys are purged when maxmemory is reached — and calculating that threshold without knowing your object count, average serialized object size, and TTL distribution will produce an undersized or oversized allocation that degrades either hit ratio or server stability. Before tuning maxmemory-policy, you need quantified projections, not estimates. Feed your site’s object count and average object byte size into this calculator to derive a scientifically grounded maxmemory value and validate that your current eviction policy is optimal for your traffic’s key reuse pattern.
Profiling Hit/Miss Ratios
Raw latency benchmarks are insufficient for cache performance analysis. The metric that governs real-world impact is the cache hit ratio, expressed as keyspace_hits / (keyspace_hits + keyspace_misses). For Redis, you can retrieve these counters in real time using redis-cli INFO stats and extracting the keyspace_hits and keyspace_misses fields. For Memcached, the equivalent is echo stats | nc localhost 11211 and reading get_hits and get_misses. Both counters are cumulative since daemon start, so baseline them at a consistent traffic interval (e.g., a full 60-minute window during peak load) to get a representative ratio rather than a transient snapshot.
A target hit ratio of 90%+ is the production floor for a well-tuned WordPress install. Sites running WooCommerce with persistent cart and session data, or BuddyPress with high-frequency user meta lookups, should target 95%+. When you observe ratios below 85%, the diagnostic checklist follows a strict order: first audit TTL configuration (objects expiring before reuse), then verify maxmemory is not undersized (triggering excessive eviction), then inspect key namespace fragmentation (too many single-use transients polluting the keyspace). Each layer has a distinct fingerprint in the INFO stats and INFO keyspace output.
The following diagnostic commands provide the essential profiling surface for a Redis backend. Run them in sequence during a live traffic window for the most actionable signal.
# 1. Real-time hit/miss counter sampling
redis-cli INFO stats | grep -E "keyspace_(hits|misses)"
# 2. Compute hit ratio (bash one-liner)
redis-cli INFO stats | awk -F: '/keyspace_hits/{h=$2} /keyspace_misses/{m=$2} END {printf "HIT RATIO: %.2f%%\n", h/(h+m)*100}'
# 3. Memory footprint and eviction pressure
redis-cli INFO memory | grep -E "used_memory_human|maxmemory_human|mem_fragmentation_ratio"
# 4. Eviction counter (non-zero = maxmemory pressure)
redis-cli INFO stats | grep evicted_keys
# 5. Live key expiry and eviction stream (1-second interval)
redis-cli --stat -i 1
# 6. Top 20 largest keys by memory (requires redis-rdb-tools or redis-cli bigkeys)
redis-cli --bigkeys
# -- Memcached equivalent --
echo "stats" | nc 127.0.0.1 11211 | grep -E "get_hits|get_misses|bytes|evictions"
The maxmemory directive defines the hard ceiling for Redis RAM use. Below 70% of that ceiling (the Safe Zone), no eviction occurs and hit ratios remain stable. Between 70–90% (Pressure Zone), the configured eviction policy begins purging keys, causing measurable hit ratio degradation. Above 90% (Eviction Threshold), aggressive churn elevates miss ratios and increases MySQL query volume. PHP’s memory_limit operates as a separate allocation ceiling above this stack and must be sized independently.
Memory Footprint & RAM Architecture
Every cached object consumes more RAM than its raw serialized byte size. Redis adds per-key metadata overhead: a 64-byte dictionary entry for the key name, expiry tracking (8 bytes for Unix timestamp), type encoding headers, and internal pointer structures. For small objects (under 100 bytes), this overhead can represent 40–80% of total per-key memory cost. This is why the mem_fragmentation_ratio reported by redis-cli INFO memory is a critical diagnostic signal — a ratio above 1.5 indicates significant internal fragmentation, meaning Redis has allocated substantially more OS memory than it is actively using for stored data, pointing to a restart or MEMORY PURGE operation.
Memcached manages memory through a slab allocator that pre-partitions RAM into fixed-size chunks grouped into slab classes (64B, 128B, 256B, up to 1MB). When a new object is stored, Memcached assigns it to the smallest slab class that fits. Objects smaller than the slab chunk size waste the unused portion (internal fragmentation is by design). This predictable, fixed-overhead model makes Memcached’s RAM consumption mathematically deterministic given a known object size distribution — an advantage when capacity planning on RAM-constrained servers.
For WordPress environments, a practical RAM budget follows a three-layer architecture: (1) OS kernel + base services (128–256MB reserved), (2) PHP-FPM worker pool (memory_limit × pm.max_children), and (3) Redis/Memcached allocation (the remainder, minus a 15% safety buffer). Failing to account for all three layers in the same calculation is the single most common cause of OOM (Out-of-Memory) kills on production servers, where the OS terminates Redis mid-request because the PHP workers collectively consumed the RAM headroom that cache profiling had assumed was available.
Takeaway
Redis is the architecturally superior choice for WordPress object caching in the majority of production configurations: its eviction policy flexibility, native persistence, and replication support address the failure modes that Memcached cannot. However, Memcached’s multi-threaded model and lower per-key RAM overhead make it a rational choice for high-concurrency, single-node environments where raw GET/SET throughput at minimum memory cost is the primary constraint, and where cache warm-up latency after a restart is acceptable. The decision is not ideological — it is a function of your traffic pattern, RAM budget, and operational tolerance for cold-cache restarts.
The hit ratio is your primary production KPI. Instrument it before and after every configuration change — maxmemory adjustment, eviction policy switch, TTL tuning, or key namespace restructuring. A configuration change that improves average response time by 10ms but drops the hit ratio from 96% to 89% is a net negative: the increased MySQL query volume will amplify under load, eroding the latency gain at concurrency peaks. Always profile the ratio, not just the speed.
WordPress PHP Memory Limit Calculator
This tool is required here because Redis and Memcached maxmemory allocations cannot be set in isolation — they must be calculated as the residual of your server’s total RAM after PHP-FPM worker pool consumption is fully accounted for. The PHP memory_limit directive, multiplied by your pm.max_children count, defines the maximum RAM your PHP workers can collectively consume under peak load. Oversizing the cache allocation without knowing this floor causes OOM-triggered Redis evictions or, critically, OS-level process kills. Use this calculator to derive your safe PHP memory ceiling, then feed the result into the Redis eviction calculator (NODE 022) to close the full RAM budget equation.
A production Redis instance has a mem_fragmentation_ratio of 2.1 and an eviction policy set to allkeys-lru. The operator increases maxmemory by 30% to reduce eviction pressure but observes no improvement in hit ratio after 24 hours. What is the most likely root cause?