Nội dung

DaiPhan

DaiPhan

Full-Stack Developer

Full-stack developer passionate about modern web technologies, best practices, and sharing knowledge with the community.

Skills & Expertise

JavaScript TypeScript React Node.js DevOps
150+
Articles
50k+
Readers
4.9
Rating

Redis Là Gì? In-Memory Database Cho High Performance Applications

Khám phá Redis - in-memory database mạnh mẽ với nhiều use case: caching, session store, pub/sub, real-time analytics và nhiều hơn thế

Redis Là Gì? In-Memory Database Cho High Performance Applications

Redis (Remote Dictionary Server) là một in-memory database mã nguồn mở nổi tiếng, được sử dụng rộng rãi như một cache, message broker, và database. Với hiệu suất cao và độ linh hoạt lớn, Redis đã trở thành một phần không thể thiếu trong kiến trúc hiện đại.

Redis Là Gì?

Redis là một in-memory data structure store có khả năng:

  • Lưu trữ dữ liệu trong bộ nhớ với nhiều loại data structure
  • Persistence dữ liệu lên disk theo nhiều cách
  • Replicationclustering cho high availability
  • Pub/Sub messaging cho real-time applications
  • TransactionsLua scripting cho complex operations

Đặc điểm nổi bật:

  • In-memory storage: Tốc độ cực nhanh (sub-millisecond latency)
  • Đa dạng data structures: Strings, lists, sets, sorted sets, hashes, bitmaps, hyperloglogs, streams
  • Persistence options: RDB snapshots, AOF (Append Only File)
  • High availability: Master-slave replication, Redis Sentinel, Redis Cluster
  • Atomic operations: Tất cả operations đều atomic
  • Lua scripting: Server-side scripting cho complex operations

Cài Đặt và Cấu Hình Redis

Cài Đặt

# Ubuntu/Debian
sudo apt update
sudo apt install redis-server

# macOS
brew install redis

# Docker
docker run -d -p 6379:6379 --name redis redis:alpine

# Kiểm tra cài đặt
redis-cli ping
# Expected: PONG

Cấu Hình Cơ Bản

# File: /etc/redis/redis.conf

# Network
bind 127.0.0.1 ::1
port 6379
protected-mode yes

# Memory
maxmemory 256mb
maxmemory-policy allkeys-lru

# Persistence
save 900 1    # Save sau 900s nếu có 1 key thay đổi
save 300 10   # Save sau 300s nếu có 10 keys thay đổi
save 60 10000 # Save sau 60s nếu có 10000 keys thay đổi

# AOF (Append Only File)
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec

# Logging
loglevel notice
logfile /var/log/redis/redis-server.log

Data Structures trong Redis

1. Strings - Cơ bản nhất nhưng mạnh mẽ

const redis = require('redis');
const client = redis.createClient();

// Basic operations
await client.set('user:1:name', 'John Doe');
await client.set('user:1:age', '30', 'EX', 3600); // Set với TTL 1 giờ

const name = await client.get('user:1:name');
const age = await client.get('user:1:age');

// Numeric operations
await client.set('counter', '0');
await client.incr('counter');        // 1
await client.incrby('counter', 5);   // 6
await client.decr('counter');        // 5

// Bit operations
await client.setbit('user:1:permissions', 0, 1);  // Bit 0: read permission
await client.setbit('user:1:permissions', 1, 1);  // Bit 1: write permission
await client.setbit('user:1:permissions', 2, 0);  // Bit 2: delete permission (no)

const permissions = await client.getbit('user:1:permissions', 1); // 1

2. Lists - Danh sách liên kết

// Social media feed
await client.lpush('feed:user:1', JSON.stringify({
  type: 'post',
  content: 'Hello Redis!',
  timestamp: Date.now()
}));

await client.lpush('feed:user:1', JSON.stringify({
  type: 'photo',
  url: 'https://example.com/photo.jpg',
  timestamp: Date.now()
}));

// Lấy 10 bài viết mới nhất
const recentPosts = await client.lrange('feed:user:1', 0, 9);

// Queue implementation
await client.rpush('task:queue', 'task:1', 'task:2', 'task:3');
const task = await client.lpop('task:queue'); // task:1

// Capped list - giữ 100 items mới nhất
await client.lpush('recent:searches', 'redis tutorial');
await client.ltrim('recent:searches', 0, 99);

3. Sets - Tập hợp không trùng lặp

