BelajarKoding Logobelajarkoding

Platform belajar web development Indonesia. Artikel, cheat sheets, roadmap, dan code challenges untuk developer Indonesia.

Navigasi

  • Artikel
  • Cheat Sheets
  • Roadmap
  • Challenges
  • Pricing
  • Search

Produk Lain

  • JagoHermes
  • KelasClaude
  • KilatKoding
  • BelajarVibeCoding
  • JualanKoding

Support

  • Privacy Policy
  • Terms of Service
  • Email

© 2026 BelajarKoding. All rights reserved.

Galih PratamaBagian dari ekosistem Galih Pratama
belajarkoding LogobyGalih Pratama
RoadmapArtikelCheat SheetsChallengesUpgrade
belajarkoding LogobyGalih Pratama
RoadmapArtikelCheat SheetsChallengesUpgrade
belajarkoding LogobyGalih Pratama
RoadmapArtikelCheat SheetsChallengesUpgrade

Daftar Isi

Cache Patterns (Konsep)Cache-Aside (Lazy Loading)Read-ThroughWrite-ThroughWrite-Behind (Write-Back)Pattern ComparisonEviction PoliciesCache InvalidationTTL (Time To Live)LRU (Least Recently Used)LFU (Least Frequently Used)HTTP CachingCache HeadersCache Strategies di Next.jsBrowser CacheCDN CachingCloudflare Cache RulesCache Key DesignAdvanced: Distributed Cache PatternsSession StorageRate LimitingDistributed LockCache Stampede PreventionCache PenetrationCache AvalancheGlossary
CachingPerformanceWeb

Caching Strategies Cheat Sheet

Referensi cepat caching strategies untuk web developer. HTTP cache headers, CDN, browser cache, Service Worker, eviction policies, dan cache invalidation patterns.

JavaScript7 min read1.343 kata
Silakan login atau daftar untuk membaca cheat sheet ini.

#Cache Patterns (Konsep)

4 pattern utama caching di application layer. Untuk implementasi code lengkap dengan Redis, lihat artikel /artikel/redis-untuk-caching.

#Cache-Aside (Lazy Loading)

Aplikasi cek cache dulu, kalau miss, fetch dari database dan simpan ke cache.

text
App --> [Cache hit?] --yes--> return cached
                   --no---> [Fetch DB] --> [Set Cache] --> return

Kapan pakai: data yang read-heavy, jarang berubah. Default choice buat kebanyakan apps. Trade-off: cold cache miss = 3x latency (cek cache + query DB + set cache).

#Read-Through

Cache layer yang otomatis fetch dari database kalau miss. Aplikasi cuma ngobrol sama cache library (contoh: cache-manager, Spring Cache).

text
App --> Cache Library --> [Cache hit?] --yes--> return
                                     --no---> [Auto-fetch DB] --> [Set Cache] --> return

Aplikasi ngga peduli cache ada atau ngga. Library handle semuanya.

#Write-Through

Setiap write ke database juga write ke cache secara sinkron.

text
App --> [Write DB] --> [Write Cache] --> return (both updated)

Kapan pakai: data yang sering dibaca setelah di-update. Konsistensi tinggi. Trade-off: write latency lebih tinggi (2x write operations).

#Write-Behind (Write-Back)

Write ke cache dulu, database di-update asynchronously via queue.

text
App --> [Write Cache] --> return (fast!)
                     [Background worker: drain queue --> DB]

Kapan pakai: high-write scenarios (metrics, analytics, counters) di mana toleransi data loss kecil.

#Pattern Comparison

PatternRead LatencyWrite LatencyConsistencyComplexity
Cache-AsideHigh on missLowEventualLow
Read-ThroughLowLowEventualMedium
Write-ThroughLowHighStrongMedium
Write-BehindLowVery LowWeakHigh

#Eviction Policies

#Cache Invalidation

Strategi invalidasi cache saat data berubah.

javascript
// Explicit invalidation
async function deleteUser(id) {
  await db.query('DELETE FROM users WHERE id = $1', [id]);
  await redis.del(`user:${id}`);
}
 
// Tag-based invalidation (banyak key sekaligus)
async function updatePost(postId, data) {
  await db.query('UPDATE posts SET ... WHERE id = $1', [postId]);
 
  // Hapus cache post + semua list yang berisi post
  await redis.del(`post:${postId}`);
  await redis.del('posts:list');
  await redis.del('posts:featured');
}
 
