CodeReady
Quay lại danh sách case study

Xử lý Flash Sale chịu tải hàng trăm nghìn lượt truy cập đồng thời

Giải quyết bài toán sập hệ thống Backend Node.js trong đợt Flash Sale do tranh chấp tài nguyên và quá tải database.

Bối cảnh

Hệ thống thương mại điện tử sử dụng Node.js kết hợp PostgreSQL chịu tải đột biến gấp 50 lần bình thường trong sự kiện Flash Sale, dẫn đến chết kết nối database.

Vấn đề cần xử lý

Quá nhiều request đồng thời cùng gọi lệnh UPDATE trừ số lượng sản phẩm tồn kho, gây khóa hàng loạt (row-level locking) trên PostgreSQL và làm tràn bộ nhớ Node.js.

Hướng xử lý đề xuất

Chuyển toàn bộ logic kiểm tra và trừ tồn kho sang Redis sử dụng Redis Lua Script để đảm bảo tính nguyên tử (atomic). Đồng thời, đưa request vào hàng đợi (Message Queue) và chỉ ghi xuống database bất đồng bộ theo lô (batch processing).

Câu trả lời mẫu khi phỏng vấn

Khi đối mặt với bài toán Flash Sale, tôi nhận ra nút thắt nằm ở việc database không chịu được lượng ghi đồng thời lớn. Giải pháp của tôi là tách biệt tầng đọc/ghi. Chúng tôi sử dụng Redis ở tầng trước để kiểm tra và giữ chỗ tồn kho bằng Lua Script vì nó chạy đơn luồng và đảm bảo tính nguyên tử tuyệt đối. Các đơn hàng thành công sẽ được đẩy vào RabbitMQ để worker xử lý ghi xuống PostgreSQL theo lô. Nhờ vậy, hệ thống đã chịu tải thành công hơn 100.000 RPS mà không gặp sự cố.

Trade-off

Chấp nhận rủi ro mất dữ liệu tồn kho nhỏ nếu Redis cluster gặp sự cố sập nguồn trước khi đồng bộ xuống DB, đổi lấy hiệu năng xử lý cực cao và độ sẵn sàng của hệ thống.

Kết quả kỳ vọng

Hệ thống hoàn thành chiến dịch Flash Sale mượt mà, thời gian phản hồi API giảm từ 2000ms xuống dưới 50ms, không còn hiện tượng chết cơ sở dữ liệu.

Bài học khi trả lời phỏng vấn

Không bao giờ để trực tiếp các request ghi trực tiếp vào database quan hệ trong các kịch bản traffic bùng nổ; luôn tận dụng caching và message queue làm vùng đệm.