2026年3月2日
Prometheus 指標類型怎麼選?從業務情境反推該用 Counter、Gauge 還是 Histogram
為什麼「選對指標類型」比「會寫 PromQL」更重要
Prometheus 的指標類型只有四種:Counter、Gauge、Histogram、Summary。但實 務上最常見的問題不是團隊不知道這四種類型的定義,而是選錯類型之後,資料已經 沒辦法回頭——Counter 存成 Gauge,你就再也算不出精確的速率;用 Gauge 存百分 比,你就再也沒辦法用不同時間窗口重新計算比率。選型是在寫程式碼埋點的當 下就決定的,出了問題往往要等到出事故、要看儀表板時才發現,那時候通常已經跑 了好幾個月的正式環境資料。
這篇文章的目標不是重講一次官方文件的定義,而是給一個更好用的思考順序:先 問這是什麼樣的業務情境,再回推該用哪種指標類型。
四種指標類型,各自解決什麼問題
Counter:只增不減的累計數
Counter 是一個只會增加的數字(服務重啟歸零除外)。它本身的絕對值通常沒有 意義,真正有用的是拿它算一段時間內的變化率。
# 每秒訂單建立速率(過去 5 分鐘平均)
rate(orders_created_total[5m])
適合的業務情境:
- 訂單建立數、付款請求數、訊息發送數——任何「累計發生了幾次」的事件
- API 請求數、依 status code 拆分的錯誤數
- Kafka 訊息生產/消費數量
命名慣例:以 _total 結尾(如 orders_created_total),讓其他人一看名
字就知道這是 Counter,要搭配 rate() 或 increase() 使用,而不是直接看原始
數值。
Gauge:可增可減的即時快照
Gauge 是任何時刻都可能上升或下降的數值,代表「現在的狀態」而不是「累計發 生過幾次」。
適合的業務情境:
- 目前線上使用者數、進行中的訂單數、待出貨物件數
- 佇列長度、Kafka Consumer Lag、連線池使用中的連線數
- Kubernetes Pod 數量、記憶體使用量、CPU 使用率
# 目前待處理付款數超過 100 筆就要警戒
payments_pending > 100
Gauge 最大的陷阱是把它拿來存「速率」或「比率」——這兩種東西都應該從 Counter 算出來,而不是另外開一個 Gauge 直接寫死當下算出來的數字(原因在下面 「常見地雷」細講)。
Histogram:把觀測值分布到預先定義的桶,換取可聚合的分位數
Histogram 用來觀察一批數值的分布狀況,例如 API 回應時間、訂單金額。它會 把每一次觀測值分配進預先定義好的桶(bucket),並且自動產生三種時間序列:
xxx_bucket{le="0.5"}:小於等於 0.5 秒的累計次數xxx_sum:所有觀測值的總和xxx_count:觀測次數
查詢時用 histogram_quantile() 在 PromQL 層級動態算出任意分位數:
# 過去 5 分鐘的 API 回應時間 p95
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))
適合的業務情境:
- API/RPC 回應時間,搭配 SLO 監控 p95/p99
- 訂單金額分布、批次任務處理時間、檔案大小分布
- 任何你會想問「95% 的使用者體驗大概落在什麼範圍」的數值
Histogram 的分位數是由 bucket 邊界估算出來的,桶切得越貼近實際分布,估 算越準;桶切得太粗,p99 可能失真。這也是選這個類型時真正要花心思的地方,不是 選不選,而是桶要怎麼切。
Summary:用戶端直接算好分位數,但無法跨實例聚合
Summary 表面上跟 Histogram 很像,也是觀察一批數值的分布,但它是在應用程式 本地直接計算好分位數再送出去,而不是送出桶再讓伺服器端算。這帶來一個致命限 制:多個副本(replica)的 Summary 分位數沒辦法正確合併——你沒辦法把三個 Pod 各自算出的 p95 平均起來得到整體的 p95,那在數學上是錯的。
什麼時候還適合用 Summary:只有在你確定「不需要跨實例聚合」、且應用程式本 地算分位數的成本可以接受的情境,例如單一長駐行程內部的自我監控。在 Kubernetes 這種天生多副本的環境下,預設應該選 Histogram,而不是 Summary。
從業務情境反推該用哪種類型
實務上更好用的思考方式是反過來問:這個業務情境的本質是「累計次數」「即時狀 態」還是「一批數值的分布」。
| 業務情境 | 該問的問題 | 對應類型 |
|---|---|---|
| 訂單建立、付款請求、訊息發送 | 這件事發生了幾次? | Counter |
| 目前待出貨訂單數、線上人數 | 現在的狀態是多少? | Gauge |
| API 回應時間、訂單金額分布 | 這批數值的分布長怎樣?p95 是多少? | Histogram |
| Kafka Consumer Lag | 現在落後多少(會漲會跌)? | Gauge |
| 付款成功率 | 一段時間內,成功/總數的比率? | 兩個 Counter 相除(見下) |
| 快取命中率 | 命中/總請求數的比率? | 帶 label 的 Counter 相除 |
| 資料庫連線池使用數 | 現在用了幾條連線? | Gauge |
常見地雷
1. 用 Gauge 存「每秒請求數」
看起來很直覺:應用程式自己算好 QPS,寫進一個 Gauge。問題是這個數字取決於你
多久算一次、用什麼視窗算,換一個監控週期結果就不一樣,而且沒辦法事後用不同
時間窗口重新計算。正確做法:用 Counter 記錄累計請求數,查詢時用
rate(requests_total[1m]),時間窗口可以在查詢當下自由調整。
2. 把比率/百分比直接存成 Gauge
「付款成功率」「快取命中率」這類比率,不要在應用程式裡自己算好百分比再存成
Gauge。正確做法是存分子與分母兩個 Counter(如
payments_success_total、payments_attempted_total),比率交給 PromQL 算:
rate(payments_success_total[5m]) / rate(payments_attempted_total[5m])
這樣你隨時可以改變時間窗口重新看比率的變化趨勢,存死的百分比 Gauge 做不到這 件事。
3. 用高基數(High Cardinality)欄位當 Label
把 user_id、order_id、email 這種幾乎唯一的值放進 Label,會讓 Prometheus
要為每一種組合維護一條獨立的時間序列,資料量瞬間爆炸,嚴重時直接拖垮
Prometheus 本身。Label 應該用來描述有限集合的維度,例如
status_code、payment_method、service_name,而不是任何形式的唯一識別
碼。
4. Histogram 的 bucket 邊界照抄範例,沒有貼合實際分布
Prometheus 官方範例的預設 bucket(如 0.005, 0.01, 0.025, 0.05, ...)是為
一般 Web API 設計的。如果你的服務正常回應時間是 200ms~2s,用預設 bucket
會讓大部分請求都落在同一個桶裡,算出來的 p95/p99 失真。應該先看一段時間的實
際分布,再決定 bucket 邊界要切在哪裡。
5. Summary 用在多副本服務上
如前面提到的,Summary 的分位數沒辦法跨實例正確聚合。在 Kubernetes 這種動輒 數個到數十個副本的環境,用 Summary 監控 API 延遲,你看到的每個 Pod 的 p95 都是「對」的,但你永遠沒辦法知道整個服務的 p95 是多少。
選型的一句話總結
先問這是「發生次數」「當下狀態」還是「一批數值的分布」;發生次數用 Counter
搭配 rate(),當下狀態用 Gauge,分布(尤其是要看分位數)用 Histogram,比率
一律用兩個 Counter 相除算出來,不要直接存成 Gauge,也盡量避免在多副本環境用
Summary。