Redis không cứu được hệ thống của team mình
Có một giai đoạn mình nghĩ Redis là “nút turbo” cho backend. API chậm? Cache. DB nóng? Cache. Traffic tăng? Cache.
Rồi production bắt đầu cháy theo những cách rất thú vị.
Mọi thứ bắt đầu từ một dashboard
Đó là một API dashboard khá bình thường:
GET /dashboard/summary
Nó trả về:
- doanh thu
- top sản phẩm
- thống kê user
- order gần đây
- vài metrics tổng hợp
Traffic tăng dần theo thời gian.
Ban đầu:
- response ~300ms
- mọi thứ ổn
Sau vài tháng:
P95 latency: 4.8s
CPU DB: 90%
Mỗi lần sale:
- DB spike
- API timeout
- dashboard quay vòng vòng
Team mình nhìn nhau và nói câu quen thuộc:
“Hay thêm Redis?”
Và đúng là Redis giúp thật
Bọn mình cache dashboard response:
@Cacheable("dashboard")
public DashboardResponse getDashboard() {
return buildDashboard();
}
Latency từ:
4.8s → 120ms
CPU DB giảm mạnh.
Grafana nhìn đẹp trở lại.
Ai cũng vui.
Mình nhớ lúc đó còn nghĩ:
“Sao không dùng Redis sớm hơn?”
Hai tuần sau, production lại bắt đầu lag
Lần này kỳ lạ hơn.
Không phải lúc nào cũng chậm.
Mà là:
- random spike
- CPU DB nhảy đột ngột
- Redis hit rate vẫn cao
- app vẫn timeout
Điều khó chịu nhất là:
metrics nhìn “không quá tệ”.
Redis hit rate 95%, nhưng DB vẫn chết
Đây là phần làm mình mất khá lâu mới hiểu.
Cache hit rate rất đẹp:
95%
Nghe rất ổn đúng không?
Sai.
Vì:
- 5% miss còn lại
- chính là traffic nguy hiểm nhất
Dashboard endpoint có traffic cực lớn.
Ví dụ:
10000 requests/min
5% miss nghĩa là:
500 requests/min hit DB thật
Mà mỗi request:
- query aggregation
- JOIN nhiều bảng
- scan dữ liệu lớn
DB vẫn bị đánh liên tục.
Lúc đó mình mới hiểu:
Cache hit rate cao không đồng nghĩa hệ thống khỏe.
Sai lầm tiếp theo: cache tất cả mọi thứ
Sau dashboard, team bắt đầu cache thêm:
- products
- categories
- recommendations
- user profile
- analytics
Redis memory tăng cực nhanh.
Ban đầu:
512MB
Sau vài tuần:
6GB
Rồi một ngày:
- eviction bắt đầu xảy ra
- latency tăng
- hit rate giảm
- DB bị spam lại
Production quay về địa ngục cũ.
Điều bọn mình không nghĩ tới
Redis không phải “free performance”.
Bạn đang:
- đổi DB pressure
- lấy memory pressure
- thêm network hop
- thêm consistency problem
- thêm invalidation complexity
Mọi cache đều có cost.
Phần khó nhất không phải cache
Mà là:
cache invalidation.
Có một bug rất vui.
Product đã update giá trong DB.
Nhưng API vẫn trả giá cũ.
Vì cache chưa bị evict.
User thấy:
- giá A ngoài homepage
- giá B trong checkout
Support bắt đầu nhận ticket.
Đó là lúc cả team nhận ra câu này đúng đến đáng sợ:
"There are only two hard things in Computer Science:
cache invalidation and naming things."
Rồi cache stampede xuất hiện
Đây là thứ làm production của team mình chết nhanh nhất.
Cache dashboard có TTL:
5 phút
Nghe hợp lý.
Cho đến đúng phút cache expire.
Hàng nghìn request cùng lúc:
- miss cache
- cùng rebuild dashboard
- cùng hit DB
CPU DB lên 100%.
Connection pool bắt đầu pending.
Timeout xuất hiện khắp nơi.
Chỉ vì:
tất cả request cùng rebuild một cache key.
Redis lúc đó không cứu được gì nữa
Nó chỉ trở thành:
- một layer nằm giữa app và DB
- trong khi bottleneck thật vẫn còn nguyên.
Đó là lúc mình bắt đầu đọc kỹ hơn về:
- cache stampede
- hot keys
- distributed locks
- probabilistic expiration
Trước đó mình nghĩ:
“thêm Redis là xong.”
Thực tế phức tạp hơn nhiều.
Một vấn đề khác: cache stale
Có những data:
- được update liên tục
- nhưng vẫn bị cache
Ví dụ:
- inventory
- stock
- pricing realtime
Kết quả:
- data inconsistency
- race conditions
- user nhìn thấy trạng thái sai
Team bắt đầu thêm:
- evict logic
- message queue
- sync jobs
- retry mechanisms
System complexity tăng gấp nhiều lần.
Điều đau nhất
Sau rất nhiều debugging, mình nhận ra:
Redis chưa bao giờ là root fix.
Nó chỉ đang che đi:
- query tệ
- aggregation tệ
- N+1
- thiếu index
- transaction quá to
- blocking calls
Bọn mình cache một endpoint mất:
- 4 giây
thay vì hỏi:
“Tại sao nó mất 4 giây?”
Đó là sai lầm lớn nhất.
Một query tốt đáng giá hơn nhiều cache tệ
Sau này team bắt đầu:
- rewrite queries
- thêm index đúng
- precompute aggregation
- tách read model
- giảm JOIN nặng
- async một số tasks
Kết quả:
Dashboard:
4.8s → 280ms
Ngay cả khi:
- Redis down
- system vẫn chạy được.
Đó mới là cảm giác “khỏe thật”.
Redis vẫn rất mạnh
Mình không anti Redis.
Redis cực kỳ hữu ích cho:
- session storage
- rate limiting
- queues
- distributed locks
- caching read-heavy data
- temporary computation
Nhưng Redis không phải:
“performance magic button”.
Nếu root cause chưa được xử lý:
- cache chỉ delay vấn đề
- không giải quyết vấn đề.
Một điều mình thấy nhiều team hay làm
Traffic tăng.
Ngay lập tức:
- thêm Redis
- thêm Kafka
- thêm microservices
- thêm Kubernetes
Trong khi bottleneck thật đôi khi chỉ là:
SELECT * FROM orders
không có index.
Sau vài năm làm backend, mình thấy:
Phần lớn performance issue không bắt đầu từ:
- thiếu Redis
- thiếu distributed system
- thiếu fancy architecture
Mà từ:
- query không kiểm soát
- ORM usage sai
- transaction giữ connection quá lâu
- external calls blocking
- không đo metrics
Redis chỉ làm những vấn đề đó khó nhìn thấy hơn.
Điều team mình thay đổi sau incident đó
1. Không cache trước khi đo bottleneck
Đầu tiên luôn là:
- metrics
- tracing
- profiling
- query analysis
Không đo → không optimize.
2. Cache phải có strategy rõ ràng
Mỗi cache cần:
- TTL
- invalidation rule
- ownership
- monitoring
Không có strategy:
- sớm muộn cũng thành technical debt.
3. Cache hit rate không đủ để đánh giá
Quan trọng hơn là:
- DB load
- tail latency
- rebuild cost
- hot key behavior
4. Redis down không được làm system chết
Nếu Redis là SPOF:
- bạn vừa tạo thêm một vấn đề mới.
Có một câu mình rất thích sau incident đó
"Cache is a performance optimization,
not a substitute for understanding your system."
Mình thấy câu này đúng với gần như mọi backend system mình từng làm.
Kết luận
Redis rất mạnh.
Nhưng càng dùng nhiều, mình càng thấy:
- cache là trade-off
- không phải free lunch.
Có những lúc Redis cứu hệ thống.
Nhưng cũng có những lúc:
- nó che bottleneck thật
- làm debugging khó hơn
- tăng complexity nhanh khủng khiếp.
Điều giúp backend ổn định hơn về lâu dài thường là:
- query tốt
- observability tốt
- transaction hợp lý
- architecture đơn giản
- hiểu bottleneck thật sự nằm ở đâu
Chứ không phải thêm một layer cache rồi hy vọng mọi thứ sẽ tự nhanh hơn.
All rights reserved