Redis sebagai cache layer di Laravel bekerja dengan pola sederhana: sebelum menjalankan query atau perhitungan mahal, aplikasi mengecek Redis; kalau datanya ada, langsung dipakai, kalau tidak, dihitung lalu disimpan untuk permintaan berikutnya. Dengan Cache::remember(), pola ini cukup satu baris. Tantangan sebenarnya ada di menentukan apa yang di-cache, berapa lama, dan kapan cache dihapus saat data berubah.

Setup Redis di Laravel

# .env
CACHE_STORE=redis
REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379

Ekstensi PHP phpredis lebih cepat. Kalau tidak bisa dipasang, gunakan paket predis/predis dan set REDIS_CLIENT=predis. Di environment Docker, host Redis adalah nama service, seperti dijelaskan di Docker untuk Laravel.

Cek koneksi:

php artisan tinker --execute 'Cache::put("tes", "ok", 60); echo Cache::get("tes");'

Pola Dasar: Cache-Aside dengan Redis

$categories = Cache::remember('categories:menu', now()->addHour(), function () {
    return Category::query()
        ->withCount('posts')
        ->orderBy('sort_order')
        ->get(['id', 'name', 'slug']);
});
  • Kunci yang jelas: pakai pola entitas:keterangan:id, misalnya product:detail:42.
  • TTL masuk akal: data yang jarang berubah (menu, pengaturan) bisa berjam-jam; data yang sering berubah (stok) cukup hitungan detik atau tanpa cache.
  • Simpan data sederhana: array atau koleksi kecil lebih aman daripada model dengan banyak relasi yang ikut terserialisasi.

Invalidasi: Hapus Cache Saat Data Berubah

Data basi biasanya terjadi karena cache tidak dihapus saat data diubah. Hubungkan penghapusan cache ke event model:

class Category extends Model
{
    protected static function booted(): void
    {
        static::saved(fn () => Cache::forget('categories:menu'));
        static::deleted(fn () => Cache::forget('categories:menu'));
    }
}

Untuk data per entitas:

// baca
$product = Cache::remember("product:detail:{$id}", now()->addMinutes(30),
    fn () => Product::with('images')->findOrFail($id)->toArray());

// saat produk diperbarui
Cache::forget("product:detail:{$product->id}");

Cache tags untuk menghapus banyak kunci sekaligus

Cache::tags(['products'])->remember("product:list:page:{$page}", 600, fn () => ...);

// hapus semua daftar produk saat ada perubahan
Cache::tags(['products'])->flush();

Tags hanya didukung driver tertentu seperti Redis dan Memcached, tidak untuk driver file atau database.

Mencegah Cache Stampede

Saat cache populer kedaluwarsa, ratusan request bisa menjalankan query mahal yang sama secara bersamaan. Dua cara mengatasinya:

Lock

$report = Cache::get('report:daily');

if ($report === null) {
    $report = Cache::lock('report:daily:lock', 30)->block(10, function () {
        return Cache::remember('report:daily', now()->addHour(), fn () => DailyReport::build());
    });
}

Flexible cache (stale-while-revalidate)

$stats = Cache::flexible('dashboard:stats', [300, 900], fn () => Stats::compute());

Dengan Cache::flexible(), data dianggap segar selama 5 menit. Antara menit 5 sampai 15, pengguna tetap mendapat data lama sementara nilai baru dihitung di belakang layar. Setelah 15 menit, data dihitung ulang seperti biasa.

Apa yang Layak Di-cache

LayakHati-hatiJangan
Menu, kategori, pengaturan situsDaftar produk dengan filter (banyak kombinasi kunci)Saldo, stok saat checkout
Hasil agregasi laporanData per pengguna (jumlah kunci membengkak)Data yang wajib selalu real-time
Respons API pihak ketigaHalaman dengan konten pribadiToken atau rahasia tanpa enkripsi

Redis untuk Queue dan Session

QUEUE_CONNECTION=redis
SESSION_DRIVER=redis

Redis cocok untuk queue karena cepat dan mendukung Laravel Horizon untuk memantau job. Kalau cache, queue, dan session memakai satu server Redis, pisahkan database atau koneksinya di config/database.php. Dengan begitu Cache::flush() tidak ikut menghapus antrean job dan session login pengguna.

Memantau

redis-cli INFO memory      # pemakaian memori
redis-cli INFO stats       # keyspace_hits dan keyspace_misses
redis-cli --bigkeys        # kunci yang paling besar

Rasio hit yang rendah menandakan kunci terlalu bervariasi atau TTL terlalu pendek. Atur maxmemory dan kebijakan maxmemory-policy (misalnya allkeys-lru untuk server khusus cache) agar Redis tidak kehabisan memori.

Kesalahan yang Sering Terjadi

  • Cache tanpa invalidasi, sehingga admin mengubah data tapi pengunjung tetap melihat versi lama.
  • Cache::flush() di production yang ikut menghapus session dan job karena satu database Redis.
  • Cache untuk menutupi query buruk. Perbaiki query dan index dulu; caranya di MySQL performance tuning.
  • Redis terbuka ke internet tanpa password. Ikat ke localhost atau jaringan privat.

Langkah Berikutnya

Redis juga dipakai untuk fitur real-time dan scaling WebSocket, dibahas di Laravel Reverb. Untuk struktur aplikasi yang mudah diberi cache, lihat Laravel 12 best practices.