Bản Chất Của "In-Memory" Trong Redis là gì
Câu chuyện muôn thuở: Hệ thống E-commerce của bạn đang chạy chiến dịch Flash Sale. Có khoảng 10.000 user liên tục F5 trang chủ để xem Top 10 sản phẩm bán chạy nhất. MySQL của bạn khóc thét, CPU giật lên 100% vì phải thực hiện câu query ORDER BY sales DESC LIMIT 10 hàng chục ngàn lần mỗi giây.
Lúc này, giải pháp cứu mạng được đưa ra là Redis. Đẩy cái Top 10 đó vào Redis, và MySQL được giải cứu. Response time từ 500ms giảm rụp xuống còn... 2ms.
Chuyện gì vừa xảy ra vậy? Phép màu nào nằm bên trong cái logo hình hộp màu đỏ đó? Câu trả lời nằm trọn trong một từ: In-Memory.
1. In-Memory là gì? Đừng coi thường Vật lý học
Để hiểu "In-Memory", bạn phải nhớ lại cấu tạo của máy tính. Dữ liệu có thể được lưu ở 2 nơi chính:
- Ổ cứng (Disk - HDD/SSD): Nơi chứa Database truyền thống như MySQL, PostgreSQL, MongoDB.
- Bộ nhớ trong (RAM - Memory): Nơi chứa biến,
objectcủa ứng dụng khi đang chạy.
Các Database truyền thống lưu dữ liệu xuống Ổ cứng. Dù bạn xài SSD xịn đến mấy, mỗi lần query, hệ điều hành vẫn phải làm một mớ thủ tục: Gọi I/O, quét mặt đĩa (với HDD) hoặc cell (với SSD), nạp lên RAM rồi mới trả về. Giống như bạn đang ngồi học, cần tra một định nghĩa, bạn phải đi bộ ra thư viện, tìm đúng kệ sách, lật đúng trang. Rất mất thời gian (tính bằng mili-giây - ms).
Redis thì khác. Nó là một "In-Memory Data Store". Nghĩa là toàn bộ dữ liệu của Redis được lưu 100% trên RAM.
Khi query vào Redis, nó đọc trực tiếp từ RAM. Giống như quyển sách bạn cần tra đã mở sẵn và đặt ngay trước mặt bạn. Tốc độ truy xuất của RAM tính bằng nano-giây (ns) – tức là nó nhanh hơn ổ cứng từ hàng trăm đến hàng ngàn lần!
2. Ủa, nếu chỉ là lưu trên RAM, sao không xài biến toàn cục (Global Variable)?
Nhiều anh em sẽ thắc mắc: "Lưu trên RAM thì mình khai báo một cái Map trong Go, hay một cái Object bự trong Node.js rồi nhét data vào đó làm Cache luôn cho tiện. Cài thêm Redis làm gì cho cực?"
Ý tưởng đó gọi là Local Cache. Nó chạy rất ngon, cho đến khi dự án của bạn Scale (mở rộng). Hãy tưởng tượng Backend của bạn đang chạy 5 instances (5 server khác nhau) để chia tải.
- User A request vào Server 1, Server 1 query MySQL rồi lưu vào Local RAM của nó.
- Lần sau User A request lại rớt vào Server 2. Server 2 không có data đó trong RAM, lại phải đi chọc vào MySQL.
- Chưa kể, nếu data thay đổi, bạn update ở Server 1 thì 4 Server kia không hề biết, dẫn đến data bị sai lệch.
Redis giải quyết bài toán này. Nó đóng vai trò là một thanh RAM "tập trung" nằm ở một Server riêng biệt. Cả 5 instances Backend của bạn đều kết nối chung vào con Redis này. Data đồng nhất 100%, ai đọc ai ghi cũng chung một nguồn.
- Mặt tối của In-Memory: Lời nguyền "Bốc Hơi" và "Đắt Đỏ" In-Memory mang lại sức mạnh của một vị thần, nhưng nó đi kèm với 2 điểm yếu chí mạng mà một Vibe Coder phải nằm lòng:
- Sự bay hơi (Volatility): Rút phích cắm server, hoặc Redis bị crash, TOÀN BỘ dữ liệu trong RAM sẽ bốc hơi sạch sẽ không tì vết. (Dù Redis có cơ chế RDB/AOF để backup xuống đĩa cứng thỉnh thoảng, nhưng về bản chất RAM vẫn là bộ nhớ tạm). Do đó, tuyệt đối không dùng Redis làm nguồn chân lý duy nhất (Primary Database) cho các dữ liệu sống còn như lịch sử giao dịch hay số dư ví.
- Sự đắt đỏ: SSD 1TB mua ngoài tiệm có vài triệu bạc. Nhưng để thuê một Server có 1TB RAM trên AWS/Google Cloud thì chi phí bằng cả tháng lương của team Dev gộp lại. Bạn không thể "cái gì cũng LIKE", và cũng không thể "cái gì cũng nhét vào Redis".
4. Mindset xài Redis chuẩn Vibe Coder
Vì RAM đắt và dung lượng có hạn, bạn phải đối xử với Redis như một mảnh đất vàng ở trung tâm quận 1:
- Chỉ lưu data được truy cập rất nhiều (Hot data).
- Luôn luôn phải có TTL (Time-To-Live). Đã nhét data vào Redis thì phải cho nó một cái hạn sử dụng (ví dụ 10 phút, 1 tiếng). Hết hạn, Redis tự xóa để giải phóng RAM cho data khác. Không có TTL, sớm muộn gì Server của bạn cũng dính án tử OOM (Out Of Memory).
Lời kết
Redis không phải là phép thuật, nó đơn giản là việc tận dụng triệt để định luật vật lý về tốc độ của bộ nhớ RAM. Hiểu được In-Memory, bạn sẽ thôi ảo tưởng việc dùng Redis để lưu trữ toàn bộ thế giới, mà sẽ dùng nó đúng chỗ như một lưỡi dao mổ cực kỳ sắc bén.
Chủ đề tiếp theo: Cache Stampede - Hiệu Ứng Bầy Đàn Dẫm Đạp Database
Bạn đã hiểu Redis và áp dụng nó. Bạn set TTL cho cái Top 10 sản phẩm bán chạy là 5 phút. Trong 5 phút đó, MySQL ngủ yên, hệ thống mượt mà.
Nhưng chuyện gì xảy ra đúng vào giây thứ 301? Lúc đó Key trên Redis vừa hết hạn (Expire) và biến mất. Ngay khoảnh khắc đó, có 5000 request cùng lúc ập vào, thấy Redis trống không, thế là cả 5000 request đó nắm tay nhau lao thẳng vào MySQL để bắt nó tính toán lại Top 10. BÙM! MySQL sập ngay lập tức vì bị đấm bất ngờ.
Hiện tượng này gọi là Cache Stampede (Hiệu ứng bầy đàn). Ở bài viết tới, mình sẽ hướng dẫn anh em cách sử dụng Khóa phân tán (Distributed Lock) để trị đám đông hỗn loạn này, đảm bảo dù Cache có hết hạn thì Database vẫn an toàn tuyệt đối. Anh em nhớ đón đọc nhé!
All Rights Reserved