Với hệ thống phân tán thì sẽ không có 1 giải pháp nào là tối ưu mà sẽ tùy vào từng trường hợp mà ta chọn / phối hợp các giải pháp sao cho tối ưu nhất. Vài ý tưởng đơn giản có thể để trả lời phỏng vấn:
1. Atomic update:
Nói chung luôn dùng atomic update nếu có thể, đây luôn là một giải pháp đơn giản, tối ưu và tiết kiệm. Ta có thể setup một sử dụng một cụm Redis cho việc lưu trữ / xử lý stock của đơn hàng. Thêm một lua script để xử lý update:
Mã:
let val = tonumber(redis.call(get, KEYS[1]))
if (val <= 0) return -1
return redis.call("incr", KEYS[1], -1)
Dù là LUA script thì redis vẫn rất rất nhanh so với các DB khác, Redis là single-threaded nên luôn đảm bảo không bao giờ có xung đột (kể cả trong hệ thống clustering). Bất lợi là việc tách logic xử lý stock ra một DB riêng sẽ kéo theo nhiều khó khăn khác về technical, redis cũng có rủi ro trong việc mất mát dữ liệu (dù rất rất hiếm).
2. Distributed lock:
Vẫn là lock, nhưng trong hệ thống phân tán thì cao cấp hơn. Implement bằng
Redis luôn cho dễ.
Lợi điểm là khả thi với hầu như mọi tình huống, khi mà không thể dùng atomic update thì có thể switch ngay qua phương án này.
Bất lợi là performance kém. Nhiều trường hợp biên cần xử lý cho bài toán global locking. Vì tự xử lý nên dễ gặp deadlock.
3. Queueing:
Việc xử lý các tác vụ collision sẽ được thực hiện bằng worker và xử lý single threaded nhằm tránh đụng độ. Ta có thể sử dụng các MQ đơn giản như RabbitMQ hoặc Redis luôn. Để scalable ta có thể hash task theo collision key và scale số lượng worker tương ứng
Lợi điểm là có thể implement các logic phức tạp, scalable, ít điều kiện biên.
Bất lợi là luồng xử lý bị băm nhỏ ra thành các giai đoạn, khó quản lý toàn luồn (có thể dùng các tool khác để quản lý flow - nhưng nằm ngoài phạm vi câu hỏi). Ngoài ra đôi khi hệ thống không sẵn sàng để phân tách như vậy, chi phí thực hiện lớn.