Các chiến lược Caching với Redis trong Node.js
Tìm hiểu các mô hình thiết kế bộ nhớ đệm (caching patterns) phổ biến như Cache-Aside, Write-Through nhằm tăng tốc độ phản hồi API.
Các chiến lược Caching với Redis trong Node.js
Trong các hệ thống phân tán hiệu năng cao, Redis đóng vai trò cực kỳ quan trọng như một lớp bộ nhớ đệm (Cache) tốc độ cực nhanh, giúp giảm tải trực tiếp cho cơ sở dữ liệu quan hệ phía sau.
Tuy nhiên, việc sử dụng cache sai cách có thể dẫn đến lỗi không đồng bộ dữ liệu (stale data). Dưới đây là 2 chiến lược thiết kế bộ nhớ đệm phổ biến nhất.
1. Chiến lược Cache-Aside (Lazy Loading)
Đây là chiến lược phổ biến nhất. Ứng dụng sẽ tìm kiếm dữ liệu trong Cache trước. Nếu có (cache hit), trả về ngay. Nếu không có (cache miss), ứng dụng truy vấn database, cập nhật vào cache và trả về.
async function getUserData(userId) {
const cacheKey = `user:${userId}`;
// 1. Kiểm tra trong Redis cache
const cachedData = await redis.get(cacheKey);
if (cachedData) {
return JSON.parse(cachedData);
}
// 2. Cache miss -> Truy vấn database
const userData = await db.findUser(userId);
// 3. Cập nhật Redis và thiết lập thời gian hết hạn (TTL)
await redis.set(cacheKey, JSON.stringify(userData), 'EX', 3600); // hết hạn sau 1 tiếng
return userData;
}
2. Chiến lược Write-Through (Ghi đồng thời)
Khi dữ liệu thay đổi, ứng dụng sẽ cập nhật đồng thời vào cả database lẫn Cache. Chiến lược này đảm bảo dữ liệu trong cache luôn mới nhất, nhưng tốc độ ghi sẽ chậm hơn một chút vì phải thực hiện hai thao tác song song.
3. Các lưu ý quan trọng khi dùng Cache
- Phải luôn thiết lập TTL (Time-To-Live): Đừng bao giờ lưu dữ liệu vĩnh viễn trong cache trừ khi bạn có cơ chế thu hồi (invalidation) cực kỳ chặt chẽ.
- Tránh Cache Stampede: Khi một key hot hết hạn cùng lúc, hàng ngàn request sẽ cùng đổ dồn vào database để lấy dữ liệu mới. Hãy sử dụng cơ chế locking hoặc cập nhật nền chủ động để giải quyết vấn đề này.
Chúc các bạn thiết lập hệ thống cache tối ưu!