// Version-based invalidation
const CACHE_VERSION = 'v2';
async function getUser(id) {
  return cache.wrap(`user:${id}:${CACHE_VERSION}`, fetchUser);
}
// Ganti CACHE_VERSION = 'v3' untuk invalidate semua sekaligus

#TTL (Time To Live)

javascript
// Redis TTL
await redis.set('key', 'value', 'EX', 3600);     // expire dalam 1 jam
await redis.set('key', 'value', 'PX', 60000);     // expire dalam 1 menit (ms)
await redis.expire('key', 3600);                   // set TTL pada key existing
await redis.persist('key');                        // hapus TTL (persistent)
await redis.ttl('key');                            // cek sisa TTL
 
// Strategi TTL per data type:
// - User session: 30 menit - 24 jam
// - Product catalog: 1-6 jam
// - Configuration: 5 menit
// - Analytics: 1-5 menit
// - Static content: 24+ jam

#LRU (Least Recently Used)

Cache otomatis hapus item yang paling lama tidak diakses.

javascript
// Redis maxmemory dengan LRU
// redis.conf:
// maxmemory 256mb
// maxmemory-policy allkeys-lru
 
// Atau via command
// CONFIG SET maxmemory 256mb
// CONFIG SET maxmemory-policy allkeys-lru
 
// JavaScript LRU implementation
class LRUCache {
  constructor(maxSize = 100) {
    this.maxSize = maxSize;
    this.cache = new Map();
  }
 
  get(key) {
    if (!this.cache.has(key)) return undefined;
    const value = this.cache.get(key);
    this.cache.delete(key);
    this.cache.set(key, value); // move to end (most recent)
    return value;
  }
 
  set(key, value) {
    if (this.cache.has(key)) {
      this.cache.delete(key);
    } else if (this.cache.size >= this.maxSize) {
      // Delete oldest (first entry)
      const oldestKey = this.cache.keys().next().value;
      this.cache.delete(oldestKey);
    }
    this.cache.set(key, value);
  }
}

#LFU (Least Frequently Used)

Hapus item yang paling jarang diakses berdasarkan frekuensi.

javascript
// Redis config
// maxmemory-policy allkeys-lfu
// LFU menggunakan probabilistic counter + decay
 
// Manual LFU di JavaScript
class LFUCache {
  constructor(maxSize = 100) {
    this.maxSize = maxSize;
    this.cache = new Map();      // key -> { value, freq }
  }
 
  get(key) {
    if (!this.cache.has(key)) return undefined;
    const entry = this.cache.get(key);
    entry.freq++;
    return entry.value;
  }
 
  set(key, value) {
    if (this.cache.size >= this.maxSize && !this.cache.has(key)) {
      // Find least frequently used
      let minKey, minFreq = Infinity;
      for (const [k, v] of this.cache) {
        if (v.freq < minFreq) {
          minFreq = v.freq;
          minKey = k;
        }
      }
      this.cache.delete(minKey);
    }
    this.cache.set(key, { value, freq: 1 });
  }
}

#HTTP Caching

#Cache Headers

http
# Cache-Control (paling powerful)
Cache-Control: public, max-age=3600           # cache 1 jam
Cache-Control: private, max-age=0              # browser only, no CDN
Cache-Control: no-cache                         # revalidate setiap kali
Cache-Control: no-store                         # never cache
Cache-Control: max-age=31536000, immutable      # 1 tahun, tidak akan berubah
Cache-Control: public, max-age=3600, s-maxage=86400  # browser 1jam, CDN 1hari
 
# ETag (content fingerprint)
ETag: "abc123"
# Response berikutnya bisa:
If-None-Match: "abc123"
# Server balas 304 Not Modified kalau sama
 
# Last-Modified
Last-Modified: Wed, 21 Jun 2026 09:00:00 GMT
If-Modified-Since: Wed, 21 Jun 2026 09:00:00 GMT
 
# Vary (cache key berdasarkan header)
Vary: Accept-Encoding, Accept-Language

#Cache Strategies di Next.js

javascript
// Next.js 16 Cache Components
import { unstable_cache } from 'next/cache';
 
