Caching (bộ nhớ đệm) là một kỹ thuật quan trọng giúp tăng hiệu suất của ứng dụng Node.js bằng cách lưu trữ tạm thời dữ liệu để truy xuất nhanh hơn, thay vì phải xử lý hoặc lấy lại từ nguồn chậm hơn (như database, API bên ngoài, hoặc xử lý tính toán nặng). Dưới đây là một số cách sử dụng caching trong Node.js:
1. Caching trên Memory (In-Memory Cache)
Lưu trữ dữ liệu ngay trong bộ nhớ của ứng dụng giúp truy xuất nhanh hơn.
1.1. Sử dụng node-cache
node-cache
là một package giúp lưu trữ key-value trong bộ nhớ RAM của Node.js.
const NodeCache = require("node-cache");
const cache = new NodeCache({ stdTTL: 100, checkperiod: 120 }); // TTL 100s
function getUser(id) {
const cachedUser = cache.get(id);
if (cachedUser) {
console.log("Cache hit!");
return cachedUser;
}
console.log("Cache miss, fetching from DB...");
const user = { id, name: "John Doe" }; // Giả lập DB query
cache.set(id, user);
return user;
}
console.log(getUser(1)); // Lần đầu lấy từ DB
console.log(getUser(1)); // Lần sau lấy từ cache
📌 Ưu điểm: Nhanh, đơn giản, không cần thiết lập phức tạp.
📌 Nhược điểm: Không phù hợp với ứng dụng phân tán (nhiều instance).
2. Caching bằng Redis
Redis là một hệ thống cache mạnh mẽ, lưu trữ dữ liệu trên RAM và hỗ trợ nhiều kiểu dữ liệu (key-value, list, hash...).
2.1. Cài đặt Redis và package redis
npm install redis
2.2. Sử dụng Redis trong Node.js
const redis = require("redis");
const client = redis.createClient();
client.on("error", (err) => console.log("Redis Error", err));
async function getUser(id) {
return new Promise((resolve, reject) => {
client.get(id, (err, data) => {
if (err) reject(err);
if (data) {
console.log("Cache hit!");
resolve(JSON.parse(data));
} else {
console.log("Cache miss, fetching from DB...");
const user = { id, name: "John Doe" }; // Giả lập DB query
client.setex(id, 100, JSON.stringify(user)); // Lưu cache trong 100s
resolve(user);
}
});
});
}
(async () => {
console.log(await getUser(1)); // Lần đầu lấy từ DB
console.log(await getUser(1)); // Lần sau lấy từ Redis cache
})();
📌 Ưu điểm:
- Hỗ trợ caching phân tán (các instance Node.js khác nhau có thể dùng chung cache).
- Nhanh, có thể lưu trữ hàng triệu key.
📌 Nhược điểm: Cần thiết lập Redis server.
3. Caching kết quả API (Response Cache)
Nếu ứng dụng gọi API bên ngoài hoặc xử lý nặng, có thể cache kết quả để giảm tải.
3.1. Dùng Redis để cache API
const axios = require("axios");
async function fetchData(url) {
return new Promise((resolve, reject) => {
client.get(url, async (err, data) => {
if (err) reject(err);
if (data) {
console.log("Cache hit!");
resolve(JSON.parse(data));
} else {
console.log("Cache miss, fetching from API...");
const response = await axios.get(url);
client.setex(url, 300, JSON.stringify(response.data)); // Cache 5 phút
resolve(response.data);
}
});
});
}
(async () => {
console.log(await fetchData("https://jsonplaceholder.typicode.com/todos/1"));
console.log(await fetchData("https://jsonplaceholder.typicode.com/todos/1")); // Lần sau lấy từ cache
})();
📌 Ưu điểm: Giảm số lượng request API, tránh rate limit.
📌 Nhược điểm: Dữ liệu có thể cũ nếu không refresh hợp lý.
4. Caching trong Database (Query Cache)
Nếu ứng dụng truy vấn database thường xuyên, có thể cache kết quả query.
4.1. Cache query MySQL bằng Redis
const mysql = require("mysql2/promise");
const pool = mysql.createPool({
host: "localhost",
user: "root",
password: "password",
database: "test",
});
async function getProducts() {
return new Promise(async (resolve, reject) => {
client.get("products", async (err, data) => {
if (err) reject(err);
if (data) {
console.log("Cache hit!");
resolve(JSON.parse(data));
} else {
console.log("Cache miss, fetching from DB...");
const [rows] = await pool.query("SELECT * FROM products");
client.setex("products", 600, JSON.stringify(rows)); // Cache 10 phút
resolve(rows);
}
});
});
}
(async () => {
console.log(await getProducts()); // Lần đầu từ DB
console.log(await getProducts()); // Lần sau từ cache
})();
📌 Ưu điểm: Giảm tải database, tăng tốc query.
📌 Nhược điểm: Dữ liệu có thể không cập nhật ngay lập tức.
5. Cache phía client (Client-Side Cache)
Nếu dữ liệu không cần cập nhật liên tục, có thể cache trên trình duyệt để giảm request đến server.
5.1. Cache API response bằng etag
const express = require("express");
const app = express();
app.set("etag", "strong"); // Bật strong etag
app.get("/data", (req, res) => {
const data = { message: "Hello, world!" };
res.json(data);
});
app.listen(3000, () => console.log("Server running at port 3000"));
📌 Ưu điểm: Giảm request đến server nếu dữ liệu không thay đổi.
📌 Nhược điểm: Không phù hợp nếu dữ liệu thay đổi liên tục.
Khi nào sử dụng caching?
✅ Nên dùng caching khi:
- Dữ liệu ít thay đổi và cần truy xuất nhanh (ví dụ: danh mục sản phẩm, cấu hình).
- Hạn chế số lần gọi API bên ngoài để tránh rate limit.
- Giảm tải cho database, tăng tốc truy vấn.
❌ Không nên dùng caching khi:
- Dữ liệu thay đổi liên tục và yêu cầu real-time.
- Cần đảm bảo dữ liệu luôn mới nhất (ví dụ: giao dịch ngân hàng).
Kết luận
- Dữ liệu nhỏ, ít thay đổi →
node-cache
. - Ứng dụng lớn, cần cache phân tán → Redis.
- Giảm tải API → Cache API response.
- Tối ưu truy vấn DB → Cache database query.
- Tăng tốc trình duyệt → Client-side cache (
etag
,localStorage
).
👉 Nếu ứng dụng của bạn cần hiệu suất cao, caching là một công cụ không thể thiếu! 🚀