BARUTeam, Domain & Bundle
Diskon 30%!
Detail
cachingredisperformanceupstashpatternshelipod

Caching Strategies dengan Redis di Helipod: Panduan Lengkap

Tim Helipod

6 menit baca

Panduan lengkap caching strategies menggunakan Redis di Helipod. Cache-aside, write-through, dan patterns lainnya untuk performa optimal.

Aplikasi lambat? Mungkin kamu belum pakai caching dengan benar. Caching yang tepat bisa meningkatkan performa 10-100x lipat.

Artikel ini panduan lengkap caching strategies.

Mengapa Caching Penting?

Tanpa Caching

Request → Database Query (500ms) → Response
Request → Database Query (500ms) → Response
Request → Database Query (500ms) → Response

Total: 1500ms untuk 3 request

Dengan Caching

Request → Cache Hit (1ms) → Response
Request → Cache Hit (1ms) → Response
Request → Cache Hit (1ms) → Response

Total: 3ms untuk 3 request

Speed up: 500x!

1. Cache-Aside Pattern

Cara Kerja

1. App cek cache
2. Cache hit → Return data
3. Cache miss → Query database → Simpan ke cache → Return data

Implementasi

// Cache-aside pattern
async function getUser(userId) {
  const cacheKey = `user:${userId}`;
  
  // 1. Cek cache
  const cached = await redis.get(cacheKey);
  if (cached) {
    return JSON.parse(cached); // Cache hit
  }
  
  // 2. Cache miss - query database
  const user = await db.users.findById(userId);
  
  // 3. Simpan ke cache dengan TTL
  await redis.set(cacheKey, JSON.stringify(user), { EX: 3600 });
  
  return user;
}

Kapan Menggunakan

  • ✅ Data yang sering dibaca
  • ✅ Data yang tidak sering berubah
  • ✅ Read-heavy workload

2. Write-Through Pattern

Cara Kerja

1. App tulis ke cache DAN database secara bersamaan
2. Data selalu sync antara cache dan database

Implementasi

// Write-through pattern
async function updateUser(userId, data) {
  const cacheKey = `user:${userId}`;
  
  // 1. Tulis ke database
  await db.users.update(userId, data);
  
  // 2. Tulis ke cache
  await redis.set(cacheKey, JSON.stringify(data), { EX: 3600 });
  
  return data;
}

Kapan Menggunakan

  • ✅ Data yang sering ditulis dan dibaca
  • ✅ Data yang harus selalu fresh
  • ✅ Write-heavy workload

3. Write-Behind Pattern

Cara Kerja

1. App tulis ke cache
2. Cache batch write ke database secara async

Implementasi

// Write-behind pattern
const writeBuffer = new Map();

async function updateUser(userId, data) {
  const cacheKey = `user:${userId}`;
  
  // 1. Tulis ke cache
  await redis.set(cacheKey, JSON.stringify(data), { EX: 3600 });
  
  // 2. Tambahkan ke buffer
  writeBuffer.set(userId, data);
}

// Batch write ke database setiap 5 detik
setInterval(async () => {
  for (const [userId, data] of writeBuffer) {
    await db.users.update(userId, data);
    writeBuffer.delete(userId);
  }
}, 5000);

Kapan Menggunakan

  • ✅ Write-heavy workload
  • ✅ Data yang bisa delay sedikit
  • ✅ High-throughput application

4. Read-Through Pattern

Cara Kerja

1. App minta data dari cache
2. Cache otomatis query database jika miss

Implementasi

// Read-through pattern dengan wrapper
class CacheReader {
  constructor(redis, db) {
    this.redis = redis;
    this.db = db;
  }
  
  async get(key, fetchFn, ttl = 3600) {
    // Cek cache
    const cached = await this.redis.get(key);
    if (cached) return JSON.parse(cached);
    
    // Fetch dari source
    const data = await fetchFn();
    
    // Simpan ke cache
    await this.redis.set(key, JSON.stringify(data), { EX: ttl });
    
    return data;
  }
}

// Penggunaan
const cache = new CacheReader(redis, db);
const user = await cache.get(
  `user:${userId}`,
  () => db.users.findById(userId),
  3600
);

5. Cache Invalidation Strategies

Time-Based (TTL)

// Data expire setelah waktu tertentu
await redis.set(`cache:${key}`, value, { EX: 3600 }); // 1 jam

Event-Based

// Invalidate saat data berubah
async function updateUser(userId, data) {
  await db.users.update(userId, data);
  await redis.del(`user:${userId}`); // Invalidate cache
}

Tag-Based

