Skip to main content
BlogDevOps

Pola Caching Redis untuk NestJS: Dari 450ms ke 42ms Waktu Respons API

Pola caching Redis praktis untuk NestJS — cache-aside, write-through, dan strategi invalidasi cache dengan contoh kode nyata dan pengukuran performa.

Matthews Wong

Software Engineer

Juni 202510 menit baca
DevOps

Mengimplementasikan caching Redis dalam API NestJS produksi dapat memangkas waktu respons secara drastis dan mengurangi sebagian besar beban database. Bayangkan sebuah endpoint dashboard yang memukul PostgreSQL dengan JOIN 6 tabel yang kompleks pada setiap permintaan: itulah jenis endpoint yang paling diuntungkan oleh cache.

Mengapa Redis Daripada Caching In-Memory

@nestjs/cache-manager default NestJS menggunakan penyimpanan in-memory, yang berfungsi untuk setup single-process tetapi langsung rusak saat Anda melakukan scale ke beberapa instance atau me-restart server. Redis memecahkan kedua masalah: ia bertahan di seluruh restart (opsional), bertahan dari restart container, dan dibagikan di semua instance aplikasi NestJS Anda.

Setup: @nestjs/cache-manager dengan Redis

Instal @nestjs/cache-manager, cache-manager, dan @keyv/redis. Konfigurasikan CacheModule di AppModule Anda dengan Redis store. Setelah dikonfigurasi, Anda dapat menggunakan dekorator @UseInterceptors(CacheInterceptor) pada metode controller mana pun untuk men-cache responsnya secara otomatis, dengan kunci cache yang diturunkan dari rute dan parameter query.

Pola Cache-Aside

Cache-aside (juga disebut lazy loading) adalah pola yang paling umum dan fleksibel. Aplikasi memeriksa cache terlebih dahulu; pada miss, ia mengambil dari database, menyimpan hasilnya di Redis, dan mengembalikannya. Pada permintaan berikutnya, cache hit disajikan langsung. Pola ini memberi Anda kontrol atas apa yang di-cache dan kapan.

┌─────────────────────────────────────────────────────┐
│              CACHE-ASIDE PATTERN FLOW               │
└─────────────────────────────────────────────────────┘

  Request
    │
    ▼
  NestJS Service
    │
    ├─► Redis CACHE ──► HIT ──► Return cached data
    │       │
    │       └─► MISS
    │               │
    │               ▼
    └──────► PostgreSQL DB
                    │
                    ▼
              Store in Redis (TTL)
                    │
                    ▼
              Return to client

Dalam proyek NestJS, gunakan notifikasi keyspace Redis untuk mengimplementasikan invalidasi cache berbasis event daripada hanya kedaluwarsa TTL. Ketika pengguna memperbarui rekaman ERP, publikasikan event invalidasi cache melalui Redis pub/sub. Layanan cache manager terpisah mendengarkan dan langsung menghapus kunci yang terpengaruh.

Strategi Invalidasi Cache

Invalidasi cache adalah masalah tersulit dalam caching. Ada tiga strategi utama: kedaluwarsa berbasis TTL (paling sederhana, tetapi berpotensi menyajikan data basi), invalidasi berbasis event (akurat, tetapi memerlukan sistem event invalidasi), dan caching write-through (perbarui cache dan database bersama-sama saat penulisan, memastikan konsistensi).

Desain Kunci Cache

Desain kunci cache sangat kritis. Gunakan kunci bernama namespace: user:{userId}:profile, report:{reportId}:data, inventory:{productId}. Ini memungkinkan invalidasi yang ditargetkan — ketika pengguna memperbarui profilnya, Anda dapat menghapus user:{userId}:* tanpa menyentuh data pengguna lain.

# Redis configuration — /etc/redis/redis.conf
maxmemory 512mb
maxmemory-policy allkeys-lru
save 900 1
save 300 10

# Redis CLI: check cache hit ratio
redis-cli INFO stats | grep -E "keyspace_hits|keyspace_misses"

# Namespaced key pattern
SET user:1234:profile '{"name":"Matthews","role":"admin"}' EX 300
SET report:5678:data '{"rows":42,"total":150000}' EX 600
DEL user:1234:*   # invalidate single user's cache

# NestJS: manual cache-aside pattern
const cacheKey = 'report:' + reportId + ':data'
const cached = await this.cacheManager.get(cacheKey)
if (cached) return cached
const data = await this.db.getReport(reportId)
await this.cacheManager.set(cacheKey, data, 300)
return data