// User interests
await client.sadd('user:1:interests', 'technology', 'programming', 'redis');
await client.sadd('user:2:interests', 'technology', 'music', 'sports');

// Tìm common interests
const commonInterests = await client.sinter('user:1:interests', 'user:2:interests');
// ['technology']

// Tìm unique interests của user:1
const uniqueInterests = await client.sdiff('user:1:interests', 'user:2:interests');
// ['programming', 'redis']

// Đếm số members
const count = await client.scard('user:1:interests'); // 3

// Kiểm tra membership
const isMember = await client.sismember('user:1:interests', 'redis'); // 1

// Random member
const randomInterest = await client.srandmember('user:1:interests');

4. Sorted Sets - Sets với score

// Leaderboard - game scores
await client.zadd('game:leaderboard', 1000, 'player:1', 850, 'player:2', 1200, 'player:3');

// Top 10 players
const topPlayers = await client.zrevrange('game:leaderboard', 0, 9, 'WITHSCORES');
// ['player:3', '1200', 'player:1', '1000', 'player:2', '850']

// Player rank
const rank = await client.zrevrank('game:leaderboard', 'player:1'); // 1 (0-based)

// Player score
const score = await client.zscore('game:leaderboard', 'player:1'); // 1000

// Players trong khoảng score
const playersInRange = await client.zrangebyscore('game:leaderboard', 800, 1100);
// ['player:2', 'player:1']

// Time-based data với timestamp làm score
await client.zadd('user:1:timeline', Date.now(), JSON.stringify({
  action: 'login',
  timestamp: Date.now()
}));

5. Hashes - Objects

// User profile
await client.hset('user:1', 'name', 'John Doe', 'email', 'john@example.com', 'age', '30');

// Lấy toàn bộ user
const user = await client.hgetall('user:1');
// { name: 'John Doe', email: 'john@example.com', age: '30' }

// Lấy specific fields
const name = await client.hget('user:1', 'name');
const fields = await client.hmget('user:1', 'name', 'email');

// Đếm số fields
const fieldCount = await client.hlen('user:1'); // 3

// Kiểm tra field existence
const exists = await client.hexists('user:1', 'email'); // 1

// Xóa field
await client.hdel('user:1', 'age');

// Tăng numeric field
await client.hincrby('user:1', 'login_count', 1);

6. Streams - Log-like data structure (Redis 5.0+)

// Add events to stream
await client.xadd('user:activity', '*', 'action', 'login', 'timestamp', Date.now());
await client.xadd('user:activity', '*', 'action', 'view_page', 'page', '/products', 'timestamp', Date.now());

// Read recent events
const events = await client.xrevrange('user:activity', '+', '-', 'COUNT', 10);

// Consumer groups
await client.xgroup('CREATE', 'user:activity', 'analytics-group', '0');

// Consumer đọc messages
const messages = await client.xreadgroup(
  'GROUP', 'analytics-group', 'consumer-1',
  'COUNT', 10,
  'BLOCK', 5000,
  'STREAMS', 'user:activity', '>'
);

// Acknowledge processed messages
await client.xack('user:activity', 'analytics-group', ...messageIds);

Caching Patterns với Redis

1. Cache-Aside Pattern

class CacheAside {
  constructor(redisClient, dataSource) {
    this.redis = redisClient;
    this.dataSource = dataSource;
  }

  async get(key, fetchFunction, ttl = 3600) {
    // Thử lấy từ cache
    let data = await this.redis.get(key);
    
    if (data) {
      return JSON.parse(data);
    }
    
    // Cache miss - lấy từ source
    data = await fetchFunction();
    
    if (data) {
      await this.redis.setex(key, ttl, JSON.stringify(data));
    }
    
    return data;
  }

  async invalidate(key) {
    await this.redis.del(key);
  }

  async update(key, data, ttl = 3600) {
    // Update source trước
    await this.dataSource.update(key, data);
    
    // Sau đó update cache
    await this.redis.setex(key, ttl, JSON.stringify(data));
  }
}

// Usage
const cache = new CacheAside(client, database);

// Get user with caching
const user = await cache.get('user:123', async () => {
  return await database.getUser(123);
}, 1800); // TTL 30 phút

2. Write-Through Cache

class WriteThroughCache {
  constructor(redisClient, dataSource) {
    this.redis = redisClient;
    this.dataSource = dataSource;
  }

  async write(key, data, ttl = 3600) {
    // Write to source first
    await this.dataSource.write(key, data);
    
    // Then update cache
    await this.redis.setex(key, ttl, JSON.stringify(data));
    
    return data;
  }

