Drop-in Object Cache Ultra-Ringan untuk WordPress High-Traffic

Views:0

Redis Object Cache – Stripped (v5.4.8)

🎯 Mengapa Plugin Ini Dibuat?

Di lingkungan WordPress dengan puluhan ribu member aktif dan ribuan posts yang di-serve setiap detiknya, setiap milidetik latency dan setiap byte memory yang terbuang adalah biaya operasional yang nyata.
Redis Object Cache – Stripped adalah drop-in object-cache.php yang saya kembangkan sebagai respons terhadap kebutuhan:
  • Zero-dependency: Hanya butuh ekstensi php-redis, tanpa library eksternal
  • Ultra-clean L1/L2 coherence: Local cache (L1) dan Redis (L2) selalu sinkron tanpa race condition
  • Fail-open yang aman: Tetap berfungsi saat Redis down tanpa corrupt data
  • JIT micro-optimized: Eviction L1, key hashing, dan pipeline batching yang efisien
  • Production-hardened: 12 koreksi kritis di v5.4.8 untuk edge case real-world
Plugin ini bukan “fork” dari solusi existing, melainkan implementasi from-scratch yang mengutamakan koherensi data, predictable performance, dan operational simplicity.

🏗️ Arsitektur: Hybrid L1/L2 dengan Key Versioning

┌─────────────────────────────────────┐
│ WordPress Request │
└─────────┬───────────────────────────┘


┌─────────────────────────────────────┐
│ L1: Local Cache (PHP Array) │
│ • O(1) lookup │
│ • Max 100k entries (configurable) │
│ • Auto-eviction LRU-style │
└─────────┬───────────────────────────┘
│ Miss / Force Refresh

┌─────────────────────────────────────┐
│ L2: Redis Backend │
│ • Persistent storage │
│ • Key versioning untuk invalidation│
│ • Pipeline batching untuk bulk ops │
└─────────────────────────────────────┘

🔑 Strategi Key Versioning (Tanpa SCAN/KEYS!)

Alih-alih menggunakan SCAN atau KEYS yang berbahaya di production, plugin ini mengimplementasikan namespace versioning:

// Format key persistent:
// {SALT}:{NS}:{BLOG_PREFIX}:{GROUP}:v{GV}:{KEY}

// Contoh:
// aoc123:42:1:options:v1735689200:alloptions

  • NS (Namespace Version): Di-increment saat flush() global → invalidate seluruh cache
  • GV (Group Version): Di-increment per-group saat flush_group() → invalidate spesifik group
  • Runtime caching: $gv_runtime menyimpan GV di memory agar tidak perlu query Redis berulang
Hasilnya: invalidation O(1), tanpa performa degradation saat cache besar.

⚡ Fitur Utama & Optimasi

1. Local Cache (L1) dengan Eviction Cerdas

// Saat limit tercapai, potong 25% oldest entries
$slice_amount = max(1, (int) (AOC_LOCAL_CACHE_LIMIT * 0.25));
$this->local = array_slice($this->local, $slice_amount, null, true);
  • Mencegah memory bloat di PHP-FPM worker
  • max(1, ...) memastikan tidak crash di limit kecil

2. Fail-Open yang Safe & Predictable

// Write operations tetap bisa ke L1 saat Redis down
if (!$this->redis_ok && $this->cfg_fail_open_write) {
$this->set_local($full, $val); // Fallback aman
return true;
}

  • Konfigurasi via AOC_FAIL_OPEN_WRITE
  • Tetap menghormati semantik add()/replace() walau Redis down

3. Recovery Auto-Healing

private function check_redis_recovery(): void {
if (time() – self::$last_retry > $this->cfg_failover_ttl) {
$this->init_redis(); // Coba reconnect
if ($this->redis_ok) {
$this->gv_runtime = []; // Reset state agar koheren
}
}
}

  • Retry setiap 15 detik (default)
  • Reset $gv_runtime saat recovery → mencegah stale version

4. WooCommerce Compatibility Mode

if (AOC_WOO_SKIP && $this->woo_strict) {
$this->np_groups[“term-queries”] = true; // Skip cache untuk query tertentu
}

  • Mode strict: otomatis bypass cache untuk key yang rentan race condition di Woo
  • Konfigurasi via AOC_WOO_MODE: "strict" | "relaxed"

5. Batch Operations dengan Pipeline

// get_multiple / set_multiple / delete_multiple
foreach (array_chunk($keys, $this->chunk_size) as $chunk) {
$this->redis->multi(Redis::PIPELINE);
// … queue operations
$this->redis->exec(); // Single round-trip
}

  • Chunk size configurable via AOC_BATCH_CHUNK (default: 1000)
  • Mengurangi network overhead hingga 90% untuk bulk operations

    ⚙️ Konfigurasi (wp-config.php)

    define(‘WP_CACHE_KEY_SALT’, ‘yourwebsitekeysalt::’);
    define(‘WP_CACHE’, true);

// — Koneksi Redis —
define(‘WP_REDIS_HOST’, ‘127.0.0.1’);
define(‘WP_REDIS_PORT’, 6379);
define(‘WP_REDIS_DATABASE’, 0);
define(‘WP_REDIS_PASSWORD’, ”); // Opsional

