Part 10 · System Design · 10.1.07

Queues & Streams: capacity, delivery và backpressure

Queue hấp thụ burst hữu hạn và decouple thời gian giữa producer với consumer; nó không tạo thêm downstream capacity. Vì vậy thiết kế async phải đi cùng capacity model, delivery semantics, fan-out strategy và operational signals.

Mental model: queue là một lớp đệm hữu hạn. Nó giúp producer và consumer không cần chạy cùng nhịp trong ngắn hạn, nhưng nếu tốc độ đến vượt tốc độ xử lý trong thời gian dài thì backlog vẫn tiếp tục tăng.

1. Khi nào nên dùng async?

Async phù hợp cho long-running work, fan-out, công việc bị giới hạn bởi provider hoặc các workflow có thể chấp nhận eventual consistency. Thay vì giữ request mở đến khi toàn bộ công việc hoàn tất, user-facing API có thể trả trạng thái accepted kèm operation ID và expose một cơ chế để client kiểm tra status.

Tuy nhiên không phải mọi bước đều nên chuyển sang async. Các bước cần thỏa immediate invariant hoặc ví dụ như payment authorization có thể vẫn phải giữ synchronous để caller nhận kết quả quyết định ngay.

Tình huốngHướng thiết kế từ sourceLý do chính
Long-running workAsyncKhông giữ request lifecycle quá lâu.
Một event cần gửi đến nhiều nơiAsync fan-outDecouple producer khỏi từng consumer.
Provider bị rate limitAsyncCho phép xếp hàng và xử lý theo nhịp provider.
Eventual consistency chấp nhận đượcAsyncCompletion có thể xảy ra sau response ban đầu.
Immediate invariant / payment authorizationCó thể vẫn syncKết quả phải được xác nhận trong request hiện tại.

2. Capacity: queue chỉ trì hoãn failure nếu hệ thống thiếu capacity

Quan hệ cốt lõi là backlog growth = arrival rate − service rate. Khi arrival rate lớn hơn service rate, backlog tăng. Queue có thể hấp thụ burst hữu hạn, nhưng nếu arrival dài hạn vẫn vượt service thì queue chỉ trì hoãn failure, không giải quyết nguyên nhân thiếu capacity.

Khi size queue hoặc stream retention, source yêu cầu xét ít nhất các yếu tố: burst duration, payload, retentiondrain RTO. Drain RTO trả lời câu hỏi: sau một burst hoặc outage, hệ thống phải mất bao lâu để xử lý hết backlog và quay về trạng thái bình thường.

Bounded queue là guardrail. Bounded queue và load shedding giúp bảo vệ memory/disk. Nếu cho backlog tăng vô hạn, hệ thống có thể biến vấn đề capacity downstream thành sự cố storage hoặc resource exhaustion ở broker.

Capacity checklist

3. Delivery semantics, retry và ordering

Với at-least-once, consumer phải được thiết kế idempotent vì message có thể được giao lại. Ordering nên được định nghĩa theo scope thực sự cần thiết; source nêu hướng phổ biến là ordering theo entity key thay vì giả định global ordering.

Retry phải bounded và có backoff. Message không thể xử lý tiếp sau số lần thử hợp lý cần được đưa vào DLQ, và DLQ phải có owner cùng quy trình replay. Nếu chỉ tạo DLQ mà không có ai chịu trách nhiệm phân loại và replay thì lỗi chỉ bị chuyển sang một nơi khác.

Với tuyên bố exactly-once, scope guarantee phải được nói rõ. Không nên dùng cụm từ này như một guarantee mơ hồ cho toàn bộ workflow. Khi business transaction vừa ghi database vừa publish message, outbox là cơ chế source đề cập để đóng dual-write gap.

Chủ đềYêu cầu từ source
At-least-onceConsumer idempotent.
OrderingĐịnh nghĩa theo entity key khi cần.
RetryBounded retry + backoff.
Poison messageĐưa vào DLQ; có owner và replay process.
Exactly-onceScope guarantee phải rõ.
Dual writeDùng outbox để đóng gap giữa state change và publish.

4. Fan-out: push-at-write, pull-at-read và hybrid

Push-at-write làm read nhanh hơn vì kết quả đã được phân phối trước, đổi lại là write amplification. Pull-at-read đơn giản hóa write nhưng làm read đắt hơn vì phải tổng hợp khi đọc. Source khuyến nghị nghĩ theo hướng hybrid cho celebrity hoặc hot users, nơi fan-out toàn bộ ở write time có thể quá tốn kém.

Notification design còn bị chi phối bởi provider rate limitper-recipient preferences. Nghĩa là fan-out không chỉ là “nhân bản message”; hệ thống còn phải tôn trọng tốc độ provider và quyết định ai thực sự nên nhận notification.

5. Operational signals: đừng nhìn queue depth một mình

Queue depth chỉ cho biết có bao nhiêu item đang nằm chờ, nhưng thiếu context về tốc độ đến, tốc độ xử lý và độ cũ của backlog. Source yêu cầu theo dõi đồng thời các signal sau:

Điểm quan trọng: queue depth một mình không đủ context. Depth cao nhưng service rate lớn và age thấp có ý nghĩa khác hoàn toàn với depth tương tự nhưng oldest age liên tục tăng.

6. Review checklist nhanh

Official references từ source BK: Queue-Based Load Leveling · Handling Overload