  async read(key) {
    return await this.get(key);
  }
}

3. Write-Behind Cache

class WriteBehindCache {
  constructor(redisClient, dataSource, batchSize = 100, flushInterval = 5000) {
    this.redis = redisClient;
    this.dataSource = dataSource;
    this.batchSize = batchSize;
    this.flushInterval = flushInterval;
    this.writeBuffer = new Map();
    
    this.startFlushTimer();
  }

  async write(key, data, ttl = 3600) {
    // Update cache immediately
    await this.redis.setex(key, ttl, JSON.stringify(data));
    
    // Buffer write to source
    this.writeBuffer.set(key, data);
    
    // Flush nếu buffer đầy
    if (this.writeBuffer.size >= this.batchSize) {
      await this.flush();
    }
  }

  async flush() {
    if (this.writeBuffer.size === 0) return;
    
    const batch = new Map(this.writeBuffer);
    this.writeBuffer.clear();
    
    try {
      // Batch write to source
      await this.dataSource.batchWrite(Array.from(batch.entries()));
    } catch (error) {
      // Restore buffer nếu fail
      for (const [key, data] of batch) {
        this.writeBuffer.set(key, data);
      }
      throw error;
    }
  }

  startFlushTimer() {
    setInterval(() => {
      this.flush().catch(console.error);
    }, this.flushInterval);
  }
}

Pub/Sub với Redis

1. Basic Pub/Sub

// Publisher
await client.publish('notifications', JSON.stringify({
  type: 'user_login',
  userId: 123,
  timestamp: Date.now()
}));

// Subscriber
const subscriber = redis.createClient();
const publisher = redis.createClient();

await subscriber.subscribe('notifications');

subscriber.on('message', (channel, message) => {
  const data = JSON.parse(message);
  console.log(`Received ${data.type} for user ${data.userId}`);
  
  // Xử lý notification
  handleNotification(data);
});

async function handleNotification(data) {
  switch (data.type) {
    case 'user_login':
      await sendWelcomeEmail(data.userId);
      break;
    case 'order_completed':
      await sendOrderConfirmation(data.orderId);
      break;
  }
}

2. Pattern-based Pub/Sub

// Subscribe to multiple channels với pattern
await subscriber.psubscribe('user:*:events');

subscriber.on('pmessage', (pattern, channel, message) => {
  const userId = channel.split(':')[1];
  const event = JSON.parse(message);
  
  console.log(`User ${userId} event:`, event);
});

// Publishers
await publisher.publish('user:123:events', JSON.stringify({ type: 'login' }));
await publisher.publish('user:456:events', JSON.stringify({ type: 'logout' }));

Session Management với Redis

class SessionStore {
  constructor(redisClient, ttl = 3600) {
    this.redis = redisClient;
    this.ttl = ttl;
  }

  async createSession(userId, sessionData) {
    const sessionId = this.generateSessionId();
    const sessionKey = `session:${sessionId}`;
    
    const session = {
      userId,
      data: sessionData,
      createdAt: Date.now(),
      lastAccessed: Date.now()
    };
    
    await this.redis.setex(sessionKey, this.ttl, JSON.stringify(session));
    
    // Lưu mapping user -> sessions để quản lý
    await this.redis.sadd(`user:${userId}:sessions`, sessionId);
    
    return sessionId;
  }

  async getSession(sessionId) {
    const sessionKey = `session:${sessionId}`;
    const sessionData = await this.redis.get(sessionKey);
    
    if (!sessionData) {
      return null;
    }
    
    const session = JSON.parse(sessionData);
    session.lastAccessed = Date.now();
    
    // Extend TTL khi access
    await this.redis.setex(sessionKey, this.ttl, JSON.stringify(session));
    
    return session;
  }

  async destroySession(sessionId) {
    const sessionKey = `session:${sessionId}`;
    const sessionData = await this.redis.get(sessionKey);
    
    if (sessionData) {
      const session = JSON.parse(sessionData);
      
      // Xóa session
      await this.redis.del(sessionKey);
      
      // Xóa khỏi user sessions
      await this.redis.srem(`user:${session.userId}:sessions`, sessionId);
    }
  }

  async getUserSessions(userId) {
    const sessionIds = await this.redis.smembers(`user:${userId}:sessions`);
    const sessions = [];
    
    for (const sessionId of sessionIds) {
      const sessionData = await this.redis.get(`session:${sessionId}`);
      if (sessionData) {
        sessions.push(JSON.parse(sessionData));
      }
    }
    
    return sessions;
  }