// — Behavior Cache —
define(‘AOC_LOCAL_CACHE_LIMIT’, 100000); // Max entries di L1
define(‘AOC_FAIL_OPEN_WRITE’, false); // Izinkan write ke L1 saat Redis down
define(‘AOC_FAILOVER_TTL’, 15); // Retry interval (detik)
define(‘AOC_DEFAULT_NOEXP_TTL’, 2592000); // TTL default untuk key tanpa expire (30 hari)
define(‘AOC_KEY_TTL_MAX’, 2592000); // Max TTL yang diizinkan
define(‘AOC_MAX_KEY_LENGTH’, 230); // Batas panjang key sebelum di-hash
define(‘AOC_BATCH_CHUNK’, 1000); // Chunk size untuk pipeline

// — Multisite & WooCommerce —
define(‘AOC_NS_PER_BLOG’, true); // Namespace terpisah per blog di multisite
define(‘AOC_WOO_SKIP’, true); // Aktifkan bypass untuk Woo
define(‘AOC_WOO_MODE’, ‘strict’); // “strict” atau “relaxed”

// — Advanced —
define(‘AOC_REDIS_TIMEOUT’, 1.5); // Connection timeout (detik)
define(‘AOC_REDIS_PERSISTENT’, true); // Gunakan pconnect()

📦 Instalasi & Penggunaan

Langkah 1: Pastikan Prasyarat

# PHP 8.0+
php -v

# Ekstensi Redis terinstall
php -m | grep redis

# Redis server berjalan
redis-cli ping # Harus return: PONG

Langkah 2: Deploy Drop-in

# Copy file ke wp-content/
cp object-cache.php /path/to/wordpress/wp-content/

# Pastikan file bisa dibaca web server
chown www-data:www-data /path/to/wordpress/wp-content/object-cache.php

Langkah 3: Verifikasi

Buka /wp-admin dan cek:
  • Tidak ada error PHP/Redis
  • Object cache stats muncul di debug bar (jika pakai)
  • Atau panggil manual: wp_cache_supports('flush_group') → harus return true

Debugging

// Aktifkan logging
define(‘WP_DEBUG’, true);
define(‘WP_DEBUG_LOG’, true);

// Cek status cache
if (isset($GLOBALS[‘wp_object_cache’])) {
echo $GLOBALS[‘wp_object_cache’]->stats();
}


🧪 Testing & Monitoring

Unit Test Edge Cases

// Test null value handling
wp_cache_set(‘test_null’, null, ‘default’);
$found = null;
$val = wp_cache_get(‘test_null’, ‘default’, false, $found);
assert($val === null && $found === true);

// Test group versioning coherence
wp_cache_flush_group(‘options’);
// Key lama di group ‘options’ harus miss, group lain tetap hit

Monitoring di Production

# Redis memory & keys
redis-cli INFO memory
redis-cli DBSIZE

# PHP-FPM memory usage
pm.status_path = /status
curl localhost/status?full

# Log AOC
tail -f /path/to/wp-content/debug.log | grep “\[AOC Redis\]”

🤔 FAQ

Q: Apakah kompatibel dengan plugin Redis Object Cache (Till Krüss)?
A: Tidak. Ini adalah drop-in replacement. Hanya satu object-cache.php yang aktif.
Q: Bagaimana dengan persistent object di Redis?
A: Semua key memiliki TTL (default 30 hari untuk no-expire). Tidak ada key abadi → aman dari memory leak.
Q: Apakah support Redis Cluster/Sentinel?
A: Tidak secara native. Plugin ini dirancang untuk single-node Redis dengan koneksi stabil. Untuk cluster, pertimbangkan proxy seperti Twemproxy di depan.
Q: Bagaimana performa vs APCu-only?
A: Di high-traffic multisite, hybrid L1/L2 ini lebih scalable:
  • L1: ~0.002ms/lookup
  • L2 (Redis local): ~0.3ms/lookup
  • L2 (Redis remote): ~1-3ms/lookup
    Dengan hit ratio 95%+, rata-rata latency < 0.15ms.

🚀 Kesimpulan

Redis Object Cache – Stripped bukan sekadar “cache plugin”. Ini adalah infrastructure component yang dirancang untuk:
  • 🎯 Predictability: Behavior konsisten di semua kondisi (Redis up/down, high/low load)
  • 🔐 Correctness: Koherensi data dijamin lewat versioning + runtime state management
  • Efficiency: Minimal overhead, maksimal throughput
Jika Anda mengelola WordPress di skala enterprise dengan SLA ketat, plugin ini layak dipertimbangkan sebagai bagian dari stack caching Anda.
📥 Download: Whatsapp saya untuk mencoba file drop-in object-cache ini.

Catatan: Plugin ini dikembangkan untuk environment spesifik. Selalu uji di staging sebelum deploy ke production. Backup database & Redis sebelum migrasi cache system.
🔖 Tags: #WordPress #Redis #ObjectCache #HighTraffic #Performance #PHP8 #DevOps

Tinggalkan Balasan