Salin dan Bagikan
Cara Menggunakan Redis untuk Caching - Panduan lengkap menggunakan Redis untuk caching dan meningkatkan performa aplikasi

Cara Menggunakan Redis untuk Caching

Redis adalah in-memory data store yang sangat cepat untuk caching. Mari pelajari cara menggunakannya.

Apa itu Redis?

Kegunaan Redis

Redis digunakan untuk:
- Caching (paling umum)
- Session storage
- Real-time analytics
- Message queue/broker
- Leaderboards
- Rate limiting
- Pub/Sub messaging

Keunggulan Redis

- Sangat cepat (in-memory)
- Support berbagai data structures
- Persistence options
- Clustering dan replication
- Atomic operations
- Pub/Sub support

Install Redis

Ubuntu/Debian

# Install Redis
sudo apt update
sudo apt install redis-server

# Start service
sudo systemctl start redis-server
sudo systemctl enable redis-server

# Check status
sudo systemctl status redis-server

# Test connection
redis-cli ping
# Response: PONG

Docker

# Run Redis container
docker run -d \
    --name redis \
    -p 6379:6379 \
    redis:alpine

# With persistence
docker run -d \
    --name redis \
    -p 6379:6379 \
    -v redis-data:/data \
    redis:alpine redis-server --appendonly yes

Redis CLI Basics

Basic Commands

# Connect to Redis
redis-cli

# Set value
SET name "Budi"
SET age 25

# Get value
GET name
GET age

# Set with expiration (seconds)
SET session:123 "data" EX 3600
SETEX session:456 3600 "data"

# Check TTL
TTL session:123

# Delete key
DEL name

# Check if key exists
EXISTS name

# Get all keys (use with caution)
KEYS *
KEYS user:*

Data Types

# String
SET greeting "Hello"
APPEND greeting " World"
GET greeting  # "Hello World"

# Integer operations
SET counter 0
INCR counter      # 1
INCRBY counter 5  # 6
DECR counter      # 5

# List
LPUSH mylist "first"
RPUSH mylist "last"
LRANGE mylist 0 -1  # Get all
LPOP mylist
RPOP mylist

# Set (unique values)
SADD myset "apple" "banana" "orange"
SMEMBERS myset
SISMEMBER myset "apple"  # 1 (true)

# Hash
HSET user:1 name "Budi" age 25 email "budi@email.com"
HGET user:1 name
HGETALL user:1
HINCRBY user:1 age 1

# Sorted Set
ZADD leaderboard 100 "player1" 200 "player2" 150 "player3"
ZRANGE leaderboard 0 -1 WITHSCORES
ZREVRANGE leaderboard 0 2  # Top 3

Caching Patterns

Cache-Aside Pattern

// Node.js dengan ioredis
const Redis = require("ioredis");
const redis = new Redis();

async function getUser(userId) {
  // 1. Check cache
  const cached = await redis.get(`user:${userId}`);
  if (cached) {
    console.log("Cache hit");
    return JSON.parse(cached);
  }

  // 2. Cache miss - fetch from database
  console.log("Cache miss");
  const user = await db.users.findById(userId);

  // 3. Store in cache
  await redis.set(
    `user:${userId}`,
    JSON.stringify(user),
    "EX",
    3600 // 1 hour
  );

  return user;
}

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

Write-Through Pattern

async function saveUser(userId, userData) {
  // Save to database
  await db.users.save(userId, userData);

  // Update cache immediately
  await redis.set(`user:${userId}`, JSON.stringify(userData), "EX", 3600);
}

TTL Strategy

// Different TTL for different data
const TTL = {
  USER_PROFILE: 3600, // 1 hour
  PRODUCT_LIST: 300, // 5 minutes
  SESSION: 86400, // 24 hours
  RATE_LIMIT: 60, // 1 minute
  STATIC_CONFIG: 604800, // 1 week
};

async function cacheData(key, data, type) {
  await redis.set(key, JSON.stringify(data), "EX", TTL[type]);
}

Express.js Integration

Setup Redis Client

// redis-client.js
const Redis = require("ioredis");

const redis = new Redis({
  host: process.env.REDIS_HOST || "localhost",
  port: process.env.REDIS_PORT || 6379,
  password: process.env.REDIS_PASSWORD || undefined,
  retryDelayOnFailover: 100,
  maxRetriesPerRequest: 3,
});

redis.on("connect", () => console.log("Redis connected"));
redis.on("error", (err) => console.error("Redis error:", err));

module.exports = redis;

Caching Middleware

// cache-middleware.js
const redis = require("./redis-client");