  generateSessionId() {
    return require('crypto').randomBytes(32).toString('hex');
  }
}

// Usage với Express
const sessionStore = new SessionStore(client);

app.post('/login', async (req, res) => {
  const { username, password } = req.body;
  
  // Validate credentials
  const user = await validateUser(username, password);
  
  if (user) {
    const sessionId = await sessionStore.createSession(user.id, {
      username: user.username,
      role: user.role
    });
    
    res.cookie('sessionId', sessionId, { httpOnly: true, secure: true });
    res.json({ success: true, user: { id: user.id, username: user.username } });
  } else {
    res.status(401).json({ error: 'Invalid credentials' });
  }
});

app.get('/profile', async (req, res) => {
  const sessionId = req.cookies.sessionId;
  
  if (!sessionId) {
    return res.status(401).json({ error: 'No session' });
  }
  
  const session = await sessionStore.getSession(sessionId);
  
  if (!session) {
    return res.status(401).json({ error: 'Invalid session' });
  }
  
  res.json({ user: session.data });
});

Rate Limiting với Redis

class RateLimiter {
  constructor(redisClient, windowMs = 60000, maxRequests = 100) {
    this.redis = redisClient;
    this.windowMs = windowMs;
    this.maxRequests = maxRequests;
  }

  async isAllowed(identifier) {
    const key = `rate_limit:${identifier}`;
    const window = Math.floor(Date.now() / this.windowMs);
    const windowKey = `${key}:${window}`;
    
    // Sử dụng sliding window
    const pipeline = this.redis.pipeline();
    
    // Tăng counter cho current window
    pipeline.incr(windowKey);
    pipeline.expire(windowKey, Math.ceil(this.windowMs / 1000));
    
    // Lấy previous window
    const prevWindowKey = `${key}:${window - 1}`;
    pipeline.get(prevWindowKey);
    
    const results = await pipeline.exec();
    const currentCount = results[0][1];
    const prevCount = parseInt(results[2][1]) || 0;
    
    // Tính toán sliding window count
    const prevWindowWeight = 1 - (Date.now() % this.windowMs) / this.windowMs;
    const slidingCount = Math.floor(currentCount + prevCount * prevWindowWeight);
    
    return {
      allowed: slidingCount <= this.maxRequests,
      current: slidingCount,
      limit: this.maxRequests,
      remaining: Math.max(0, this.maxRequests - slidingCount)
    };
  }

  async middleware(req, res, next) {
    const identifier = req.ip || req.connection.remoteAddress;
    
    try {
      const rateLimit = await this.isAllowed(identifier);
      
      // Thêm headers
      res.setHeader('X-RateLimit-Limit', this.maxRequests);
      res.setHeader('X-RateLimit-Remaining', rateLimit.remaining);
      res.setHeader('X-RateLimit-Reset', Date.now() + this.windowMs);
      
      if (!rateLimit.allowed) {
        res.setHeader('Retry-After', Math.ceil(this.windowMs / 1000));
        return res.status(429).json({
          error: 'Too many requests',
          retryAfter: Math.ceil(this.windowMs / 1000)
        });
      }
      
      next();
    } catch (error) {
      console.error('Rate limiting error:', error);
      // Cho phép request nếu Redis fail
      next();
    }
  }
}

// Usage với Express
const rateLimiter = new RateLimiter(client, 60000, 100); // 100 requests per minute

app.use('/api/', (req, res, next) => rateLimiter.middleware(req, res, next));

Redis Cluster và High Availability

Redis Sentinel

const redis = require('redis');

// Sentinel configuration
const sentinelConfig = {
  sentinels: [
    { host: 'sentinel1', port: 26379 },
    { host: 'sentinel2', port: 26379 },
    { host: 'sentinel3', port: 26379 }
  ],
  name: 'mymaster',
  role: 'master'
};

const client = redis.createClient(sentinelConfig);

client.on('error', (err) => {
  console.error('Redis error:', err);
});

client.on('connect', () => {
  console.log('Connected to Redis master via Sentinel');
});

Redis Cluster

const redis = require('redis');

// Cluster configuration
const clusterConfig = {
  host: 'localhost',
  port: 6379,
  enableReadyCheck: true,
  maxRetriesPerRequest: 3,
  retryDelayOnFailover: 100,
  slotsRefreshTimeout: 2000,
  slotsRefreshInterval: 5000
};

