Quorum queue là câu trả lời hiện đại của RabbitMQ cho tính sẵn sàng cao, thay cho cơ chế nhân bản classic kiểu cũ. Bài này đo cái giá của nó trong điều kiện dễ chịu nhất có thể: một node duy nhất, không có nhân bản nào qua mạng. Con số ở đây là sàn — cụm thật sẽ đắt hơn.
Quorum queue từ chối những gì
| Khai báo | Kết quả |
|---|---|
durable=false |
541 INTERNAL_ERROR - transient_nonexcl_queues is deprecated |
exclusive=true |
406 - invalid property 'exclusive-owner' |
autoDelete=true |
406 - invalid property 'auto-delete' |
x-max-priority=10 |
406 - invalid arg 'x-max-priority' |
x-message-ttl=1000 |
cho phép |
x-max-length=100 |
cho phép |
Ba dòng đầu hợp lý: hàng đợi nhân bản mà lại tạm thời hoặc chết theo connection thì vô nghĩa. Dòng thứ tư mới đáng nhớ — quorum queue không có ưu tiên, nên nếu bạn dựa vào priority như phần 7 đo, chuyển sang quorum là mất tính năng đó, và phải tách thành nhiều hàng đợi.
Ngược lại, x-delivery-limit chỉ có ở quorum — phần 20 đo được classic từ chối thẳng tham số này.
Thông lượng và độ trễ
50 000 thông điệp 200 byte, persistent, có publisher confirms, trung vị 3 lượt, một node:
| Thông lượng | Độ trễ một thông điệp | |
|---|---|---|
| classic | 127 800 msg/s | p50 0,40 ms · p95 0,49 ms |
| quorum | 81 967 msg/s (64%) | p50 0,61 ms · p95 1,66 ms |
Thông lượng còn 64%. Độ trễ trung vị tăng 50%, nhưng cột p95 mới là chỗ đáng nhìn: gấp 3,4 lần. Đó là hình dạng đặc trưng của một hệ đồng thuận — phần lớn thao tác nhanh, nhưng thỉnh thoảng phải chờ một vòng ghi nhật ký Raft hoàn tất.
Bộ nhớ
100 000 thông điệp, cùng dữ liệu, đo tiến trình hàng đợi:
| Bộ nhớ tiến trình hàng đợi | messages_ram |
|
|---|---|---|
| classic | 0,41 MiB | 1 |
| quorum | 2,78 MiB | 0 |
Gấp 6,8 lần. Quorum queue giữ nhật ký Raft cùng chỉ mục của nó trong bộ nhớ, và phần trước cho thấy classic thì gần như không giữ gì. Với vài chục hàng đợi thì không sao; với vài nghìn hàng đợi quorum thì đây là con số phải nhân lên trước khi quyết định.
Vậy mua được gì
Không mất thông điệp khi một node chết. Đây là toàn bộ lý do tồn tại của nó. Thông điệp chỉ được xác nhận sau khi đa số node đã ghi, nên mất một node trong cụm ba node không mất gì cả — thứ mà cơ chế nhân bản classic kiểu cũ không bảo đảm được trong mọi tình huống.
Hành vi rõ ràng khi phân vùng mạng. Raft có luật đa số; bên thiểu số biết mình là thiểu số và ngừng phục vụ, thay vì hai bên cùng nhận thông điệp rồi phải hoà giải sau.
x-delivery-limit chạy thật. Phần 20 đo được cơ chế này bắt đúng trường hợp consumer sập — thứ không bộ đếm nào trong mã của bạn bắt được, vì mã đó đã chết.
Khi nào vẫn dùng classic
Khi chỉ có một node. Quorum trên một node là trả toàn bộ chi phí Raft mà không nhận được gì — bảng trên chính là hoá đơn đó.
Khi cần priority. Không có đường vòng nào ngoài việc tách thành nhiều hàng đợi và tự chọn.
Khi hàng đợi là tạm hoặc chết theo connection — hàng đợi trả lời trong mẫu RPC, hàng đợi theo dõi của một client. Quorum từ chối thẳng những tổ hợp cờ đó.
Khi có rất nhiều hàng đợi. Nhân 2,78 MiB với số hàng đợi trước khi quyết định.
Ngoài bốn trường hợp trên, với hệ thống nhiều node thì quorum là mặc định đúng: cái giá 36% thông lượng đổi lấy việc không mất dữ liệu khi một máy chết là món hời ở gần như mọi nơi.
Bài sau: stream — kiểu hàng đợi thứ ba, với mô hình hoàn toàn khác hai cái này.
Thử ba mươi giây
# hang doi cua ban thuoc kieu nao, va ton bao nhieu bo nho
docker exec -u rabbitmq rmq rabbitmqctl -q list_queues name type messages memory \
| sort -k4 -rn | head
Nếu thấy hàng đợi quorum trên một broker chỉ có một node, bạn đang trả giá Raft mà không nhận được tính sẵn sàng nào.