Database 4 min read

Arsitektur Caching SvelteKit: Mengoptimalkan Kecepatan Turso SQLite dengan Upstash Redis

Bagaimana memanfaatkan Redis untuk meminimalisasi latensi database Turso SQLite dan memperoleh skor Lighthouse 100.

0 views

Dalam pengembangan aplikasi web portofolio pribadi, kecepatan memuat halaman adalah elemen krusial pertama untuk memukau calon klien atau pemberi kerja. Kita mendambakan skor 100/100 pada metrik Google Lighthouse.

Untuk database, saya memilih Turso SQLite karena basisnya yang merupakan database edge serverless yang berlatensi rendah dan sangat murah. Namun, karena server database berada secara terpisah di cloud, setiap request halaman dinamis (seperti halaman blog detail) masih memerlukan waktu jabat tangan jaringan (network round-trip) sekitar 40ms hingga 120ms untuk menarik data.

Untuk menekan latensi pembacaan data ini hingga mendekati 0ms, saya mengimplementasikan strategi caching di sisi server menggunakan Upstash Redis. Artikel ini akan membedah bagaimana mengonfigurasi dan mengintegrasikan Redis sebagai lapisan penyimpanan data sementara di atas Drizzle ORM dan SvelteKit.

Mengapa Memilih Upstash Redis?

  1. Serverless & Auto-scale: Sesuai dengan filosofi arsitektur cloud saat ini, Upstash Redis membebankan biaya berdasarkan jumlah request, bukan sewa server bulanan yang konstan.
  2. Koneksi HTTP Restful: Berbeda dengan Redis tradisional yang membutuhkan koneksi TCP yang persisten (tidak cocok untuk Serverless Edge Functions Vercel yang cepat mati), Upstash menyediakan SDK berbasis HTTP Client.
  3. Latensi Super Rendah: Data tersimpan di memori RAM, sehingga pengambilan artikel blog yang sudah ter-cache hanya memakan waktu 2ms - 5ms.

Pola Desain Caching (Cache-Aside Pattern)

Prinsip kerja caching ini menggunakan pola Cache-Aside:

  1. Saat server menerima request data, pertama kita periksa apakah data tersebut sudah ada di memori Redis menggunakan Cache Key tertentu.
  2. Jika ada (Cache Hit), kita langsung parsing JSON dari Redis dan mengembalikannya ke browser.
  3. Jika tidak ada (Cache Miss), kita query database Turso via Drizzle ORM, simpan hasil query tersebut ke Redis dengan waktu kadaluwarsa (TTL), lalu kirimkan data ke browser.

Langkah Penulisan Kode

1. Inisialisasi Klien Redis

Pertama, konfigurasikan koneksi Upstash Redis menggunakan token credential dari file env:

import { Redis } from '@upstash/redis';
import { env } from '$env/dynamic/private';

export const redis = new Redis({
  url: env.UPSTASH_REDIS_REST_URL || '',
  token: env.UPSTASH_REDIS_REST_TOKEN || ''
});

2. Mengambil Artikel Blog dengan Cache Layer

Di dalam rute server pemuatan blog detail (src/routes/(public)/blog/[slug]/+page.server.ts), kita bungkus query database menggunakan utilitas caching:

import { db } from '$lib/server/db';
import { blogPosts } from '$lib/server/db/schema';
import { eq } from 'drizzle-orm';
import { redis } from '$lib/server/redis';
import { error } from '@sveltejs/kit';

export const load = async ({ params }) => {
  const { slug } = params;
  const cacheKey = `blog:${slug}`;

  // 1. Coba ambil dari cache Redis
  try {
    const cachedPost = await redis.get(cacheKey);
    if (cachedPost) {
      console.log(`⚡ Cache Hit untuk key: ${cacheKey}`);
      return { post: cachedPost };
    }
  } catch (err) {
    console.error("Redis Error:", err);
  }

  // 2. Jika Cache Miss, tarik dari Turso DB via Drizzle ORM
  console.log(`🐌 Cache Miss untuk key: ${cacheKey}. Menarik dari database...`);
  const post = await db.query.blogPosts.findFirst({
    where: eq(blogPosts.slug, slug),
    with: { tags: { with: { tag: true } } }
  });

  if (!post) {
    throw error(404, 'Postingan tidak ditemukan.');
  }

  // 3. Simpan ke Redis dengan TTL 24 jam (86400 detik)
  try {
    await redis.set(cacheKey, JSON.stringify(post), { ex: 86400 });
  } catch (err) {
    console.error("Gagal menulis ke Redis:", err);
  }

  return { post };
};

3. Invalidation Cache saat Update Konten (CMS Dashboard)

Agar pengunjung tidak melihat konten yang basi saat admin melakukan pengeditan tulisan di dashboard CMS, kita wajib menghapus key cache terkait (Cache Invalidation) sesaat setelah query UPDATE database dieksekusi:

export const actions = {
  updatePost: async ({ request }) => {
    const data = await request.formData();
    const slug = data.get('slug') as string;
    
    // Update data di database Turso
    await db.update(blogPosts).set({ ... }).where(eq(blogPosts.slug, slug));
    
    // Hapus key cache di Redis secara instan agar data ter-refresh
    const cacheKey = `blog:${slug}`;
    await redis.del(cacheKey);
    await redis.del('blog:all_posts'); // Hapus juga cache list blog utama
    
    return { success: true };
  }
};

Hasil Optimasi

Setelah mengimplementasikan caching Redis ini, latensi respons pemuatan halaman (Time To First Byte - TTFB) menurun tajam dari rata-rata 140ms menjadi hanya 12ms. Halaman dapat berpindah secara instan tanpa ada efek blank screen, memberikan impresi performa super premium kepada pengunjung portofolio Anda.