const nodes = [
  { host: '127.0.0.1', port: 7000 },
  { host: '127.0.0.1', port: 7001 },
  { host: '127.0.0.1', port: 7002 },
  { host: '127.0.0.1', port: 7003 },
  { host: '127.0.0.1', port: 7004 },
  { host: '127.0.0.1', port: 7005 }
];

const cluster = new redis.Cluster(nodes, clusterConfig);

cluster.on('error', (err) => {
  console.error('Cluster error:', err);
});

cluster.on('ready', () => {
  console.log('Connected to Redis Cluster');
});

Performance Tuning

Connection Pooling

const redis = require('redis');
const { promisify } = require('util');

class RedisPool {
  constructor(config = {}) {
    this.config = {
      host: 'localhost',
      port: 6379,
      maxConnections: 10,
      minConnections: 2,
      acquireTimeoutMillis: 3000,
      idleTimeoutMillis: 30000,
      ...config
    };
    
    this.pool = [];
    this.available = [];
    this.waiting = [];
    
    this.initializePool();
  }

  async initializePool() {
    for (let i = 0; i < this.config.minConnections; i++) {
      await this.createConnection();
    }
  }

  async createConnection() {
    const client = redis.createClient(this.config);
    const connection = {
      client,
      lastUsed: Date.now(),
      inUse: false,
      id: Math.random().toString(36)
    };
    
    client.on('error', (err) => {
      console.error(`Connection ${connection.id} error:`, err);
      this.removeConnection(connection);
    });
    
    client.on('end', () => {
      this.removeConnection(connection);
    });
    
    await new Promise((resolve) => client.once('ready', resolve));
    
    this.pool.push(connection);
    this.available.push(connection);
    
    return connection;
  }

  async acquire() {
    const startTime = Date.now();
    
    while (Date.now() - startTime < this.config.acquireTimeoutMillis) {
      const connection = this.available.shift();
      
      if (connection) {
        connection.inUse = true;
        connection.lastUsed = Date.now();
        return connection;
      }
      
      if (this.pool.length < this.config.maxConnections) {
        const newConnection = await this.createConnection();
        newConnection.inUse = true;
        return newConnection;
      }
      
      await new Promise(resolve => setTimeout(resolve, 100));
    }
    
    throw new Error('Connection pool timeout');
  }

  release(connection) {
    if (!connection.inUse) return;
    
    connection.inUse = false;
    connection.lastUsed = Date.now();
    
    this.available.push(connection);
    
    // Xử lý waiting requests
    if (this.waiting.length > 0) {
      const waitingRequest = this.waiting.shift();
      waitingRequest.resolve(this.acquire());
    }
  }

  removeConnection(connection) {
    const poolIndex = this.pool.indexOf(connection);
    const availableIndex = this.available.indexOf(connection);
    
    if (poolIndex > -1) this.pool.splice(poolIndex, 1);
    if (availableIndex > -1) this.available.splice(availableIndex, 1);
    
    connection.client.quit();
  }

  async close() {
    for (const connection of this.pool) {
      connection.client.quit();
    }
    this.pool = [];
    this.available = [];
  }
}

Pipeline và Transactions

// Pipeline - gửi nhiều commands trong một request
async function batchOperations() {
  const pipeline = client.pipeline();
  
  // Thêm nhiều operations vào pipeline
  for (let i = 0; i < 1000; i++) {
    pipeline.set(`key:${i}`, `value:${i}`);
  }
  
  // Execute tất cả commands
  const results = await pipeline.exec();
  console.log(`Executed ${results.length} commands`);
}

// Transaction - MULTI/EXEC
async function transactionExample() {
  const multi = client.multi();
  
  // Thêm commands vào transaction
  multi.set('account:1:balance', '1000');
  multi.set('account:2:balance', '500');
  multi.decrby('account:1:balance', 100);
  multi.incrby('account:2:balance', 100);
  
  // Execute transaction
  const results = await multi.exec();
  
  // Kiểm tra results
  const balance1 = await client.get('account:1:balance'); // 900
  const balance2 = await client.get('account:2:balance'); // 600
  
  console.log(`Account 1: ${balance1}, Account 2: ${balance2}`);
}

