Prometheus 提供 PromQL 讓我們對 metrics 查詢,可以查出最近 1 小時內的請求成功率,最近 30 分鐘內的請求延遲等等的資訊,下面用範例說明。
Request Per Second
此範例查詢「每秒的請求數量」,我用 Traefik 當作範例說明。
第一步要了解哪些 metrics 是可能的候選人。比如我們要查詢「每秒的請求數量」,所以網路流量(可得出每秒流量)、應用程式是否正常運行、請求延遲等等的 metrics 都不適合。以 traefik 來說,適合的 metrics 可能是 traefik_entrypoint_requests_total, traefik_service_requests_total,參考如下:
# HELP traefik_service_requests_total How many HTTP requests processed on a service, partitioned by status code, protocol, and method.
# TYPE traefik_service_requests_total counter
traefik_service_requests_total{code="204",method="POST",protocol="http",service="serviceA-a7e1ffe6507cabd06198@kubernetescrd"} 13224
traefik_service_requests_total{code="499",method="POST",protocol="http",service="serviceA-a7e1ffe6507cabd06198@kubernetescrd"} 29
traefik_service_requests_total{code="500",method="GET",protocol="http",service="serviceA-a7e1ffe6507cabd06198@kubernetescrd"} 5
# HELP traefik_entrypoint_requests_total How many HTTP requests processed on an entrypoint, partitioned by status code, protocol, and method.
# TYPE traefik_entrypoint_requests_total counter
traefik_entrypoint_requests_total{code="200",entrypoint="metrics",method="GET",protocol="http"} 216
traefik_entrypoint_requests_total{code="200",entrypoint="traefik",method="GET",protocol="http"} 308
traefik_entrypoint_requests_total{code="204",entrypoint="websecure",method="POST",protocol="http"} 13224
traefik_entrypoint_requests_total{code="404",entrypoint="metrics",method="GET",protocol="http"} 2
traefik_entrypoint_requests_total{code="499",entrypoint="websecure",method="POST",protocol="http"} 29
traefik_entrypoint_requests_total{code="500",entrypoint="websecure",method="GET",protocol="http"} 5
註 - 這 2 個 metrics 都是 counter,counter 是一個不斷向上累計的值,當 Application 重新啟動時,counter 的值會從 0 開始。實際使用的時候並不會直接使用,通常都會丟給 Prometheus function 做一些處理,這些 function 若是發現下一個 Sample 的值比較小,就會自動調整,所以並不會因為 Application 重新啟動,造成結果不正常。
假如你用的是 NGINX, HAProxy 會有不同的 metrics。因為 Traefik 有 Entrypoint, Service 的概念,所以有不同的 metrics 可以使用,這裡我決定用 Service 的 metrics 來計算 request per second,因為我比較想要知道是每個應用程式的 request per second。
以下就是我們第一個 PromQL:
rate(traefik_service_requests_total[5m])
註 - 在 Grafana 上檢視時,將上述的「5m」替換成「$__rate_interval」後,讓 Grafana 根據時間範圍自動調整時間間隔。
這段 PromQL 的意思是用 traefik_service_requests_total 當作資料的來源,每 5 分鐘為一個區間,算出該 5 分鐘的速率,得到「每秒有幾個 request」的速率。
其實還可以更進一步的用 Prometheus Label 過濾結果,可以得到「每秒有幾個 status code = 200 ~ 399 的 request」、「每秒有幾個 status code = 400 ~ 499 的 request」、「每秒有幾個 status code = 500 ~ 599 的 request」。
rate(traefik_service_requests_total{code=~"2..|3.."}[5m])
rate(traefik_service_requests_total{code=~"4.."}[5m])
rate(traefik_service_requests_total{code=~"5.."}[5m])
當具有這樣的基礎後,就可以設定 Prometheus Alert,比如 status code = 5xx 的比例超過 5% 的時候發出 alert;當 status code = 4xx 的比例超過 7% 的時候發出 alert。
P99, P95, P90(latency)
計算 Request Latentcy 的時候,若是使用平均值,會有誤差。比如平均值是 200ms,但是有 2% 的使用者是 1500ms,這 2% 的使用者體驗到明顯的延遲,但是卻從平均值看不到,讓我們沒有發現系統有這樣的問題,這不是我們樂見的情況。
P99, P95, P90 就是用不同的角度看待 request latency,P99 的意思是 99% 的 request 在幾秒內完成;P95 的意思是 95% 的 request 在幾秒內完成;P90 的意思是 90% 的 request 在幾秒內完成。
Prometheus 提供 histogram_quantile 幫我們計算 P99, P95, P90。以下是 traefik 提供的資料:
# HELP traefik_service_request_duration_seconds How long it took to process the request on a service, partitioned by status code, protocol, and method.
# TYPE traefik_service_request_duration_seconds histogram
traefik_service_request_duration_seconds_bucket{code="204",method="POST",protocol="http",service="svcA-a7e1ffe6507cabd06198@kubernetescrd",le="0.1"} 7197
traefik_service_request_duration_seconds_bucket{code="204",method="POST",protocol="http",service="svcA-a7e1ffe6507cabd06198@kubernetescrd",le="0.3"} 19643
traefik_service_request_duration_seconds_bucket{code="204",method="POST",protocol="http",service="svcA-a7e1ffe6507cabd06198@kubernetescrd",le="1.2"} 19761
traefik_service_request_duration_seconds_bucket{code="204",method="POST",protocol="http",service="svcA-a7e1ffe6507cabd06198@kubernetescrd",le="5"} 19791
traefik_service_request_duration_seconds_bucket{code="204",method="POST",protocol="http",service="svcA-a7e1ffe6507cabd06198@kubernetescrd",le="+Inf"} 19791
traefik_service_request_duration_seconds_sum{code="204",method="POST",protocol="http",service="svcA-a7e1ffe6507cabd06198@kubernetescrd"} 2347.9746004539984
當 Traefik 啟動到現在,Request Latency 在 0.1 秒內有 7197 個;在 0.3 秒內 19643 個;在 1.2 秒內 19761 個;在 5 秒內有 19791 個。
我們可以用 Prometheus 提供的 histogram_quantile function 來計算 P99, P95, P50,參考如下:
histogram_quantile(0.99, rate(traefik_service_request_duration_seconds_bucket{code="204", service="token-ig-token@kubernetescrd"}[50m]))
histogram_quantile(0.95, rate(traefik_service_request_duration_seconds_bucket{code="204", service="token-ig-token@kubernetescrd"}[50m]))
histogram_quantile(0.50, rate(traefik_service_request_duration_seconds_bucket{code="204", service="token-ig-token@kubernetescrd"}[50m]))
這幫我們得出以下結果:
- 最近 50 分鐘內,99% 的 Request(status code = 204) 都在幾秒內完成?
- 最近 50 分鐘內,95% 的 Request(status code = 204) 都在幾秒內完成?
- 最近 50 分鐘內,50% 的 Request(status code = 204) 都在幾秒內完成?
成功率、錯誤率
成功的意思是 HTTP status code 在 200 ~ 399 之間;失敗的意思是 HTTP status code 在 400 ~ 599 之間。
註 - 我發現網路上有人用 != 500 ~ 599 認定為成功。
第一步都是找出哪個 metrics 是可能的候選人,我發現以下 metrics 有 status code,可以計算成功率、失敗率。
# HELP traefik_service_requests_total How many HTTP requests processed on a service, partitioned by status code, protocol, and method.
# TYPE traefik_service_requests_total counter
traefik_service_requests_total{code="200",method="GET",protocol="http",service="monitoring-ig-grafana-cd46c5dca3cf5026653c@kubernetescrd"} 99
traefik_service_requests_total{code="200",method="POST",protocol="http",service="monitoring-ig-grafana-cd46c5dca3cf5026653c@kubernetescrd"} 77
traefik_service_requests_total{code="204",method="POST",protocol="http",service="token-ig-token-a7e1ffe6507cabd06198@kubernetescrd"} 19791
traefik_service_requests_total{code="302",method="GET",protocol="http",service="monitoring-ig-grafana-cd46c5dca3cf5026653c@kubernetescrd"} 1
traefik_service_requests_total{code="304",method="GET",protocol="http",service="monitoring-ig-grafana-cd46c5dca3cf5026653c@kubernetescrd"} 14
traefik_service_requests_total{code="400",method="POST",protocol="http",service="monitoring-ig-grafana-cd46c5dca3cf5026653c@kubernetescrd"} 3
traefik_service_requests_total{code="499",method="POST",protocol="http",service="serviceA-a7e1ffe6507cabd06198@kubernetescrd"} 50
traefik_service_requests_total{code="500",method="GET",protocol="http",service="serviceA-a7e1ffe6507cabd06198@kubernetescrd"} 3
成功率:
sum by(serice) (traefik_service_requests_total{code=~"2.*|3.*") / sum by(serice) (traefik_service_requests_total)
錯誤率:
sum(traefik_service_requests_total{code=~"5.*|4.*") / sum(traefik_service_requests_total)