Đây là thundering herd kết hợp cache trống. Bình thường cache hấp thụ 95%+ lưu lượng đọc, DB chỉ nhận phần rất nhỏ và được cấp phát theo mức đó. Khi cache trống, 100% lưu lượng đập thẳng vào DB — mức tải mà DB chưa bao giờ được thiết kế để chịu. Tệ hơn: hàng nghìn request cùng miss một khoá sẽ cùng chạy đúng một query, DB làm đi làm lại cùng một việc.
Ba tình huống hay gặp: Redis restart hoặc bị evict hàng loạt; nhiều khoá cùng hết hạn một lúc (vì được nạp cùng lúc, cùng TTL); và retry storm — client timeout rồi retry, nhân đôi lưu lượng đúng lúc hệ thống yếu nhất.
Cách chống:
- Request coalescing / single-flight: chỉ cho một request đi tính lại giá trị cho mỗi khoá, các request còn lại chờ kết quả đó. Cắt N query xuống 1.
- TTL có jitter: TTL ngẫu nhiên trong khoảng (ví dụ 300s ± 60s) để các khoá không hết hạn đồng loạt.
- Làm mới sớm: khi khoá gần hết hạn thì một request nền cập nhật lại trong khi bản cũ vẫn được phục vụ (stale-while-revalidate).
- Cache warming: nạp sẵn các khoá nóng trước khi mở lưu lượng vào instance/cache mới.
- Đặt trần đồng thời về phía DB kèm load shedding: thà trả 503 cho một phần lưu lượng còn hơn để DB dừng phục vụ toàn bộ.
- Retry có backoff và jitter, và có ngân sách retry — retry không kiểm soát là chất đốt của sự cố lan rộng.
Cần kiểm chứng bằng diễn tập: chủ động xoá cache trên môi trường thử nghiệm ở mức tải thật, xem DB có sống không.