Redis: Lebih dari Sekadar Cache — Cara Penggunaan yang Sering Diabaikan Developer
Kebanyakan developer hanya pakai Redis untuk cache. Padahal Redis bisa jadi rate limiter, pub/sub broker, job queue, dan real-time leaderboard. Ini panduan lengkapnya.
Redis sering diperkenalkan sebagai "database key-value in-memory untuk caching". Ini tidak salah, tapi ini hanya 20% dari apa yang Redis bisa lakukan.
Setup Cepat
# Dengan Docker
docker run -d -p 6379:6379 redis:7-alpine
# Install client Node.js
npm install ioredis
import Redis from "ioredis";
const redis = new Redis(process.env.REDIS_URL);
Use Case 1: Caching (yang Semua Orang Tahu)
async function getUserProfile(userId: string) {
const cacheKey = `user:profile:${userId}`;
// Cek cache dulu
const cached = await redis.get(cacheKey);
if (cached) return JSON.parse(cached);
// Cache miss — query database
const user = await db.users.findById(userId);
// Simpan ke cache, expire 1 jam
await redis.setex(cacheKey, 3600, JSON.stringify(user));
return user;
}
Use Case 2: Rate Limiting
async function rateLimit(ip: string, limit = 100, windowSeconds = 60) {
const key = `ratelimit:${ip}`;
const current = await redis.incr(key);
if (current === 1) {
// Set expiry hanya saat pertama kali
await redis.expire(key, windowSeconds);
}
if (current > limit) {
throw new Error("Too Many Requests");
}
return { current, limit, remaining: limit - current };
}
Use Case 3: Session Management
// Simpan session dengan auto-expire
async function createSession(userId: string, sessionData: object) {
const sessionId = crypto.randomUUID();
await redis.setex(
`session:${sessionId}`,
86400, // 24 jam
JSON.stringify({ userId, ...sessionData })
);
return sessionId;
}
// Hapus session saat logout — instant invalidation
async function destroySession(sessionId: string) {
await redis.del(`session:${sessionId}`);
}
Use Case 4: Real-time Leaderboard
// Sorted Set — perfect untuk leaderboard
// Tambah/update skor
await redis.zadd("leaderboard:game1", score, userId);
// Top 10
const top10 = await redis.zrevrange("leaderboard:game1", 0, 9, "WITHSCORES");
// Rank user tertentu
const rank = await redis.zrevrank("leaderboard:game1", userId);
Use Case 5: Pub/Sub untuk Real-time Features
// Publisher — kirim notifikasi
const publisher = new Redis();
await publisher.publish("notifications", JSON.stringify({
userId: "123",
message: "Order kamu sudah dikirim!"
}));
// Subscriber — terima notifikasi
const subscriber = new Redis();
await subscriber.subscribe("notifications");
subscriber.on("message", (channel, message) => {
const data = JSON.parse(message);
// Push ke user via WebSocket
io.to(data.userId).emit("notification", data);
});
Use Case 6: Distributed Lock
// Cegah race condition di distributed system
async function processOrderOnce(orderId: string) {
const lockKey = `lock:order:${orderId}`;
const lockId = crypto.randomUUID();
// Coba acquire lock
const acquired = await redis.set(lockKey, lockId, "NX", "EX", 30);
if (!acquired) throw new Error("Order sedang diproses");
try {
await processOrder(orderId);
} finally {
// Release lock — hanya kalau kita yang punya
const current = await redis.get(lockKey);
if (current === lockId) await redis.del(lockKey);
}
}