Đọc mực nước trong một bể chứa gần như không cho biết bể có khoẻ không. Bể đầy 30 000 lít đang chảy ra đều và được bơm bù là hoàn toàn bình thường; bể đầy 30 000 lít mà ống thoát tắc là một cơn ngập sắp xảy ra — cùng một mực nước. Cái quyết định là dòng chảy (vào so với ra), không phải cái mức tại một khoảnh khắc. Cảnh báo phổ biến nhất trên RabbitMQ lại chính là "hàng đợi vượt N thông điệp" — một phép đo mực nước. Bài này dựng hai tình huống có cùng độ sâu — một bình thường, một hỏng nặng — để xem chỉ số đó nói được gì.
Bật Prometheus
docker exec rmq rabbitmq-plugins enable rabbitmq_prometheus
curl -s localhost:15692/metrics
191 tên chỉ số khác nhau. Bài này không liệt kê hết; nó đi tìm những cái thật sự phân biệt được "đang bận" với "đang chết".
Hai tình huống, cùng một hàng đợi 30 000 thông điệp
Cả hai đều có đúng một consumer, prefetch 100. Khác nhau ở chỗ consumer thứ hai nhận thông điệp rồi không bao giờ ack — đúng kiểu một luồng bị treo ở lời gọi HTTP không có phép chờ.
| A. đang rút bình thường | B. consumer kẹt cứng | |
|---|---|---|
messages_ready |
26 140 | 29 900 |
messages_unacked |
100 | 100 |
consumers |
1 | 1 |
| tốc độ ack | 795/s | 0/s |
Ba dòng đầu gần như không phân biệt được: cùng số consumer, cùng số unacked, và độ sâu thì chỉ khác nhau ở chỗ một bên đang giảm dần — thứ mà một lần đọc không thấy được.
Chỉ số quyết định là tốc độ ack
Dòng cuối bảng là thứ tách được hai tình huống, và nó tách rất dứt khoát: 795 so với 0.
Nói rộng hơn, thứ đáng theo dõi là quan hệ giữa tốc độ vào và tốc độ ra:
- Tốc độ ack ≈ tốc độ publish → hệ thống theo kịp, độ sâu bao nhiêu cũng không sao.
- Tốc độ ack < tốc độ publish → độ sâu đang tăng; cảnh báo khi xu hướng kéo dài, không phải khi vượt ngưỡng.
- Tốc độ ack = 0 mà có consumer → đây mới là cảnh báo cần đánh thức người trực.
Trường hợp cuối là thứ mà cảnh báo theo ngưỡng độ sâu luôn báo muộn: nó phải chờ hàng đợi dồn tới ngưỡng, trong khi tốc độ ack đã về 0 từ giây đầu tiên.
Một chỉ số tôi không dùng
consumer_utilisation hay được nhắc tới, nên tôi đo luôn. Kết quả:
A. đang rút bình thường : consumer_utilisation = 0,05
B. consumer kẹt cứng : consumer_utilisation = 0,42
Ngược hẳn với điều cái tên gợi ra. Tôi không có giải thích chắc chắn cho con số này, nên bài không đưa ra lời khuyên nào dựa trên nó — và cũng khuyên bạn đừng đặt cảnh báo lên một chỉ số mà mình chưa giải thích được. Tốc độ ack thì không có chỗ nào để hiểu nhầm.
Sáu chỉ số đáng đặt cảnh báo
| Chỉ số | Cảnh báo khi | Vì sao |
|---|---|---|
rabbitmq_global_messages_acknowledged_total (tốc độ) |
về 0 mà consumers > 0 |
Bảng đầu bài |
rabbitmq_queue_messages_unacked |
dừng ở đúng bằng prefetch và không đổi | Consumer treo, không phải bận |
rabbitmq_consumers |
= 0 trên hàng đợi công việc | Phần 32: hàng đợi bị bỏ quên ăn đĩa |
rabbitmq_global_messages_dead_lettered_*_total |
tăng | Bốn hậu tố rejected / expired / maxlen / delivery_limit khớp đúng bốn nguyên nhân ở phần 14 |
rabbitmq_disk_space_available_bytes |
dưới ngưỡng | Phần 32: đĩa đầy làm broker chặn mọi producer |
rabbitmq_alarms_free_disk_space_watermark |
= 1 | Báo động đã kích hoạt — lúc này producer đã bị chặn rồi |
Chi tiết đáng khen của bản Prometheus: nhóm dead_lettered tách theo nguyên nhân. Cảnh báo trên maxlen nghĩa là hàng đợi đang tràn; trên rejected nghĩa là mã của bạn đang ném ngoại lệ; trên expired nghĩa là TTL đang cắt thông điệp. Ba việc khác nhau, ba cách chữa khác nhau, và trước đây phải đi bới x-death mới biết.
Còn độ sâu thì sao
Vẫn theo dõi, nhưng như một xu hướng, không phải một ngưỡng. Và với stream thì bỏ hẳn: phần 35 đo được rằng stream luôn báo messages = 0 dù đang giữ đủ dữ liệu.
Kiểm nhanh xem consumer của mình có đang treo không, chạy hai lần cách nhau mười giây:
curl -s localhost:15692/metrics | grep -E "^rabbitmq_(global_messages_acknowledged_total|queue_messages_unacked|consumers|disk_space_available_bytes) "
Nếu acknowledged_total không đổi trong khi consumers khác 0, bạn có một consumer đang treo — và độ sâu hàng đợi lúc này còn chưa kịp nhúc nhích.
Mẫu số chung
Một cái mức (ảnh chụp, gauge) gần như không nói gì về sức khoẻ; một cái tốc độ thì có. Câu hỏi đúng không bao giờ là "hàng đợi/đĩa/bộ nhớ đầy bao nhiêu?" mà là "tốc độ ra có theo kịp tốc độ vào không?" — hai ảnh chụp giống hệt nhau (sâu 30 000, một consumer, 100 unacked) đã giấu một hệ khoẻ và một hệ đang chết, chỉ tốc độ ack (795 so với 0) tách được. Hãy cảnh báo trên đạo hàm, đừng trên giá trị: một cái đĩa đầy thêm 1%/ngày là bình thường, 10%/phút là sự cố — mà ngay lúc này chúng đọc ra cùng một số. Phiên bản sắc nhất — tốc-độ-ra = 0 mà vẫn có thợ — nổ ngay khoảnh khắc sự cố bắt đầu, trong khi ngưỡng độ sâu phải đợi hàng dồn lại mới biết. Đây là bản năng golden-signals: canh dòng, đừng canh khối.
Điều thứ hai: đừng cảnh báo trên — cũng đừng suy luận từ — một chỉ số mình không giải thích được. consumer_utilisation đo ra ngược hẳn cái tên nó gợi, nên nước đi trung thực là từ chối dựng luật lên nó: một tín hiệu bạn không hiểu còn tệ hơn không có, vì nó dụ bạn ra một quyết định sai đầy tự tin. Hãy ưu tiên cái chỉ số không có chỗ hiểu nhầm (tốc độ ack chỉ có một nghĩa). Và mặt còn lại của một chỉ số tốt là nó mang theo cái vì sao: bộ đếm dead-letter tách theo nguyên nhân (rejected/expired/maxlen/ delivery_limit) biến "có thứ đang chết" thành "đây là bệnh nào trong ba, và cách chữa" — không ai phải đi khai quật x-death nữa. Một con số chỉ hữu ích ngang với khả năng bạn nói chính xác nó nghĩa là gì.
Bài sau: gom toàn bộ phép đo của sê-ri thành một bảng — thứ gì thật sự đổi được hiệu năng, và thứ gì ai cũng khuyên mà đo ra không khác gì.