PromQL Nâng Cao: Đừng Để “Con Số Trung Bình” Đánh Lừa Bạn

Monitoring tutorial - IT technology blog
Monitoring tutorial - IT technology blog

Nỗi đau mang tên “Số trung bình”

Hồi mới làm DevOps, mình từng hí hửng nhìn dashboard Grafana hiển thị Latency trung bình 100ms. Mọi thứ xanh mướt, mình đinh ninh hệ thống đang chạy cực mượt. Thế nhưng, group chat của team Support bỗng nổ tung: “Khách than thanh toán lag quá, xoay vòng vòng mãi không xong!”.

Lúc đó mình mới nhận ra sai lầm chết người. Con số 100ms trung bình thực chất là kết quả của 90 người dùng phản hồi cực nhanh (10ms) và 10 người khác phải đợi tận 2 giây. 10 người đó chính là những khách hàng đang nổi giận. Nếu chỉ dùng các câu lệnh up hay rate cơ bản, bạn sẽ mãi kẹt trong cái bẫy của những con số đẹp đẽ nhưng vô nghĩa.

Để tìm ra sự thật, chúng ta cần những “vũ khí” hạng nặng hơn trong PromQL. Hãy cùng mình mổ xẻ cách dùng Histogram và Subquery để nhìn thấu hệ thống.

Tại sao các truy vấn cơ bản thường bỏ lỡ lỗi?

Những câu lệnh như rate(http_requests_total[5m]) chỉ cho bạn biết tốc độ yêu cầu hiện tại. Nó hoàn toàn mù tịt về các điểm bất thường (Outliers).

Thực tế, có ba vấn đề khiến các Dashboard của Junior thường thiếu tin cậy:

  • Lạm dụng Average: Trung bình cộng làm mờ đi các đỉnh nhọn (spikes) nguy hiểm. Một server chết lâm sàng 10 giây có thể bị che lấp bởi 50 phút chạy ổn định.
  • Mất dấu vết thời gian: Bạn khó xác định được đỉnh cao nhất của tỉ lệ lỗi trong suốt 24 giờ qua nếu chỉ nhìn vào Real-time.
  • Nhiễu dữ liệu: Khi chạy hàng trăm microservices, việc sum bừa bãi khiến bạn không thể chỉ mặt đặt tên instance nào đang “đổ bệnh”.

Histogram Quantile: Đo lường trải nghiệm thực tế (P95, P99)

Đây là kỹ thuật mình ưu tiên hàng đầu để đo Latency. Thay vì tính trung bình, histogram_quantile giúp bạn biết chính xác 99% người dùng đang trải nghiệm tốc độ bao nhiêu.

Giả sử bạn có metric http_request_duration_seconds_bucket. Để tính P99 (99% yêu cầu hoàn thành trong khoảng này hoặc nhanh hơn), hãy dùng:

histogram_quantile(0.99, sum by (le) (rate(http_request_duration_seconds_bucket[5m])))

Cơ chế hoạt động rất đơn giản:

  • rate(...[5m]): Tính tốc độ tăng của các bucket trong 5 phút.
  • sum by (le): Gom dữ liệu theo nhãn le (less than or equal). Đây là nhãn sống còn của Histogram.
  • 0.99: Ngưỡng percentile bạn muốn soi.

Nếu kết quả trả về là 0.5, nghĩa là 99% user nhận phản hồi dưới 500ms. Nếu con số này vọt lên 2s trong khi trung bình vẫn là 100ms, bạn biết chắc chắn hệ thống đang có vấn đề nghiêm trọng ở một nhóm user cụ thể.

Subquery: Truy vấn lồng trong truy vấn

Bạn đã bao giờ tự hỏi: “Trong 1 giờ qua, có lúc nào tỉ lệ lỗi vượt quá 5% không?”. Nếu dùng rate thông thường, bạn chỉ thấy con số ngay lúc này. Subquery sẽ giúp bạn quét lại quá khứ như một mảng dữ liệu động.

Cú pháp cơ bản: <query> [<range>:<resolution>].

Ví dụ, tìm giá trị lỗi lớn nhất (5 phút) xảy ra trong vòng 1 giờ qua:

max_over_time(
  rate(http_requests_total{status=~"5.."}[5m])[1h:1m]
)

Trong đó, [1h:1m] nghĩa là quét dữ liệu 1 giờ trước, cứ mỗi 1 phút lấy một mẫu. Kỹ thuật này cực kỳ hữu ích để thiết lập cảnh báo (alert). Nó giúp tránh tình trạng cảnh báo nhảy ảo (flapping) khi metric chỉ nhích nhẹ lên rồi giảm ngay.

Aggregation thông minh với “without”

Thay vì dùng sum by (instance, pod, region) và phải liệt kê dài dằng dặc, hãy thử dùng without. Nó cho phép bạn loại bỏ những nhãn không cần thiết và giữ lại tất cả những thứ còn lại.

sum without (instance, pod) (rate(http_requests_total[5m]))

Câu lệnh này cộng tổng request nhưng vẫn giữ lại các label như method hay endpoint. Cách này giúp query của bạn linh hoạt hơn rất nhiều. Khi hệ thống thêm mới các label như az hay version, query vẫn tự động cập nhật mà không cần bạn sửa code.

Mẹo tối ưu Dashboard chuyên nghiệp

Để Dashboard không chỉ đẹp mà còn nhanh, mình thường áp dụng 3 quy tắc vàng:

  1. Dùng Recording Rules: Những câu lệnh như histogram_quantile cực kỳ ngốn CPU. Hãy để Prometheus tính toán trước và lưu vào một metric mới thay vì bắt nó tính lại mỗi khi bạn F5 trình duyệt.
  2. Combo P50 – P95 – P99: Luôn hiển thị ba con số này cạnh nhau. Khoảng cách giữa chúng sẽ tiết lộ độ ổn định của hệ thống. Nếu chúng tách xa nhau, hệ thống đang bị nghẽn cổ chai cục bộ.
  3. Kiểm soát Cardinality: Đừng bao giờ gán nhãn có giá trị thay đổi liên tục như user_id. Việc này sẽ khiến Prometheus phình to dữ liệu và sập nguồn trong chốc lát.

Làm chủ PromQL là bước tiến lớn từ một người chỉ biết “xem biểu đồ” thành một kỹ sư có khả năng “đọc vị” hệ thống. Từ khi áp dụng P99 và Subquery, mình không còn phải thức đêm SSH vào server để đoán mò nữa. Mọi thứ giờ đây đều hiển thị rõ ràng qua những con số biết nói.

Share: