L
Next.js & SSR Architecture 🚨 Post-Mortem & Incident Runbook • Literally Web ID

Arsitektur Resilien Next.js SSR dengan Edge Caching Cloudflare

⏱️ 15 menit baca • 📅 20 Oct 2026 • 👁️ 2 views
Arsitektur Resilien Next.js SSR dengan Edge Caching Cloudflare
🔊 Dengarkan Artikel Ini

1. Alarm Tengah Malam: Saat Layanan Produksi Mulai Tumbang

Pukul 02.14 WIB. PagerDuty di ponsel saya menjerit melengking, membangunkan tidur nyenyak saya dengan ritme yang hanya bisa diartikan satu hal: produksi sedang sekarat. Sembari menyapu mata, saya membuka laptop di atas meja kerja yang remang-remang. Dashboard Grafana menampilkan pemandangan yang membuat jantung berdegup kencang: latensi p99 loncat dari biasanya 180 milidetik menjadi lebih dari 8.50onan detik, sementara Error Rate HTTP 504 Gateway Timeout merangkak naik menyentuh angka 42%. Di saat yang sama, kluster Kubernetes yang menjalankan aplikasi Node.js kami berteriak minta tolong karena utilisasi CPU menembus batas kritis 98%, disusul oleh metrik connection pool database MySQL yang jebol akibat antrean ribuan koneksi paralel yang menggantung.

# Pengecekan awal kesehatan pod Kubernetes saat insiden
kube-ctl get pods -n production | grep nextjs-ssr
# Hasilnya mencengangkan: 12 dari 15 pod mengalami OOMKilled atau restart loop secara konstan

Pengguna di luar sana mengeluh tidak bisa mengakses halaman utama portal e-commerce kami yang sedang menggelar kampanye flash sale tengah malam. Beban trafik melonjak hingga 45.000 req/s, melampaui kapasitas normal harian sebanyak sepuluh kali lipat. Namun, yang membuat saya penasaran bukanlah tingginya volume trafik itu sendiri, melainkan mengapa aplikasi Next.js dengan fitur Server-Side Rendering (SSR) yang biasanya tangguh ini mendadak kolaps begitu cepat. Untuk menjawab misteri ini, kita harus menyelami apa yang sebenarnya terjadi di balik layar mesin Node.js ketika ribuan request masuk secara bersamaan.

2. Jejak Digital: Menelusuri Anomali Log & Lonjakan Metrik

Tanpa membuang waktu, saya langsung melompat ke terminal untuk mengekstrak log akses dari Nginx reverse proxy yang berada di garda terdepan sebelum trafik diteruskan ke aplikasi Node.js. Menggunakan mantra awk dan grep kesayangan, saya menyaring pola akses yang masuk pada detik-detik sebelum alarm berbunyi.

# Membedah log Nginx untuk mencari URL yang paling sering direquest dan membebani server
cat /var/log/nginx/access.log | awk '{print $7}' | sort | uniq -c | sort -nr | head -n 10

Hasilnya langsung menunjuk pada halaman produk dan kategori utama. Masalahnya, meskipun halaman-halaman tersebut dirender secara dinamis menggunakan getServerSideProps di Next.js untuk mengambil data stok real-time dari database MySQL, setiap request ternyata memaksa Node.js melakukan eksekusi JavaScript yang berat secara berulang-ulang. Tidak ada satupun byte respons yang singgah di cache layer luar. Akibatnya, setiap kali seorang pengguna merefresh halaman, Node.js harus memproses ulang komponen React, melakukan serialization HTML, dan memanggil kueri SQL yang sama persis ke database secara masif. Ini adalah definisi klasik dari Anatomi SSR Bottleneck di Node.js—di mana arsitektur SSR yang tidak diimbangi dengan strategi caching yang tepat berubah menjadi bumerang yang mencekik backend-nya sendiri. Database MySQL kami kewalahan melayani pembacaan berulang, connection pool habis terkuras, dan Node.js yang sifatnya single-threaded langsung kehabisan napas memproses beban CPU yang tidak perlu ini. Dari sinilah, jejak digital mengarahkan kita pada akar masalah yang sebenarnya.

3. Membongkar Biang Kerok: Akar Masalah yang Sebenarnya

Setelah menggali lebih dalam ke dalam kode sumber dan konfigurasi infrastruktur, kami menemukan tiga dosa besar arsitektur yang saling bersekongkol menjatuhkan sistem:

  1. Absennya Edge Caching: Cloudflare dikonfigurasi secara naif hanya meneruskan seluruh trafik dinamis langsung ke origin server tanpa instruksi cache yang jelas melalui header Cache-Control. Setiap request dianggap unik dan bypass total dari jaringan global Cloudflare.
  2. Kueri Database yang Redundan: Di dalam fungsi getServerSideProps, terdapat pemanggilan kueri SQL kompleks tanpa memanfaatkan in-memory cache seperti Redis untuk data referensi yang sifatnya semi-statis.
  3. Kesalahpahaman Konsep ISR: Tim sebelumnya mencoba mengandalkan Incremental Static Regeneration (ISR), namun gagal menerapkannya pada halaman dengan trafik tinggi karena salah mengatur parameter revalidate dan mengabaikan karakteristik invalidasi di tingkat edge CDN.

[!WARNING] Mengandalkan SSR murni tanpa lapisan edge caching pada platform berskala besar adalah undangan terbuka bagi bencana latensi dan kegagalan infrastruktur total.

Untuk mengatasi hal ini, kita harus mengubah paradigma: jangan biarkan origin server Node.js bekerja keras untuk hal-hal yang bisa dilayani oleh edge server Cloudflare yang tersebar di ratusan kota di seluruh dunia. Mari kita lihat bagaimana kita merombak total strategi pertahanan ini.

