Redis: Caching Strategy dan Session Management
Implementasi caching dan session store di aplikasi backend
Tujuan Pembelajaran
- Bisa implementasi cache-aside dan write-through
- Mengerti cache invalidation strategies
- Bisa membuat session store dengan Redis
Analogi
Caching Strategies:
├── Cache-Aside (Lazy Load)
├── Write-Through (Sync)
├── Write-Behind (Async)
└── Cache Invalidation
Session Store:
SET session:abc123 '{"userId":1}' EX 3600
Caching adalah use case paling umum Redis — strategi yang tepat sangat penting
Penjelasan Konsep
Caching adalah tentang trade-off: kamu menukar freshness data dengan kecepatan. Strategi caching yang tepat tergantung pada seberapa sering data berubah dan seberapa penting data yang selalu fresh.
Cache-Aside (Lazy Loading)
Pola paling umum: cek cache dulu, kalau miss baru ke database.
1. App minta data
2. Cek Redis → HIT? return data
3.
MISS? Query database
4. Simpan ke Redis
5. Return data
Pros: Simple, tidak ada write penalty Cons: Cache miss tetap lambat (db query), risk stale data
Write-Through
Setiap write ke database juga write ke cache secara synchronous.
1.
App write data
2. Simpan ke database
3. Simpan ke cache
4. Return success
Pros: Cache selalu fresh, read cepat Cons: Write lebih lambat (2x write), cache bisa membesar tanpa batas
Write-Behind (Write-Back)
Write ke cache dulu, database di-update secara async.
1.
App write data
2. Simpan ke cache
3. Return success (kepada user)
4. Async: update database
Pros: Write sangat cepat, throughput tinggi Cons: Risk data loss kalau crash sebelum db write
Cache Invalidation
Invalidasi cache lebih penting daripada caching itu sendiri.
Strategi:
-
TTL (Time To Live): Set expire otomatis
SET cache:user:1 $data EX 300 # Expire 5 menit -
Active Invalidation: Hapus cache saat data berubah
// Saat user di-update UPDATE users SET name = 'Baru' WHERE id = 1; DEL cache:user:1; // Invalidate cache -
Pattern-based Invalidation: Hapus multiple keys
KEYS cache:user:* # Find all user cache DEL cache:user:1 cache:user:2 ...
Session Store
Redis sangat cocok untuk session store karena:
- Cepat (sub-milidetik read/write)
- Auto-expire (session timeout otomatis)
- Shared across servers (semua server akses Redis yang sama)
// Session flow
// 1.
User login → buat session
const sessionId = crypto.randomUUID();
await redis.setex(`session:${sessionId}`, 3600, JSON.stringify({ userId: 1, role: 'admin' }));
// Set cookie dengan sessionId
// 2. Request berikutnya → validasi session
const session = await redis.get(`session:${sessionId}`);
if (!session) return 401; // Session expired
const user = JSON.parse(session); Contoh Kode
import { createClient } from 'redis';
const redis = createClient({ url: 'redis://localhost:6379' });
await redis.connect();
// Cache-aside implementation
class UserCache {
private ttl = 300; // 5 menit
async getUser(id: number) {
// 1. Cek cache
const cached = await redis.get(`user:${id}`);
if (cached) {
console.log('Cache HIT');
return JSON.parse(cached);
}
// 2. Cache miss → query DB
console.log('Cache MISS');
const user = await db.select().from(users).where(eq(users.id, id));
if (!user) return null;
// 3. Simpan ke cache
await redis.setex(`user:${id}`, this.ttl, JSON.stringify(user));
return user;
}
async invalidateUser(id: number) {
await redis.del(`user:${id}`);
}
async updateUser(id: number, data: any) {
// Write-through: update DB + cache
const [user] = await db.update(users).set(data).where(eq(users.id, id)).returning();
await redis.setex(`user:${id}`, this.ttl, JSON.stringify(user));
return user;
}
}
// Session store
class SessionStore {
private ttl = 3600; // 1 jam
async create(userId: number, data: any): Promise<string> {
const sessionId = crypto.randomUUID();
await redis.setex(`session:${sessionId}`, this.ttl, JSON.stringify({ userId, ...data }));
return sessionId;
}
async get(sessionId: string): Promise<any | null> {
const data = await redis.get(`session:${sessionId}`);
return data ? JSON.parse(data) : null;
}
async destroy(sessionId: string): Promise<void> {
await redis.del(`session:${sessionId}`);
}
async refresh(sessionId: string): Promise<void> {
await redis.expire(`session:${sessionId}`, this.ttl);
}
}Penjelasan Kode
Prompt AI
Implementasikan rate limiting dengan Redis: track request count per IP dengan window 1 menit, limit 60 requests.
Pertanyaan Reflektif
Cache invalidation adalah 'hard problem' dalam computer science. Dokumentasikan strategi caching-mu dan kapan invalidasi terjadi.