// Cache function result
const getCachedUser = unstable_cache(
  async (id) => {
    return await db.user.findById(id);
  },
  ['user'],          // cache key prefix
  {
    revalidate: 3600, // revalidate every hour
    tags: ['users'],  // for on-demand revalidation
  }
);
 
// On-demand revalidation
import { revalidateTag } from 'next/cache';
revalidateTag('users');

#Browser Cache

javascript
// Service Worker cache
const CACHE_NAME = 'app-v1';
const ASSETS = ['/', '/styles.css', '/app.js'];
 
self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(CACHE_NAME).then(cache => cache.addAll(ASSETS))
  );
});
 
self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request).then(cached => {
      return cached || fetch(event.request);
    })
  );
});

#CDN Caching

#Cloudflare Cache Rules

javascript
// Cloudflare Page Rules (via Wrangler atau dashboard)
// Cache everything untuk API responses
{
  "matches": ["api.example.com/*"],
  "cache": {
    "edgeTtl": 3600,
    "browserTtl": 60
  }
}
 
// Vercel Edge Config + cache
export const config = {
  runtime: 'edge',
};
 
export default async function handler(req) {
  const data = await getData();
  return new Response(JSON.stringify(data), {
    headers: {
      'Cache-Control': 's-maxage=3600, stale-while-revalidate=86400',
    },
  });
}

#Cache Key Design

javascript
// Cache key yang baik: specific, hierarchical, versionable
 
// BAD: terlalu generik
redis.set('data', JSON.stringify(data));
 
// GOOD: namespaced + specific
redis.set('user:123:profile', JSON.stringify(data));
redis.set('posts:list:page:1:limit:10', JSON.stringify(data));
redis.set('api:v2:search:q=hello:sort=date', JSON.stringify(data));
 
// Version key buat bulk invalidation
redis.set('v2:user:123:profile', data);
// Ganti v2 -> v3 untuk invalidate semua user caches

#Advanced: Distributed Cache Patterns

Pattern ini umum di sistem dengan Redis atau Memcached. Implementasi code lengkap ada di artikel /artikel/redis-untuk-caching.

#Session Storage

Simpan session user di cache (bukan di memory server) buat horizontal scaling. Express + connect-redis, NextAuth + Upstash, atau Django + django-redis.

#Rate Limiting

Fixed window (counter per period) atau sliding window (sorted set per timestamp). Cache sebagai single source of truth buat count across multiple server instances.

#Distributed Lock

Mutex lock across multiple server instances pakai SET NX (set-if-not-exists). Release pakai Lua script buat atomic check-and-delete.

#Cache Stampede Prevention

Saat cache miss bersamaan (1000 request datang bareng), pakai mutex lock biar cuma 1 request yang fetch dari DB. Request lain nunggu dan baca cache setelahnya.

#Cache Penetration

Query buat data yang ngga ada di DB. Cache miss terus. Solusi: cache null result juga (dengan TTL pendek).

#Cache Avalanche

Banyak entry expire barengan. Solusi: randomize TTL (base_ttl + random(0, 60)).

#Glossary

  • Cache Hit: Data ditemukan di cache. Tidak perlu query database.
  • Cache Miss: Data tidak ada di cache. Harus fetch dari database.
  • TTL (Time To Live): Waktu sebelum cache entry expire dan dihapus otomatis.
  • LRU: Least Recently Used. Eviction policy yang hapus item paling lama tidak diakses.
  • LFU: Least Frequently Used. Eviction policy yang hapus item paling jarang diakses.
  • Cache Stampede: Banyak request datang bersamaan saat cache miss, semua query database sekaligus. Bisa bikin database down.
  • Cache Penetration: Query untuk data yang tidak ada di database. Cache miss setiap kali. Solusi: cache null result juga.
  • Cache Avalanche: Banyak cache entry expire bersamaan. Solusi: randomize TTL.
  • Invalidation: Proses menghapus atau update cache saat data source berubah.
  • Stale-While-Revalidate: Serve stale cache sambil fetch data baru di background.
  • Edge Cache: Cache yang disimpan di CDN edge location, dekat dengan user.
  • ETag: Hash/fingerprint content yang dipake buat validasi apakah cache masih valid.

Baca Cheat Sheet Lengkap

Login atau daftar akun gratis untuk membaca cheat sheet ini.

LoginDaftar Gratis
Share: