CDN (Content Delivery Network) adalah jaringan server di banyak kota yang menyimpan salinan file situsmu dekat dengan pengunjung. Bayangin gudang pusat sebuah toko ada di Amerika, tapi tokonya punya minimarket di Jakarta. Barang yang sudah ada di rak minimarket langsung kamu bawa pulang. Kalau belum ada, minimarket memesannya dari gudang pusat, kamu menunggu lama, dan minimarket menyimpan satu salinan buat pembeli berikutnya. Label di barangnya bilang berapa lama boleh dipajang.
🧪 Tebakan cepat:
app.js(tanpa hash di namanya) dikirim denganCache-Control: public, max-age=31536000, immutable. Kamu mengubah isinya, lalu purge CDN. Pengunjung yang kemarin sudah membuka situsmu dapat versi baru? Tebak dulu, jawabannya ada di bagian "Purge, cache key, dan nama file ber-hash".
Istilah dulu
- Origin: server aslimu, tempat aplikasi dan database berada.
- Edge (atau PoP, Point of Presence): server CDN di kota dekat pengunjung, misalnya Jakarta.
- HIT: edge sudah punya salinan dan langsung menjawab. MISS: belum punya, jadi bertanya ke origin.
- TTFB (Time to First Byte): waktu dari request dikirim sampai byte pertama jawaban tiba.
- Cek di tab Network DevTools: header
x-cache: HIT(di Cloudflare namanyacf-cache-status) danage: 120, umur salinannya dalam detik.
Satu request, empat tempat
Lab di halaman ini mengirim request dari Jakarta ke origin di Amerika Serikat. Angkanya perkiraan yang masuk akal: ke edge Jakarta sekitar 15 ms pulang-pergi, dari edge ke origin sekitar 230 ms pulang-pergi, aplikasi di origin sekitar 40 ms, dan query database sekitar 60 ms. File statis cukup sekitar 5 ms di origin, tanpa database.
Kejadian, file app.3f9a1c.js |
Browser cache | Edge Jakarta | Origin | Total, sekitar |
|---|---|---|---|---|
| Kamu, request pertama | MISS | MISS | ditanya | 15 + 230 + 5 = 250 ms |
| Pengunjung lain di Jakarta | MISS (browser-nya sendiri) | HIT | gak ditanya | 15 ms |
| Kamu lagi, besoknya | HIT | gak ditanya | gak ditanya | 0 ms |
Halaman HTML yang MISS lebih mahal lagi: 15 + 230 + 40 + 60 = 345 ms. Cache browser milik satu orang, cache edge dipakai bersama semua pengunjung di kota itu. Itulah untungnya CDN: satu MISS, ribuan HIT.
Cache-Control: siapa boleh menyimpan, berapa lama
Origin memberi label lewat header Cache-Control. CDN dan browser mengikutinya.
Cache-Control: public, max-age=31536000, immutable
Cache-Control: public, max-age=60, s-maxage=86400
Cache-Control: public, max-age=0, s-maxage=60, stale-while-revalidate=600
Cache-Control: no-cache
Cache-Control: private, no-store
public: semua cache boleh menyimpan, termasuk CDN.private: cuma browser pengunjung itu.max-age=60: segar selama 60 detik, berlaku untuk semua cache, termasuk browser.31536000detik itu satu tahun.s-maxage=86400: khusus shared cache (CDN dan proxy), dan di sana menggantikanmax-age. Baris kedua artinya browser menyimpan 1 menit, CDN menyimpan 1 hari.no-cache: boleh disimpan, tapi harus dicek ke origin setiap kali sebelum dipakai.no-store: jangan disimpan sama sekali.immutable: isinya gak akan pernah berubah, jadi browser gak mengecek ulang walau halaman di-reload.stale-while-revalidate=600: setelah habis masa segarnya, salinan lama masih boleh dipakai sampai 600 detik lagi, sambil mengambil yang baru di background.
stale-while-revalidate di edge
Dengan baris ketiga (s-maxage=60, stale-while-revalidate=600) untuk halaman /, ini yang terjadi di Lab:
| Waktu | Status di edge | Total, sekitar |
|---|---|---|
| Menit ke-0 | MISS, simpan | 345 ms |
| +1 menit (umur 60 detik) | STALE: salinan lama dikirim, edge mengambil yang baru di background | 15 ms |
| +1 jam | MISS, sudah lewat 60 + 600 detik | 345 ms |
Pengunjung yang datang saat STALE gak menunggu origin sama sekali.
Purge, cache key, dan nama file ber-hash
Cache key adalah "nama" yang dipakai CDN untuk menentukan dua request itu file yang sama: biasanya URL lengkap termasuk query string, jadi /app.js?v=2 beda dengan /app.js. Header yang disebut di Vary (misalnya Accept-Encoding) juga ikut.
Purge menghapus salinan di edge sebelum waktunya: per URL, atau per tag. Response bisa diberi label Cache-Tag: product-123 (Cloudflare) atau Surrogate-Key: product-123 (Fastly). Saat produk 123 berubah, purge tag itu saja: semua halaman yang memuatnya terhapus, cache lain tetap utuh.
Tapi purge cuma membersihkan CDN, bukan browser pengunjung. Pengunjung kemarin tetap memakai app.js lama dari cache browser-nya, sampai setahun. Itu jawaban tebakannya. Solusinya nama file ber-hash: app.3f9a1c.js. Isinya berubah, hash-nya berubah, URL-nya baru, jadi gak ada cache yang punya salinannya. Karena URL lama dijamin gak pernah berubah isinya, max-age=31536000, immutable aman. HTML yang memuat nama-nama file itu diberi cache pendek atau no-cache.
Edge function: kode yang jalan di edge
CDN modern bisa menjalankan JavaScript-mu langsung di edge, tanpa bolak-balik ke origin: Cloudflare Workers, Netlify Edge Functions, Vercel. Cocok untuk redirect per negara, A/B test, atau cek login sederhana.
// Cloudflare Worker
export default {
async fetch(request) {
const country = request.cf?.country; // diisi Cloudflare, misalnya "ID"
if (country === 'ID') return Response.redirect('https://tokoku.com/id', 302);
return fetch(request); // sisanya lewat cache dan origin seperti biasa
},
};
Versi latihan: parseCacheControl dan hit ratio
Cache hit ratio adalah persen request yang dijawab dari cache: cacheHits / totalRequests × 100. Untuk file statis, targetnya di atas 90%.
| Panggilan | Hasil |
|---|---|
parseCacheControl('public, max-age=31536000, immutable') |
{ maxAge: 31536000, isPublic: true, noStore: false, immutable: true } |
parseCacheControl('no-store') |
{ maxAge: 0, isPublic: false, noStore: true, immutable: false } |
parseCacheControl('no-cache') |
{ maxAge: 0, isPublic: false, noStore: false, immutable: false } |
calculateCacheHitRatio(1000, 920) |
92 |
calculateCacheHitRatio(3, 1) |
33.33 |
calculateCacheHitRatio(0, 0) |
0 |
- Pecah header di koma lalu
trim(), karena ada spasi setelah koma:'public, max-age=3600'.split(',')menghasilkan'public'dan' max-age=3600'. maxAgeharus angka:Number('3600'), bukan string'3600'. Tanpamax-age, nilainya0.- Pembulatan 2 desimal yang tetap angka:
Math.round((hits / total) * 10000) / 100.toFixed(2)menghasilkan string'33.33', dan itu beda dengan angka33.33.
⚠️ Jebakan yang sering ketemu
- Mengira
no-cacheartinya "jangan simpan". Ituno-store.no-cachetetap disimpan, cuma dicek dulu setiap kali. max-agepanjang di file tanpa hash. Purge gak menjangkau browser, jadi pengunjung terjebak di versi lama.- Data pribadi dengan
public. CDN bisa mengirim isi keranjang satu orang ke orang lain. Data per user pakaiprivateatauno-store. - Query string acak di URL seperti
?t=1712345. Cache key-nya beda setiap kali, jadi selalu MISS. - Di latihan: urutan key harus
maxAge,isPublic,noStore,immutable, dan hit ratio dikembalikan sebagai angka,0kalautotalRequests0.
TL;DR: CDN menyimpan salinan di edge dekat pengunjung: HIT dari edge Jakarta sekitar 15 ms, MISS ke origin di Amerika sekitar 250 sampai 345 ms. Cache-Control mengatur siapa boleh menyimpan dan berapa lama: max-age untuk semua cache, s-maxage khusus CDN, no-cache simpan tapi cek dulu, no-store jangan simpan, immutable gak pernah berubah, stale-while-revalidate kirim yang lama sambil mengambil yang baru. Cache key biasanya URL lengkap. Purge membersihkan CDN (per URL atau per tag lewat Cache-Tag/Surrogate-Key), tapi bukan browser, jadi aset diberi nama file ber-hash plus max-age=31536000, immutable. Edge function menjalankan kode di edge. Hit ratio = hits / total × 100, targetnya di atas 90%.