1. Caching là gì?
Caching là kỹ thuật lưu tạm dữ liệu đã được tính toán hoặc truy xuất trước đó để có thể sử dụng lại nhanh hơn trong những lần truy cập tiếp theo. Giả sử một API lấy thông tin sản phẩm từ PostgreSQL. Mỗi request đều truy vấn database, chuyển đổi dữ liệu rồi trả về client. Nếu sản phẩm đó được hàng nghìn người xem trong thời gian ngắn, hệ thống có thể phải thực hiện hàng nghìn truy vấn tương tự. Thay vì truy vấn database mỗi lần, ứng dụng có thể lưu kết quả vào cache. Những request tiếp theo đọc dữ liệu từ cache cho đến khi dữ liệu hết hạn hoặc bị vô hiệu hóa.
2. Redis là gì?
Redis là một hệ thống lưu trữ dữ liệu trong bộ nhớ, hỗ trợ nhiều cấu trúc dữ liệu và các thao tác có độ trễ thấp. Redis thường được sử dụng cho:
- Caching dữ liệu từ database.
- Lưu session đăng nhập.
- Rate limiting.
- Đếm lượt truy cập.
- Leaderboard và bảng xếp hạng.
- Distributed locking trong những trường hợp phù hợp.
- Pub/Sub và Redis Streams.
- Lưu trạng thái tạm thời của các tác vụ.
Redis có thể giảm số lần truy vấn database và giảm độ trễ khi đọc dữ liệu đã được cache. Tuy nhiên, cache thêm một tầng vận hành và không tự giải quyết mọi vấn đề về hiệu năng.
Redis có phải database không?
Có. Redis là một hệ thống lưu trữ dữ liệu thực sự, không chỉ là thư viện cache.
Redis có thể được cấu hình để lưu dữ liệu xuống ổ đĩa thông qua các cơ chế persistence. Tuy vậy, khi sử dụng Redis làm cache, ứng dụng thường phải chấp nhận rằng dữ liệu cache có thể bị xóa, hết hạn hoặc mất sau sự cố tùy cấu hình.
3. Vì sao cần Caching?
Giảm độ trễ
Truy vấn database thường cần xử lý SQL, đọc index hoặc dữ liệu, sử dụng connection pool và truyền kết quả qua mạng.
Với dữ liệu đã có trong Redis, ứng dụng có thể bỏ qua phần lớn công việc đó và lấy kết quả trực tiếp từ cache.
Tuy nhiên, tốc độ thực tế phụ thuộc vào network, kích thước dữ liệu, serialization, tải hệ thống và cách triển khai. Không nên mặc định mọi thao tác Redis đều nhanh hơn mọi truy vấn database.
Giảm tải database
Giả sử một endpoint nhận 10.000 request trong một phút. Nếu phần lớn request đọc cùng một danh sách danh mục sản phẩm, cache có thể giúp tránh thực hiện lại cùng truy vấn trên database.
Điều này có thể giảm:
- Số truy vấn đọc.
- Sử dụng CPU trên database.
- Áp lực lên connection pool.
- Chi phí đọc dữ liệu.
- Khả năng database bị quá tải khi traffic tăng đột biến.
Tăng khả năng phục vụ traffic
Khi database là điểm nghẽn, cache có thể giúp backend phục vụ nhiều request hơn mà không phải tăng tài nguyên database tương ứng.
Nhưng cache chỉ có lợi rõ rệt khi dữ liệu được truy cập lặp lại và cache hit rate đủ cao. Nếu mỗi request truy cập một dữ liệu hoàn toàn khác nhau, cache có thể làm tăng độ phức tạp mà không tiết kiệm được nhiều truy vấn.
4. TTL – Time To Live
TTL (Time To Live) là khoảng thời gian một key được phép tồn tại trước khi Redis xem nó là hết hạn.
Ví dụ:
SET product:101 '{"name":"Keyboard"}' EX 60
Key product:101 được đặt TTL 60 giây.
TTL giúp giới hạn thời gian dữ liệu cache có thể trở nên cũ. Khi TTL hết hạn, key không còn được xem là dữ liệu hợp lệ cho các lần truy cập tiếp theo.
TTL không bảo đảm dữ liệu luôn mới
Giả sử sản phẩm có giá 100. Backend cache giá trong 5 phút. Một quản trị viên đổi giá thành 120 trong database ngay sau khi cache được ghi.
Trong khoảng thời gian còn lại, ứng dụng có thể trả về giá 100 nếu chưa có cơ chế invalidation.
Vì vậy, TTL chỉ giới hạn thời gian tồn tại của cache entry; nó không tự bảo đảm dữ liệu luôn đồng bộ với database.
5. Cache-Aside Pattern – Mô hình cache phổ biến nhất
Cache-aside, còn gọi là lazy loading, là chiến lược phổ biến khi dùng Redis để cache dữ liệu từ database.
Nguyên tắc:
- Đọc Redis trước.
- Nếu có dữ liệu, trả về.
- Nếu không có, truy vấn database.
- Lưu kết quả vào Redis với TTL.
- Trả dữ liệu cho client.
Ưu điểm:
- Chỉ cache dữ liệu thực sự được truy cập.
- Không cần nạp toàn bộ database vào Redis.
- Dễ tích hợp vào backend hiện có.
- Cache có thể được xóa và tái tạo từ nguồn dữ liệu chính.
Nhược điểm:
- Request đầu tiên sau khi cache miss phải truy vấn database.
- Có thể phát sinh nhiều truy vấn đồng thời khi một key hết hạn.
- Cần xử lý cache invalidation sau khi dữ liệu thay đổi.
- Nếu cache và database không được đồng bộ đúng cách, có thể trả dữ liệu cũ.
6. Cache Stampede – Nhiều request cùng truy vấn database
Cache stampede xảy ra khi một cache entry phổ biến hết hạn hoặc bị xóa, khiến nhiều request đồng thời cache miss và cùng truy vấn database.
Ví dụ, 500 request cùng đọc product:101. Key hết hạn đúng lúc cả 500 request đến. Nếu mỗi request đều truy vấn database, cache có thể làm giảm tải bình thường nhưng lại tạo ra đột biến tải khi cache miss.
cách sử lý
Singleflight trong cùng một process: gom nhiều request cùng key để chỉ một request thực hiện truy vấn nguồn trong một thời điểm trên process đó. Các process khác vẫn có thể thực hiện truy vấn riêng.
Distributed lock: dùng Redis lock hoặc một cơ chế điều phối giữa nhiều instance để hạn chế việc cùng nạp một key. Cần thiết kế lease, timeout và cách xử lý lock hết hạn; không được giả định lock đơn giản luôn bảo đảm tính đúng đắn trong mọi sự cố.
TTL jitter: thêm một lượng ngẫu nhiên nhỏ vào TTL để nhiều key không đồng loạt hết hạn.
7. Tổng kết
Redis là hệ thống lưu trữ dữ liệu trong bộ nhớ với nhiều cấu trúc dữ liệu, còn caching là kỹ thuật tái sử dụng kết quả để giảm độ trễ và tải cho nguồn dữ liệu chính.








Khoá học lập trình game con rắn cho trẻ em