Pola Lanjutan: Caching Multi-Layer

Untuk endpoint traffic sangat tinggi, pertimbangkan cache dua lapisan: cache LRU in-process berumur pendek (menggunakan node-lru-cache atau serupa) untuk kunci terpanas, didukung oleh Redis untuk cache yang lebih luas. Cache in-process menghilangkan round-trip jaringan Redis untuk data yang paling sering diakses.

Saya pernah men-deploy Redis di VPS 1GB tanpa mengonfigurasi maxmemory dan kebocoran memori di lapisan caching kami mengisi instance sepenuhnya. Redis OOM, crash, dan aplikasi NestJS kami jatuh ke database untuk setiap permintaan secara bersamaan — menyebabkan kegagalan cascade yang membutuhkan 20 menit untuk pulih. Selalu atur maxmemory di redis.conf (misalnya maxmemory 512mb).

Memantau Performa Cache Redis

Lacak metrik Redis ini dalam produksi: keyspace_hits dan keyspace_misses (hitung rasio hit Anda), used_memory vs maxmemory, evicted_keys (bukan nol berarti Anda membutuhkan lebih banyak memori atau kebijakan eviksi yang berbeda), dan connected_clients. Ekspos metrik ini ke Prometheus melalui redis_exporter untuk dashboard Grafana.

Apa yang Sebenarnya Saya Cache

Tidak semua hal harus ada di Redis. Cache data yang mahal untuk dihitung atau diambil (query JOIN kompleks, respons API eksternal, agregat yang dihitung) dan dibaca jauh lebih sering daripada ditulis. Jangan cache data yang harus akurat secara real-time atau data yang sudah cepat diambil.

Sumber & Bacaan Lanjutan

FAQ

Pertanyaan Umum

Jawaban singkat untuk pertanyaan yang paling sering diajukan pembaca tentang topik ini.

Mengapa harus menggunakan Redis dibanding cache in-memory bawaan NestJS?

@nestjs/cache-manager bawaan NestJS menyimpan cache di memori proses, sehingga langsung bermasalah saat di-scale ke beberapa instance atau server di-restart karena setiap instance punya cache terpisah. Redis dibagikan ke semua instance aplikasi NestJS dan tetap ada melewati restart container, menjadikannya optimasi di level sistem, bukan sekadar optimasi lokal.

Seberapa besar peningkatan performa yang realistis dari Redis caching di API NestJS?

Untuk endpoint dashboard yang menjalankan JOIN 6 tabel PostgreSQL yang kompleks pada setiap permintaan, Redis caching dapat menurunkan waktu respons rata-rata secara signifikan, karena sebagian besar permintaan dilayani dari memori, bukan dari database. Peningkatan sebenarnya bergantung pada rasio cache hit, biaya query, dan TTL Anda, jadi ukur sebelum dan sesudahnya.

Apa itu pola cache-aside dan apa trade-off utamanya?

Cache-aside (juga disebut lazy loading) memeriksa cache terlebih dahulu; jika miss, data diambil dari database, disimpan ke Redis, lalu dikembalikan. Trade-off utamanya adalah permintaan pertama setelah cache miss atau kedaluwarsa selalu mengenai database, sehingga cache warming penting untuk endpoint dengan traffic tinggi.

Bagaimana cara merancang struktur kunci cache yang baik di Redis?

Gunakan kunci bernama namespace seperti user:'{userId}':profile atau report:'{reportId}':data. Ini memungkinkan invalidasi yang ditargetkan — misalnya, menghapus user:'{userId}':* hanya membersihkan data satu pengguna tanpa menyentuh pengguna lain. Hindari menggunakan query string mentah sebagai kunci karena bisa sangat panjang dan mengekspos parameter sensitif di output Redis MONITOR; sebaiknya hash parameter yang kompleks.

Apa yang terjadi jika lupa mengatur maxmemory di Redis, dan bagaimana konfigurasi yang tepat?

Tanpa batas maxmemory, kebocoran memori atau pertumbuhan cache yang tak terbatas bisa memenuhi instance sepenuhnya, menyebabkan Redis OOM-crash dan memaksa setiap permintaan NestJS jatuh ke database secara bersamaan — mengakibatkan kegagalan cascade. Selalu atur maxmemory di redis.conf (misalnya maxmemory 512mb) dan pilih kebijakan eviksi seperti allkeys-lru yang mengeluarkan kunci paling jarang dipakai alih-alih crash.