Gốc rễ oversell là chuỗi read–check–write không nguyên tử: hai request cùng đọc stock = 1, cùng thấy còn hàng, cùng trừ. Chốt chặn phải là một thao tác atomic.
Tầng DB (đủ cho concurrent vừa phải): trừ kho bằng một câu UPDATE có điều kiện — DB tự khóa dòng, không cần đọc trước:
UPDATE products
SET stock = stock - 1
WHERE id = $1 AND stock > 0;
-- 0 rows affected → out of stock, reject the orderHoặc SELECT ... FOR UPDATE trong transaction khi phải trừ nhiều bảng. Giới hạn: chục nghìn request tranh một dòng → lock contention, DB nghẽn.
Tầng Redis (flash sale thật sự): đưa bộ đếm suất lên Redis, chặn từ trước khi chạm DB:
1. DECR stock:{sku} — lệnh atomic, Redis đơn luồng nên trừ tuần tự chính xác; kết quả < 0 → trả "hết hàng" ngay (và INCR bù lại).
2. Ai giành được suất → đẩy message vào queue; worker tạo đơn + trừ kho DB bất đồng bộ — user thấy phản hồi nhanh, DB không ăn burst.
3. Suất giữ chỗ có TTL: không thanh toán trong N phút → hoàn suất về pool.
Lớp đi kèm bắt buộc: giới hạn 1 suất/user (SADD set người đã mua, atomic), idempotency key chống double-submit, rate limit per-user chống bot.
Lỗi hay gặp: SELECT kiểm tồn kho rồi mới UPDATE ở hai bước tách rời; trừ kho lúc thêm giỏ hàng thay vì lúc chốt suất; quên hoàn suất khi thanh toán thất bại.