// Invalidate berdasarkan tag
async function invalidateTag(tag) {
  const keys = await redis.smembers(`tag:${tag}`);
  for (const key of keys) {
    await redis.del(key);
  }
  await redis.del(`tag:${tag}`);
}

// Saat update
async function updateUser(userId, data) {
  await db.users.update(userId, data);
  await redis.del(`user:${userId}`);
  await redis.sadd(`tag:user:${userId % 10}`, `user:${userId}`);
}

6. Cache Patterns untuk Use Cases

Session Storage

// Session dengan auto-expire
async function createSession(userId) {
  const sessionId = crypto.randomUUID();
  const session = {
    userId,
    createdAt: Date.now(),
    expiresAt: Date.now() + 86400000 // 24 jam
  };
  
  await redis.set(`session:${sessionId}`, JSON.stringify(session), { EX: 86400 });
  
  return sessionId;
}

async function getSession(sessionId) {
  const session = await redis.get(`session:${sessionId}`);
  return session ? JSON.parse(session) : null;
}

API Rate Limiting

// Rate limit dengan sliding window
async function checkRateLimit(userId, limit = 100, window = 60) {
  const key = `ratelimit:${userId}`;
  const now = Date.now();
  const windowStart = now - window * 1000;
  
  // Hapus request lama
  await redis.zremrangebyscore(key, 0, windowStart);
  
  // Hitung request saat ini
  const count = await redis.zcard(key);
  
  if (count >= limit) {
    return false; // Rate limited
  }
  
  // Tambah request baru
  await redis.zadd(key, now, `${now}`);
  await redis.expire(key, window);
  
  return true;
}

Leaderboard

// Leaderboard dengan sorted set
async function updateScore(userId, score) {
  await redis.zadd('leaderboard', score, userId);
}

async function getTop10() {
  return await redis.zrange('leaderboard', 0, 9, { REV: true });
}

async function getUserRank(userId) {
  const rank = await redis.zrevrank('leaderboard', userId);
  return rank !== null ? rank + 1 : null;
}

Shopping Cart

// Cart dengan hash
async function addToCart(userId, productId, quantity) {
  await redis.hset(`cart:${userId}`, productId, quantity);
}

async function getCart(userId) {
  const cart = await redis.hgetall(`cart:${userId}`);
  return Object.entries(cart).map(([productId, quantity]) => ({
    productId,
    quantity: parseInt(quantity)
  }));
}

async function clearCart(userId) {
  await redis.del(`cart:${userId}`);
}

7. Performance Optimization

Pipeline untuk Batch Operations

// ❌ Slow - multiple round trips
for (const key of keys) {
  await redis.get(key);
}

// ✅ Fast - single round trip
const pipeline = redis.pipeline();
for (const key of keys) {
  pipeline.get(key);
}
const results = await pipeline.exec();

Connection Pooling

// Gunakan connection pooling
import { Redis } from 'ioredis';

const redis = new Redis({
  host: 'localhost',
  port: 6379,
  maxRetriesPerRequest: 3,
  enableReadyCheck: true,
  lazyConnect: true,
});

Memory Optimization

// Gunakan hash untuk data yangRelated
// ❌ Multiple keys
await redis.set('user:1:name', 'Budi');
await redis.set('user:1:email', '[email protected]');
await redis.set('user:1:age', '25');

// ✅ Single hash
await redis.hset('user:1', {
  name: 'Budi',
  email: '[email protected]',
  age: '25'
});

8. Monitoring dan Debugging

Metrics

// Monitor cache hit rate
async function getCacheStats() {
  const info = await redis.info('stats');
  const hits = parseInt(info.match(/keyspace_hits:(\d+)/)[1]);
  const misses = parseInt(info.match(/keyspace_misses:(\d+)/)[1]);
  
  return {
    hits,
    misses,
    hitRate: hits / (hits + misses)
  };
}

Debug Logging

// Log cache operations
redis.on('error', (err) => {
  console.error('Redis error:', err);
});

redis.on('connect', () => {
  console.log('Redis connected');
});

Checklist Caching

  • Pilih caching pattern yang tepat
  • Setup TTL untuk data
  • Implementasi cache invalidation
  • Setup monitoring
  • Optimize memory usage
  • Test cache hit rate

Kesimpulan

Caching yang tepat bisa meningkatkan performa aplikasi secara signifikan. Dengan Redis + Helipod, kamu bisa:

  • ✅ Implementasi berbagai caching patterns
  • ✅ Optimize performa aplikasi
  • ✅ Monitor cache usage
  • ✅ Scale sesuai kebutuhan

Butuh bantuan? Hubungi [email protected]

Baca juga:

Siap coba Helipod?

Deploy aplikasi kamu sekarang. Gratis, tanpa kartu kredit.

Mulai Gratis →