+1

Sử Dụng Redis Cache Thông Minh Trong Node.js

Redis là key-value store siêu nhanh, thường được dùng làm cache layer cho backend. Nhưng nếu bạn chỉ biết .set().get(), thì bạn mới đang dùng Redis ở mức "cơ bản".

Trong bài này, mình sẽ chia sẻ cách sử dụng Redis thông minh hơn: tối ưu hiệu năng, tránh cache sai dữ liệu, và đảm bảo cache hoạt động hiệu quả khi traffic cao.

Tại sao nên dùng Redis?

  • Tăng tốc độ phản hồi: dữ liệu trả về từ Redis có thể nhanh gấp 10–100 lần so với gọi DB.
  • Giảm tải cho database: những truy vấn lặp lại nhiều lần không cần gọi lại.
  • Giữ state cho nhiều instance: phù hợp với hệ thống có load balancer.

1. Cache theo key động (dynamic key)

Đừng dùng key tĩnh như 'user'. Hãy cache theo ID, query, hoặc session.

const key = `user:${userId}`;
const cached = await redis.get(key);

if (cached) {
  return res.json(JSON.parse(cached));
}

const user = await db.getUserById(userId);
await redis.set(key, JSON.stringify(user), 'EX', 60 * 10); // cache 10 phút
return res.json(user);

2. Chỉ cache khi cần (cache selectively)

Không phải response nào cũng nên cache:

  • Đừng cache data thay đổi liên tục (realtime, điểm số...)
  • Đừng cache data chưa đầy đủ
if (user.isPremium) {
  await redis.set(key, JSON.stringify(user), 'EX', 600);
}

3. Cache theo query string (pagination, filter)

Với các API có nhiều biến thể (filter, sort, page), bạn nên cache theo query:

const queryKey = `products:${req.query.category}-${req.query.page}`;

Lưu ý: cần chuẩn hóa query trước khi tạo key để tránh tạo quá nhiều bản ghi.

4. Sử dụng TTL và cache invalidation hợp lý

  • EX: TTL (time-to-live) – chỉ cache trong một thời gian nhất định
  • DEL: xoá cache khi dữ liệu bị thay đổi
  • EXPIRE: cập nhật thời gian sống lại khi có update
wait redis.set('user:123', JSON.stringify(user), 'EX', 300); // cache 5 phút

// Khi user cập nhật thông tin:
await redis.del('user:123');

5. Dùng pipeline hoặc mget để giảm số roundtrip

Nếu cần lấy nhiều key cùng lúc:

const values = await redis.mget(['user:1', 'user:2', 'user:3']);

Hoặc khi set nhiều giá trị:

const pipeline = redis.pipeline();
items.forEach(item => {
  pipeline.set(`item:${item.id}`, JSON.stringify(item), 'EX', 600);
});
await pipeline.exec();

6. Cache tầng 2 (Two-Level Cache)

  • Level 1: Redis
  • Level 2: In-memory (RAM trong process) Giúp xử lý nhanh gọn những request lặp lại liên tục trong cùng instance, tránh cả Redis overload.

Ví dụ (với node-cache):

const localCache = new NodeCache();

let user = localCache.get(`user:${id}`);
if (!user) {
  const redisData = await redis.get(`user:${id}`);
  if (redisData) {
    user = JSON.parse(redisData);
    localCache.set(`user:${id}`, user, 30);
  }
}

7. Cache dạng danh sách (list, sorted set)

Redis không chỉ lưu string. Bạn có thể cache top list, ranking, queue bằng zadd, lpush, lrange.

// Top sản phẩm bán chạy
await redis.zadd('top-products', 100, 'product:123');
const top = await redis.zrevrange('top-products', 0, 9);

Kết

Redis không chỉ là “bộ nhớ tạm” – nếu biết cách dùng thông minh, bạn có thể:

  • Tăng tốc API gấp 10 lần
  • Giảm chi phí hạ tầng
  • Giữ hệ thống ổn định ở mức tải cao

Tóm lại:

  • Cache đúng: theo ID, query, TTL
  • Cache đủ: dùng TTL, xóa khi cần
  • Cache sạch: xóa khi update, dùng mget, pipeline, in-memory nếu hợp

All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí