Khi bắt đầu triển khai cache vào hệ thống thực tế, một câu hỏi mới xuất hiện:
Nếu dữ liệu đã nằm trong cache, ứng dụng sẽ đọc và ghi dữ liệu như thế nào?
Nghe có vẻ đơn giản, nhưng đây chính là nơi xuất hiện hàng loạt chiến lược caching khác nhau.
Mỗi chiến lược đều cố gắng cân bằng giữa ba yếu tố:
Hiệu năng
Tính nhất quán dữ liệu
Độ phức tạp khi triển khai
Không có chiến lược nào tốt nhất cho mọi hệ thống. Điều quan trọng là hiểu cách chúng hoạt động để lựa chọn phù hợp với bài toán của mình.

Đặc điểm:
Application chịu trách nhiệm quản lý việc đọc và ghi giữa Cache và Database.
Đây là mô hình phổ biến nhất trong các hệ thống hiện nay vì đơn giản và dễ triển khai.
Đây là cặp chiến lược thường được sử dụng cùng nhau.
Khi cache hit:
Trả thẳng dữ liệu có từ cache
Khi cache miss:
Ứng dụng đọc từ Database
Đưa dữ liệu vào Cache
Trả kết quả về cho người dùng
Khi nào cần ghi mới dữ liệu vào cache
Những thành phần phần cấu hình nên dữ liệu này đã được thay đổi
Khi phần dữ liệu được cache không còn do đã bị xoá hoặc đã hết hạn
Khi ghi đạt vào trong 2 điều kiện trên :
Cache không được cập nhật ngay.
Dữ liệu chỉ được đưa vào Cache khi có nhu cầu đọc sau đó.
User cập nhật hồ sơ:
Cập nhập profile customer ở disk database
Xóa cache liên quan đến hồ sơ vừa được cập nhật
Lần request profile tiếp theo phát hiện cache Miss
Query dữ liệu từ disk và load lại vào cache.
Đơn giản, dễ triển khai ở bất kỳ đâu trong toàn bộ logic của dự án
Chỉ cache dữ liệu thực sự được sử dụng ở những chỗ cần thiết
Giảm dung lượng cache sử dụng vì chỉ những dữ liệu thực sự được truy cập mới được đưa vào cache.
Cache miss đầu tiên luôn phải truy cập Database
Read đầu tiên sau cache Miss sẽ take time nếu là api cần xử lý lâu
Dễ gặp Cache Stampede (Nhiều request cùng lúc gặp Cache Miss và đồng thời truy vấn Database)
Khó quản lý các luồng đọc/ghi cache khi triển khai rải rác khắp source
Product Catalog
User Profile
CMS
Hầu hết hệ thống CRUD
Dữ liệu ghi nhiều nhưng không phải lúc nào cũng được đọc

Cache Loader / Data Source Adapter sẽ được Cache layer được cấu hình trước.
Toàn bộ trách nhiệm đọc và ghi được giao cho Cache Layer.
Cách tiếp cận này thường xuất hiện trong các hệ thống lớn hoặc nền tảng có nhiều service dùng chung dữ liệu.
Khi cache miss:
Cache Layer tự động lấy dữ liệu từ Database
Tự cập nhật Cache
Trả kết quả cho Application
Application không cần biết dữ liệu đến từ đâu.
Khi ghi dữ liệu:
Application
|
v
Cache Layer
|
+--> Cache
|
+--> Database
Sau khi ghi:
Cache = New Value
DB = New Value
Application cập nhật giá sản phẩm:
Update Product Price
|
v
Cache Layer
|
+----+----+
| |
Cache Database
Kết quả:
Cache = 100$
DB = 100$
Lần đọc tiếp theo:
Read Product Price
|
v
Cache Hit
Logic cache được tập trung vào một chỗ
Application đơn giản hơn
Cache và Database được cập nhật trong cùng luồng ghi nên độ nhất quán rất cao.
Read sau Write thường là Cache Hit
Dễ quản lý khi có nhiều service
Cần Cache Provider hoặc Cache Loader
Triển khai phức tạp hơn
Mỗi lần ghi phải cập nhật cả Cache và Database, làm tăng độ trễ ghi và số lượng thao tác I/O.
Hệ thống lớn
Microservices
Pricing Service
Product Information
Metadata Service
Nhiều service cùng truy cập dữ liệu
Hai nhóm phía trên tập trung vào tính nhất quán dữ liệu.
Một số hệ thống chấp nhận đánh đổi tính nhất quán để đổi lấy tốc độ ghi.
Ghi vào Cache trước, Database cập nhật sau.

Tốc độ ghi cực nhanh
Giảm tải Database
Hỗ trợ batch write hiệu quả
Eventual Consistency
Nguy cơ mất dữ liệu khi hệ thống gặp sự cố
Khó xử lý rollback
Like Counter
View Counter
Analytics
Logging
Telemetry
Thanh toán
Số dư tài khoản
Giao dịch tài chính
Inventory thời gian thực

Thường chỉ áp dụng cho các dữ liệu được truy cập thường xuyên hoặc có giá trị cao.
Thông thường:
TTL = 10 phút
10:00 Cache Expired
10:01 User Request
10:01 Database Query
Người dùng đầu tiên sau khi cache hết hạn sẽ phải chờ Database.
Refresh Ahead chủ động làm mới dữ liệu trước khi cache hết hạn.
TTL còn 10%
|
v
Background Job
|
v
Refresh Cache
Kết quả:
Cache luôn nóng
Giảm Cache Miss
Latency ổn định hơn
Homepage
Trending Products
Dashboard
Configuration Data
Frequently Accessed Data