Kiến trúc Caching chuyên sâu: Giải quyết bài toán Latency và hiểu hơn về Caching Patterns (Demo 1.000 records).
Chào các bạn,
Hôm nay mình sẽ chia sẻ trải nghiệm xây dựng một dự án demo về Caching Patterns cực kỳ nhanh chóng và chuẩn chỉnh bằng cách sử dụng tool nodejs-quickstart-structure. Đây là một case study thực tế về việc kết hợp giữa kiến trúc sạch (Clean Architecture) với sức mạnh của tool này.

Câu chuyện bắt đầu: Tại sao lại là Caching?
Trong các hệ thống lớn, Caching là "cứu cánh" để giảm tải cho Database và tối ưu tốc độ phản hồi. Tuy nhiên, việc chọn Pattern nào (Cache-Aside, Write-Through,...) lại phụ thuộc vào từng bài toán. Để hiểu rõ, mình quyết định build một source demo showcase tất cả các Pattern này.
Và để không mất thời gian cấu hình boilerplate, mình đã chọn nodejs-quickstart-structure làm "nền móng".
5 Caching Patterns: Hiểu rõ để áp dụng đúng
Dưới đây là chi tiết 5 loại pattern mình đã triển khai trong project demo:
1. Cache-Aside (Lazy Loading)

- Mục đích: Ứng dụng tự quản lý cache. Chỉ nạp data vào cache khi cần thiết.
- Khi nào dùng: Phù hợp cho các hệ thống có tần suất Đọc >> Ghi, phổ biến nhất (User Profile).
- Ưu điểm: Tiết kiệm bộ nhớ, dữ liệu chỉ load khi thực sự cần và kiểm soát tối đa logic cache.
2. Read-Through

- Mục đích: Ẩn logic fetch data từ DB vào trong Cache Provider. App chỉ việc gọi "Get" từ Cache.
- Khi nào dùng: Khi muốn clean code ở tầng Use Case.
- Ưu điểm: Code Business cực sạch.
3. Write-Through

- Mục đích: Ghi dữ liệu vào cả Cache và DB đồng thời.
- Khi nào dùng: Khi cần tính nhất quán cao (Strong Consistency)
- Ưu điểm: Data luôn đồng bộ 100%.
4. Write-Around

- Mục đích: Ghi thẳng vào DB và xóa sạch (invalidate) cache cũ.
- Khi nào dùng: Dữ liệu ghi vào có thể sẽ không được đọc lại ngay, chỉ Cache khi đọc và dữ liệu ít khi được đọc lại ngay.
- Ưu điểm: Tránh làm "rác" bộ nhớ Cache.
5. Write-Back (Write-Behind)

- Mục đích: Ghi vào Cache trước, DB update âm thầm ở background.
- Khi nào dùng: Cần Write-Performance cực cao như hệ thống High-load (Log, Metrics).
- Ưu điểm: Tốc độ ghi cực nhanh.
Cùng bắt đầu triển khai kỹ thuật nào! (Step-by-Step)
Để xây dựng một source code chuẩn như demo này, mình đã thực hiện theo trình tự sau:
-
Khởi tạo dự án: Sử dụng npx để init source theo Clean Architecture.
- chạy lệnh này trên terminal:
npx nodejs-quickstart-structure@latest init - sau đó chọn theo structure này tool sẽ automation tạo structure cho bạn:
- Project name: nodejs-service-caching-pattern
- Select Language: TypeScript
- Select Architecture: Clean Architecture
- Select Database: MySQL
- Database Name: demo
- Microservices Communication: REST APIs
- Caching Layer: Redis
- Select CI/CD Provider: GitHub Actions
- chạy lệnh này trên terminal:
-
Định nghĩa Interface (Domain Layer): Đây là bước quan trọng nhất để đảm bảo tính trừu tượng.
export interface ICacheService { get<T>(key: string): Promise<T | null>; set(key: string, value: unknown, ttl?: number): Promise<void>; del(key: string): Promise<void>; getOrSet<T>(key: string, fetcher: () => Promise<T>, ttl?: number): Promise<T>; }export interface IUserRepository { findById(id: number | string): Promise<User | null>; save(user: User): Promise<User>; } -
Cập nhật Infrastructure: Triển khai thực tế cho Redis và Database (Sequelize).
-
Database Seeding: Tạo dữ liệu mẫu 1000 users để demo.
-
Triển khai 5 Use Cases Caching:
// Read-Through: Provider (Cache) tự gọi DB nếu Miss return await this.cacheService.getOrSet<User | null>(cacheKey, async () => { return await this.userRepository.findById(id); }, 3600);// Write-Back: Update Cache ngay, DB update sau (async) await this.cacheService.set(cacheKey, updatedUser, 3600); this.asyncDatabaseUpdate(updatedUser); // background task -
Tạo API & Documentation:
-
Testing & Coverage: Viết unit test đảm bảo chất lượng và logic.
Hướng dẫn Test & Kiểm chứng (Manual Trigger)
Sau khi đã triển khai xong, đây là cách bạn có thể trigger các API để kiểm chứng logic hoạt động:
1. Test Cache-Aside / Read-Through (Read Path)
- Lần 1 (Cold Cache):
curl -X GET http://localhost:3000/api/demo/cache-aside/1- Logic: App check Redis (Miss) -> Query MySQL -> Set Redis -> Trả về.
- Lần 2 (Warm Cache): Gọi lại cùng lệnh.
- Logic: App check Redis (Hit) -> Trả về ngay. Latency cực thấp.
2. Test Write-Through (Sync Write)
- Trigger:
curl -X POST http://localhost:3000/api/demo/write-through -H "Content-Type: application/json" -d '{"name": "Viblo", "email": "viblo@test.com"}'- Logic: Service ghi đồng thời vào MySQL VÀ Redis.
3. Test Write-Around (Clean Write)
- Trigger:
curl -X POST http://localhost:3000/api/demo/write-around -H "Content-Type: application/json" -d '{"name": "Guest", "email": "guest@test.com"}'- Logic: Ghi vào MySQL, sau đó gọi
DELxóa key trong Redis.
- Logic: Ghi vào MySQL, sau đó gọi
4. Test Write-Back (Async Write)
- Trigger:
curl -X PUT http://localhost:3000/api/demo/write-back/1 -H "Content-Type: application/json" -d '{"name": "Fast Update"}'- Logic: Update Redis ngay lập tức. DB sẽ được update sau một khoảng trễ ngắn (async).
Kết luận & Cảm nhận về nodejs-quickstart-structure
Điều bạn sẽ thích nhất ở tool nodejs-quickstart-structure không chỉ là việc init code nhanh, mà là tính AI-Native. Với file .cursorrules và các prompts/ đi kèm và auto step startup app trên môi trường dev đên production, mình luôn giữ được kiến trúc sạch và code style đồng nhất.
Link Source Code: [https://github.com/paudang/nodejs-service-caching-pattern]
Link Prompt Skills: [https://github.com/paudang/nodejs-service-caching-pattern/tree/main/prompts]
Source article:https://dev.to/paudang/master-caching-patterns-a-clean-architecture-guide-with-ai-native-tooling-p7j
Hy vọng bài viết này giúp các bạn hiểu rõ hơn về Caching!
All rights reserved