4. Tindakan Darurat: Menghidupkan Kembali Layanan dalam Hitungan Menit

Di tengah situasi genting, kami memerlukan tindakan bedah darurat yang bisa dieksekusi dalam hitungan detik untuk menyelamatkan sistem dari kehancuran total. Langkah pertama adalah memaksa Cloudflare untuk menahan beban dengan mengaktifkan Cache Everything secara agresif melalui Cloudflare Page Rules dan menyuntikkan header Cache-Control yang tepat langsung dari aplikasi Next.js.

Berikut adalah cuplikan kode pada file konfigurasi Next.js (next.config.js) atau pada fungsi SSR untuk memaksa browser dan Cloudflare melakukan edge caching dengan mekanisme Stale-While-Revalidate:

// next.config.js atau penanganan header respons kustom di middleware Next.js
export async function middleware(req) {
  const res = NextResponse.next();
  
  // Beritahu Cloudflare dan Browser untuk menyimpan cache halaman selama 60 detik,
  // dan tetap melayani versi stale selama 60 detik berikutnya saat background revalidation berjalan.
  res.headers.set(
    'Cache-Control',
    'public, s-maxage=60, stale-while-revalidate=60'
  );
  
  return res;
}

Selain itu, untuk meredakan amukan trafik pada database MySQL, kami segera mengaktifkan kembali Redis sebagai lapisan penengah data referensi:

// Contoh implementasi singkat koneksi Redis di backend Go/Node untuk caching data referensi
const getCachedProductData = async (productId) => {
  const cachedData = await redisClient.get(`product:${productId}`);
  if (cachedData) {
    return JSON.parse(cachedData);
  }
  
  const freshData = await db.query('SELECT * FROM products WHERE id = ?', [productId]);
  await redisClient.setex(`product:${productId}`, 30, JSON.stringify(freshData));
  return freshData;
};

[!TIP] Penggunaan header s-maxage bersama stale-while-revalidate adalah senjata paling ampuh untuk meredam lonjakan trafik mendadak tanpa mengorbankan kesegaran data bagi pengguna akhir.

Dengan menerapkan one-liner pembersihan cache di Cloudflare API dan memperbarui header respons tersebut, kurva latensi di Grafana mulai melandai drastis dalam waktu kurang dari 3 menit setelah deployment darurat disebar.

5. Kebijakan Retrospektif: Menambal Celah agar Tak Pernah Terulang

Badai telah berlalu, kini saatnya duduk bersama tim untuk merumuskan kebijakan defensif jangka panjang agar insiden serupa tidak terulang di masa depan. Kami menyadari bahwa arsitektur web modern menuntut pergeseran dari pure SSR ke Edge-First Architecture.

Berikut adalah perbandingan strategi caching yang kini kami adopsi secara ketat:

Aspek Evaluasi Sebelum Insiden (Naif SSR) Sesudah Perbaikan (Edge-Resilient SSR)
Lokasi Render 100% di Origin Node.js Hybrid: Edge CDN + Background ISR
Beban Database MySQL Tinggi (Kueri masif per request) Rendah (Teredam Redis & Edge Cache)
Header Cache-Control Tidak terdefinisi / no-cache public, s-maxage=60, stale-while-revalidate=60
Latensi p99 > 8500 ms < 220 ms

Kami juga memperketat aturan code review di mana setiap penambahan halaman baru yang menggunakan getServerSideProps wajib menyertakan dokumen spesifikasi strategi cache dan persetujuan dari tim infrastruktur. Dengan cara ini, kolaborasi antara frontend dan infrastructure engineer menjadi lebih erat dan terarah.

6. Pasang Alarm: Otomasi Deteksi Dini untuk Tim On-Call

Sebagai penutup dari rangkaian mitigasi ini, kami tidak ingin lagi bergantung pada laporan pengguna atau lonjakan error yang terlambat disadari. Kami membangun sistem monitoring proaktif menggunakan Prometheus dan Alertmanager yang terintegrasi langsung dengan webhook PagerDuty.

Berikut adalah aturan alerting Prometheus yang kami pasang untuk mendeteksi dini anomali pada latensi edge dan tingkat error gateway sebelum mereka berubah menjadi bencana tengah malam:

groups:
  - name: edge-ssr-alerts
    rules:
      - alert: HighEdgeLatencyP99
        expr: histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le)) > 0.5
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "Latensi p99 melebihi 500ms selama 2 menit berturut-turut!"
          description: "Aplikasi Next.js mengalami perlambatan signifikan di edge atau origin. Segera periksa metrik CPU dan database connection pool."

      - alert: SpikeHTTP504GatewayTimeout
        expr: sum(rate(http_requests_total{status="504\
🏷️ Tags: #Nginx #High Concurrency #Performance #Sysadmin #Web Server

Apakah panduan tutorial ini membantu Anda?

Masukan Anda sangat berharga untuk terus memperbarui dan menyempurnakan kualitas materi teknis kami.

🎉

Terima kasih banyak atas apresiasi Anda!

Tim kami terus menyempurnakan tutorial agar selalu akurat dengan versi teknologi terbaru.

Bantu Kami Menyempurnakan Materi Ini

⚡ Literally Tech Digest

Update Tutorial & Developer Tools Terbaru Langsung ke Email Anda

Dapatkan kurasi artikel arsitektur software, tips DevOps, panduan database, serta rilis fitur developer utility gratis setiap minggu. Bebas spam, bisa berhenti kapan saja.

⏳ Mencari artikel...
Tutorial & Artikel Terkait
Developer Tools
Tidak ditemukan tutorial atau tool dengan kata kunci "".
Ketik minimal 2 karakter untuk mencari artikel atau nama tools.
Tekan ESC untuk menutup Cari di Semua Artikel →