function cache(duration) {
  return async (req, res, next) => {
    const key = `cache:${req.originalUrl}`;

    try {
      const cached = await redis.get(key);
      if (cached) {
        return res.json(JSON.parse(cached));
      }

      // Store original json method
      const originalJson = res.json.bind(res);

      // Override json method to cache response
      res.json = async (data) => {
        await redis.set(key, JSON.stringify(data), "EX", duration);
        return originalJson(data);
      };

      next();
    } catch (error) {
      console.error("Cache error:", error);
      next();
    }
  };
}

module.exports = cache;

Using Cache Middleware

const express = require("express");
const cache = require("./cache-middleware");
const app = express();

// Cache for 5 minutes
app.get("/api/products", cache(300), async (req, res) => {
  const products = await db.products.findAll();
  res.json(products);
});

// Cache for 1 hour
app.get("/api/users/:id", cache(3600), async (req, res) => {
  const user = await db.users.findById(req.params.id);
  res.json(user);
});

// No cache
app.post("/api/users", async (req, res) => {
  const user = await db.users.create(req.body);
  res.json(user);
});

Session Storage

Express Session with Redis

const session = require("express-session");
const RedisStore = require("connect-redis").default;
const redis = require("./redis-client");

app.use(
  session({
    store: new RedisStore({ client: redis }),
    secret: process.env.SESSION_SECRET,
    resave: false,
    saveUninitialized: false,
    cookie: {
      secure: process.env.NODE_ENV === "production",
      httpOnly: true,
      maxAge: 24 * 60 * 60 * 1000, // 24 hours
    },
  })
);

Rate Limiting

Simple Rate Limiter

async function rateLimiter(userId, limit = 100, window = 60) {
  const key = `ratelimit:${userId}`;

  const current = await redis.incr(key);

  if (current === 1) {
    await redis.expire(key, window);
  }

  if (current > limit) {
    return {
      allowed: false,
      remaining: 0,
      resetIn: await redis.ttl(key),
    };
  }

  return {
    allowed: true,
    remaining: limit - current,
    resetIn: await redis.ttl(key),
  };
}

// Express middleware
async function rateLimitMiddleware(req, res, next) {
  const userId = req.ip; // or req.user.id
  const result = await rateLimiter(userId, 100, 60);

  res.set("X-RateLimit-Remaining", result.remaining);
  res.set("X-RateLimit-Reset", result.resetIn);

  if (!result.allowed) {
    return res.status(429).json({ error: "Too many requests" });
  }

  next();
}

Pub/Sub Messaging

Publisher

const Redis = require("ioredis");
const publisher = new Redis();

// Publish message
async function publishEvent(channel, data) {
  await publisher.publish(channel, JSON.stringify(data));
}

// Example usage
publishEvent("notifications", {
  type: "new_order",
  userId: 123,
  orderId: 456,
});

Subscriber

const Redis = require("ioredis");
const subscriber = new Redis();

// Subscribe to channel
subscriber.subscribe("notifications", (err, count) => {
  console.log(`Subscribed to ${count} channels`);
});

// Handle messages
subscriber.on("message", (channel, message) => {
  const data = JSON.parse(message);
  console.log(`Received on ${channel}:`, data);

  // Process message based on type
  switch (data.type) {
    case "new_order":
      // Handle new order
      break;
    case "payment_received":
      // Handle payment
      break;
  }
});

Configuration

redis.conf Optimization

# /etc/redis/redis.conf

# Memory limit
maxmemory 256mb
maxmemory-policy allkeys-lru

# Persistence
save 900 1       # Save if 1 key changed in 900 sec
save 300 10      # Save if 10 keys changed in 300 sec
save 60 10000    # Save if 10000 keys changed in 60 sec

# AOF persistence (more durable)
appendonly yes
appendfsync everysec

# Security
requirepass yourpassword
bind 127.0.0.1

# Performance
tcp-keepalive 300
timeout 0

Eviction Policies

allkeys-lru      # Remove least recently used
allkeys-lfu      # Remove least frequently used
volatile-lru     # LRU among keys with TTL
volatile-lfu     # LFU among keys with TTL
volatile-ttl     # Remove shortest TTL first
noeviction       # Return error when full

Monitoring

Redis CLI Commands

# Server info
INFO

# Memory usage
INFO memory
MEMORY USAGE key

# Connected clients
CLIENT LIST

# Slow queries
SLOWLOG GET 10

# Monitor commands (debug only)
MONITOR

# Stats
INFO stats

Key Metrics

- Memory usage
- Connected clients
- Hit rate (hits / (hits + misses))
- Evicted keys
- Blocked clients
- Commands per second

Kesimpulan

Redis adalah tool powerful untuk caching dan berbagai use case lainnya. Mulai dengan simple caching lalu explore fitur advanced seperti Pub/Sub dan clustering.

Artikel Terkait

Link Postingan : https://www.tirinfo.com/cara-menggunakan-redis-caching/

Hendra WIjaya
Tirinfo
5 minutes.
7 January 2026