Sáu bài liền của sê-ri này kết thúc bằng cùng một câu: thông điệp không khớp binding nào thì biến mất im lặng. Phần 4 đưa ra cách biết — cờ mandatory. Bài này đưa ra cách giữ lại, và đo xem hai cơ chế đó chồng lên nhau thế nào.
Khai một alternate exchange
ch.exchangeDeclare("lac", "fanout", true); // nơi hứng
ch.queueBind("thung-lac", "lac", "");
ch.exchangeDeclare("chinh", "direct", true, false,
Map.of("alternate-exchange", "lac")); // ← đúng một dòng
gửi 2 thông điệp ('moi' khớp binding, 'khong-ai-bind' không khớp)
-> kho=1 thung-lac=1
Thông điệp lạc đường không mất nữa. AE gần như luôn nên là fanout — nó phải hứng mọi thứ, mà routing key của thông điệp lạc thì tuỳ ý, nên direct hay topic sẽ để lọt tiếp.
AE và mandatory không thay thế nhau
mandatory=true + CÓ ae -> ReturnListener: IM LẶNG | thung-lac=1
mandatory=true + KHÔNG ae -> ReturnListener: 312 NO_ROUTE
mandatory ngừng báo. Dưới góc nhìn của broker, thông điệp đã được định tuyến thành công — vào AE — nên không có gì để trả về. Nếu hệ thống của bạn đang dựa vào ReturnListener để đếm số thông điệp lạc, thêm AE sẽ làm bộ đếm đó về 0 trong khi vấn đề vẫn còn nguyên.
Hai cơ chế trả lời hai câu hỏi khác nhau:
mandatory + ReturnListener |
alternate exchange | |
|---|---|---|
| Ai biết chuyện | bên gửi, ngay lập tức | bên vận hành, khi đọc hàng đợi hứng |
| Thông điệp | mất sau khi trả về | giữ lại được |
| Dùng để | xử lý ngay trong mã gửi | không mất dữ liệu, điều tra sau |
Muốn cả hai thì đừng trông vào mandatory nữa — hãy đặt cảnh báo trên độ sâu của hàng đợi hứng. Đó là tín hiệu đáng tin hơn, vì nó không phụ thuộc vào việc bên gửi có còn chạy hay không.
AE trỏ tới exchange không tồn tại
khai AE trỏ tới exchange không có -> ReturnListener: 312 NO_ROUTE
Broker không kiểm tra lúc khai báo. Gõ sai tên AE thì mọi thứ trông vẫn bình thường, và hệ thống lặng lẽ quay về hành vi cũ: thông điệp bốc hơi. Chỉ mandatory bắt được — nên trong giai đoạn dựng topology, hãy bật cả hai rồi mới tắt mandatory sau khi đã thấy hàng đợi hứng nhận được thật.
AE của AE
gửi vào c1 (c1 → c2 → c3) -> cuoi-day=1
Dây chuyền hoạt động: AE không định tuyến được thì tìm AE của chính nó. Hữu ích khi phân tầng — mỗi miền nghiệp vụ một thùng hứng, tất cả đổ về một thùng chung cuối cùng.
Không thêm AE vào exchange đã có
406 PRECONDITION_FAILED - inequivalent arg 'alternate-exchange' for exchange 'khong-ae'
in vhost '/': received the value 'lac' of type 'longstr' but current is none
Giống mọi tham số khai báo khác trong phần 6: đổi ý sau là phải xoá exchange rồi khai lại, và trong lúc đó mọi binding trỏ vào nó biến mất. Quyết định chuyện AE lúc thiết kế, không phải lúc sự cố.
Cái giá
20 000 thông điệp, publisher confirms, hâm nóng, trung vị 3 lượt:
| Thông điệp định tuyến được | Thông điệp KHÔNG định tuyến được | |
|---|---|---|
| Không có AE | 129 754 msg/s | 250 742 msg/s |
| Có AE | 130 225 msg/s | 116 277 msg/s |
Hai điều đọc ra:
Khi thông điệp đi bình thường, AE không tốn gì — 130 225 so với 129 754, chênh lệch nằm trong nhiễu. Bật nó lên không phải đánh đổi hiệu năng.
Con số 250 742 là tốc độ vứt dữ liệu. Không AE mà thông điệp lạc thì broker nhanh gấp đôi, đơn giản vì nó không phải ghi gì cả. Bật AE, tốc độ tụt còn 116 277 — vì bây giờ mỗi thông điệp lạc là một lần ghi thật vào hàng đợi hứng. Nếu bạn thấy thông lượng tụt sau khi bật AE, đó không phải AE chậm; đó là bạn vừa phát hiện ra mình đang mất bao nhiêu thông điệp.
Nên dùng thế nào
Mọi exchange nhận dữ liệu từ bên ngoài đội bạn đều nên có AE. Chi phí bằng không khi mọi thứ đúng, và nó là khác biệt giữa "điều tra được" với "dữ liệu đã biến mất tuần trước".
Đặt cảnh báo trên hàng đợi hứng, ngưỡng là bất kỳ số nào lớn hơn 0. Hàng đợi đó đúng ra phải luôn rỗng; có thông điệp trong đó nghĩa là ai đó vừa đổi routing key mà không báo.
Đừng cho consumer đọc hàng đợi hứng rồi xử lý lại tự động. Thông điệp vào đó vì không ai biết phải làm gì với nó — tự động hoá phần đó chỉ giấu lỗi đi sâu hơn một tầng.
Bài sau: dead letter exchange — nơi thông điệp đã vào hàng đợi rồi mới hỏng đi qua, và ba nguyên nhân đưa chúng tới đó.
Thử ba mươi giây
# hang doi hung cua ban co dang chua gi khong
docker exec -u rabbitmq rmq rabbitmqctl -q list_queues name messages \
| awk '$2>0'
Nếu hàng đợi hứng xuất hiện trong danh sách đó, hãy xem routing_key của những thông điệp bên trong trước khi xoá — chúng nói cho bạn biết bên gửi đang nghĩ nó đang gửi đi đâu.