// Optimistic locking với WATCH
async function optimisticLocking() {
  await client.watch('counter');
  
  const current = await client.get('counter');
  const newValue = parseInt(current) + 1;
  
  const multi = client.multi();
  multi.set('counter', newValue);
  
  const results = await multi.exec();
  
  if (results === null) {
    console.log('Transaction failed - key was modified');
    // Retry hoặc handle conflict
  } else {
    console.log('Transaction successful');
  }
}

So Sánh Redis Với Các Database Khác

Redis vs Memcached

Tính năngRedisMemcached
Data structuresStrings, lists, sets, sorted sets, hashes, streamsChỉ strings
PersistenceCó (RDB, AOF)Không
ReplicationKhông
Pub/SubKhông
Lua scriptingKhông
Memory usageCao hơnThấp hơn
PerformanceRất nhanhCực nhanh

Redis vs MongoDB

Tính năngRedisMongoDB
StorageIn-memoryDisk
Data modelKey-value, data structuresDocument
QueryingĐơn giảnPhức tạp
ScalingClusteringSharding
Use caseCache, session, real-timeGeneral purpose
LatencySub-millisecondMillisecond

Redis vs PostgreSQL

Tính năngRedisPostgreSQL
StorageIn-memoryDisk
ACIDPartialFull
SQL supportKhông
Complex queriesKhông
TransactionsCó (limited)Có (full)
Use caseCache, real-timeOLTP, OLAP

Best Practices

1. Key Design

// Good key design
const keyPatterns = {
  user: 'user:{userId}',
  session: 'session:{sessionId}',
  cache: 'cache:{entity}:{id}',
  rateLimit: 'rate_limit:{identifier}:{window}',
  leaderboard: 'leaderboard:{game}:{period}'
};

// Sử dụng
const userKey = `user:${userId}`;
const sessionKey = `session:${sessionId}`;
const cacheKey = `cache:product:${productId}`;

2. Memory Optimization

// Sử dụng appropriate data structures
// Thay vì nhiều keys
await client.set('user:1:name', 'John');
await client.set('user:1:email', 'john@example.com');
await client.set('user:1:age', '30');

// Dùng hash để tiết kiệm memory
await client.hset('user:1', 'name', 'John', 'email', 'john@example.com', 'age', '30');

// Sử dụng compression cho large values
const zlib = require('zlib');
const { promisify } = require('util');
const compress = promisify(zlib.gzip);
const decompress = promisify(zlib.gunzip);

async function setCompressed(key, data) {
  const compressed = await compress(JSON.stringify(data));
  await client.setex(key, 3600, compressed);
}

async function getCompressed(key) {
  const compressed = await client.get(key);
  if (!compressed) return null;
  
  const decompressed = await decompress(compressed);
  return JSON.parse(decompressed.toString());
}

3. Error Handling và Retry

class RedisClient {
  constructor(config) {
    this.config = config;
    this.client = null;
    this.connect();
  }

  async connect() {
    this.client = redis.createClient(this.config);
    
    this.client.on('error', (err) => {
      console.error('Redis error:', err);
      this.handleError(err);
    });
    
    this.client.on('connect', () => {
      console.log('Connected to Redis');
    });
    
    this.client.on('reconnecting', () => {
      console.log('Reconnecting to Redis...');
    });
  }

  async executeWithRetry(operation, maxRetries = 3) {
    for (let attempt = 1; attempt <= maxRetries; attempt++) {
      try {
        return await operation();
      } catch (error) {
        console.error(`Attempt ${attempt} failed:`, error.message);
        
        if (attempt === maxRetries) {
          throw error;
        }
        
        // Exponential backoff
        await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 100));
      }
    }
  }

  handleError(error) {
    // Log error, send alert, etc.
    console.error('Redis connection error:', error);
  }
}

Kết Luận

Redis là một in-memory database đa năng và mạnh mẽ, phù hợp cho nhiều use case khác nhau trong ứng dụng hiện đại. Với hiệu suất cao, độ linh hoạt lớn và ecosystem phong phú, Redis là lựa chọn tuyệt vời cho:

  • Caching: Tăng tốc ứng dụng với sub-millisecond latency
  • Session management: Lưu trữ session data cho web applications
  • Real-time analytics: Xử lý và phân tích dữ liệu theo thời gian thực
  • Pub/Sub messaging: Giao tiếp real-time giữa components
  • Rate limiting: Giới hạn requests và prevent abuse
  • Leaderboards: Real-time ranking systems
  • Queue management: Task queues và job processing

Việc hiểu rõ các data structures, patterns và best practices của Redis sẽ giúp bạn xây dựng ứng dụng hiệu quả và scalable hơn.