Giới thiệu
Trong các ứng dụng web hiện đại, tốc độ phản hồi là yếu tố quyết định trải nghiệm người dùng. Khi API phải truy vấn cơ sở dữ liệu phức tạp hoặc thực hiện các phép tính nặng, thời gian đáp ứng có thể tăng đáng kể. Caching là giải pháp phổ biến để giảm tải cho database và tăng tốc độ trả về. Redis, một store dữ liệu dạng key‑value trong bộ nhớ, được tích hợp dễ dàng với Node.js và Express, giúp chúng ta lưu trữ tạm thời các kết quả truy vấn quan trọng.
Tại sao cần caching
Cache mang lại ba lợi ích chính:
- Giảm thời gian truy vấn: Dữ liệu được lưu trong RAM, truy cập nhanh hơn hàng chục lần so với disk.
- Giảm tải cho database: Các truy vấn lặp lại không cần thực hiện lại trên DB, giúp hệ thống chịu tải cao hơn.
- Tăng khả năng chịu lỗi: Khi database gặp sự cố, các dữ liệu đã được cache vẫn có thể phục vụ người dùng.
Cài đặt Redis và thư viện
Trước tiên, cần cài đặt Redis trên máy chủ (hoặc sử dụng dịch vụ cloud). Sau khi Redis đã chạy, chúng ta thêm thư viện ioredis vào dự án Node.js:
npm install ioredis --save
Triển khai Redis client trong Express
Chúng ta tạo một module riêng để khởi tạo và xuất ra client Redis, giúp tái sử dụng ở mọi nơi trong ứng dụng.
// redisClient.js
const Redis = require('ioredis');
const redis = new Redis({
host: '127.0.0.1',
port: 6379,
// password: 'your_password', // nếu có
});
module.exports = redis;Sau đó, trong file app.js hoặc server.js, chúng ta import client này để sử dụng.
Cache cho API GET
Giả sử có một endpoint trả về danh sách sản phẩm từ MongoDB. Chúng ta sẽ viết một middleware kiểm tra cache trước khi thực hiện truy vấn.
// cacheMiddleware.js
const redis = require('./redisClient');
function cache(keyPrefix, ttlSeconds) {
return async function (req, res, next) {
const key = `${keyPrefix}:${req.originalUrl}`;
const cached = await redis.get(key);
if (cached) {
res.setHeader('X-Cache', 'HIT');
return res.json(JSON.parse(cached));
}
// Ghi lại hàm res.json để lưu cache sau khi có dữ liệu
const originalJson = res.json.bind(res);
res.json = async (data) => {
await redis.setex(key, ttlSeconds, JSON.stringify(data));
res.setHeader('X-Cache', 'MISS');
originalJson(data);
};
next();
};
}
module.exports = cache;Áp dụng middleware vào route:
// productRoutes.js
const express = require('express');
const router = express.Router();
const Product = require('../models/Product');
const cache = require('../cacheMiddleware');
router.get('/products', cache('products', 300), async (req, res) => {
const products = await Product.find({});
res.json(products);
});
module.exports = router;Quản lý TTL và invalidation
Thời gian sống (TTL) của cache nên được thiết lập dựa trên tính chất dữ liệu. Đối với dữ liệu thay đổi thường, TTL ngắn (ví dụ 60‑300 giây) giúp giảm rủi ro dữ liệu lỗi thời. Khi có thao tác cập nhật, xóa hoặc tạo mới, chúng ta cần xóa cache liên quan để đảm bảo tính nhất quán.
// Khi cập nhật sản phẩm
router.put('/products/:id', async (req, res) => {
const updated = await Product.findByIdAndUpdate(req.params.id, req.body, {new: true});
// Xóa cache của danh sách sản phẩm
await redis.del('products:/products');
res.json(updated);
});Đối với các endpoint phức tạp, có thể sử dụng pattern key như products:/products?page=2 để xóa toàn bộ các key liên quan bằng lệnh redis.keys (cẩn thận với hiệu suất).
Kết luận
Việc tích hợp Redis cache vào Express không chỉ cải thiện thời gian phản hồi mà còn giảm tải cho database, giúp hệ thống chịu tải tốt hơn trong môi trường sản xuất. Để nắm vững toàn bộ quy trình từ cài đặt, cấu hình đến tối ưu hoá, bạn có thể Tham khảo khóa học "Lập trình Back-End với NodeJS Express" tại đây.








