[{"data":1,"prerenderedAt":487},["ShallowReactive",2],{"article-\u002Farticles\u002Fprometheus-metric-types":3},{"id":4,"title":5,"body":6,"date":473,"description":67,"excerpt":474,"extension":475,"meta":476,"navigation":477,"path":478,"seo":479,"stem":480,"tags":481,"__hash__":486},"articles\u002Farticles\u002Fprometheus-metric-types.md","Prometheus 指標類型怎麼選？從業務情境反推該用 Counter、Gauge 還是 Histogram",{"type":7,"value":8,"toc":453},"minimark",[9,14,31,38,42,47,57,68,74,87,109,113,120,124,135,141,148,152,159,179,186,192,196,207,217,221,232,241,244,247,345,348,352,363,367,382,388,391,395,422,426,433,437,444,447],[10,11,13],"h2",{"id":12},"為什麼選對指標類型比會寫-promql更重要","為什麼「選對指標類型」比「會寫 PromQL」更重要",[15,16,17,18,22,23,26,27,30],"p",{},"Prometheus 的指標類型只有四種：",[19,20,21],"strong",{},"Counter、Gauge、Histogram、Summary","。但實\n務上最常見的問題不是團隊不知道這四種類型的定義，而是選錯類型之後，資料",[19,24,25],{},"已經\n沒辦法回頭","——Counter 存成 Gauge，你就再也算不出精確的速率；用 Gauge 存百分\n比，你就再也沒辦法用不同時間窗口重新計算比率。選型是在",[19,28,29],{},"寫程式碼埋點的當\n下","就決定的，出了問題往往要等到出事故、要看儀表板時才發現，那時候通常已經跑\n了好幾個月的正式環境資料。",[15,32,33,34,37],{},"這篇文章的目標不是重講一次官方文件的定義，而是給一個更好用的思考順序：",[19,35,36],{},"先\n問這是什麼樣的業務情境，再回推該用哪種指標類型","。",[10,39,41],{"id":40},"四種指標類型各自解決什麼問題","四種指標類型，各自解決什麼問題",[43,44,46],"h3",{"id":45},"counter只增不減的累計數","Counter：只增不減的累計數",[15,48,49,50,53,54,37],{},"Counter 是一個",[19,51,52],{},"只會增加","的數字（服務重啟歸零除外）。它本身的絕對值通常沒有\n意義，真正有用的是",[19,55,56],{},"拿它算一段時間內的變化率",[58,59,64],"pre",{"className":60,"code":62,"language":63},[61],"language-text","# 每秒訂單建立速率（過去 5 分鐘平均）\nrate(orders_created_total[5m])\n","text",[65,66,62],"code",{"__ignoreMap":67},"",[15,69,70,73],{},[19,71,72],{},"適合的業務情境","：",[75,76,77,81,84],"ul",{},[78,79,80],"li",{},"訂單建立數、付款請求數、訊息發送數——任何「累計發生了幾次」的事件",[78,82,83],{},"API 請求數、依 status code 拆分的錯誤數",[78,85,86],{},"Kafka 訊息生產\u002F消費數量",[15,88,89,92,93,96,97,100,101,104,105,108],{},[19,90,91],{},"命名慣例","：以 ",[65,94,95],{},"_total"," 結尾（如 ",[65,98,99],{},"orders_created_total","），讓其他人一看名\n字就知道這是 Counter，要搭配 ",[65,102,103],{},"rate()"," 或 ",[65,106,107],{},"increase()"," 使用，而不是直接看原始\n數值。",[43,110,112],{"id":111},"gauge可增可減的即時快照","Gauge：可增可減的即時快照",[15,114,115,116,119],{},"Gauge 是",[19,117,118],{},"任何時刻都可能上升或下降","的數值，代表「現在的狀態」而不是「累計發\n生過幾次」。",[15,121,122,73],{},[19,123,72],{},[75,125,126,129,132],{},[78,127,128],{},"目前線上使用者數、進行中的訂單數、待出貨物件數",[78,130,131],{},"佇列長度、Kafka Consumer Lag、連線池使用中的連線數",[78,133,134],{},"Kubernetes Pod 數量、記憶體使用量、CPU 使用率",[58,136,139],{"className":137,"code":138,"language":63},[61],"# 目前待處理付款數超過 100 筆就要警戒\npayments_pending > 100\n",[65,140,138],{"__ignoreMap":67},[15,142,143,144,147],{},"Gauge 最大的陷阱是",[19,145,146],{},"把它拿來存「速率」或「比率」","——這兩種東西都應該從\nCounter 算出來，而不是另外開一個 Gauge 直接寫死當下算出來的數字（原因在下面\n「常見地雷」細講）。",[43,149,151],{"id":150},"histogram把觀測值分布到預先定義的桶換取可聚合的分位數","Histogram：把觀測值分布到預先定義的桶，換取可聚合的分位數",[15,153,154,155,158],{},"Histogram 用來觀察一批數值的",[19,156,157],{},"分布狀況","，例如 API 回應時間、訂單金額。它會\n把每一次觀測值分配進預先定義好的桶（bucket），並且自動產生三種時間序列：",[75,160,161,167,173],{},[78,162,163,166],{},[65,164,165],{},"xxx_bucket{le=\"0.5\"}","：小於等於 0.5 秒的累計次數",[78,168,169,172],{},[65,170,171],{},"xxx_sum","：所有觀測值的總和",[78,174,175,178],{},[65,176,177],{},"xxx_count","：觀測次數",[15,180,181,182,185],{},"查詢時用 ",[65,183,184],{},"histogram_quantile()"," 在 PromQL 層級動態算出任意分位數：",[58,187,190],{"className":188,"code":189,"language":63},[61],"# 過去 5 分鐘的 API 回應時間 p95\nhistogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))\n",[65,191,189],{"__ignoreMap":67},[15,193,194,73],{},[19,195,72],{},[75,197,198,201,204],{},[78,199,200],{},"API／RPC 回應時間，搭配 SLO 監控 p95／p99",[78,202,203],{},"訂單金額分布、批次任務處理時間、檔案大小分布",[78,205,206],{},"任何你會想問「95% 的使用者體驗大概落在什麼範圍」的數值",[15,208,209,210,213,214,37],{},"Histogram 的分位數是",[19,211,212],{},"由 bucket 邊界估算出來的","，桶切得越貼近實際分布，估\n算越準；桶切得太粗，p99 可能失真。這也是選這個類型時真正要花心思的地方，不是\n選不選，而是",[19,215,216],{},"桶要怎麼切",[43,218,220],{"id":219},"summary用戶端直接算好分位數但無法跨實例聚合","Summary：用戶端直接算好分位數，但無法跨實例聚合",[15,222,223,224,227,228,231],{},"Summary 表面上跟 Histogram 很像，也是觀察一批數值的分布，但它是在",[19,225,226],{},"應用程式\n本地","直接計算好分位數再送出去，而不是送出桶再讓伺服器端算。這帶來一個致命限\n制：",[19,229,230],{},"多個副本（replica）的 Summary 分位數沒辦法正確合併","——你沒辦法把三個\nPod 各自算出的 p95 平均起來得到整體的 p95，那在數學上是錯的。",[15,233,234,237,238,37],{},[19,235,236],{},"什麼時候還適合用 Summary","：只有在你確定「不需要跨實例聚合」、且應用程式本\n地算分位數的成本可以接受的情境，例如單一長駐行程內部的自我監控。在 Kubernetes\n這種天生多副本的環境下，",[19,239,240],{},"預設應該選 Histogram，而不是 Summary",[10,242,243],{"id":243},"從業務情境反推該用哪種類型",[15,245,246],{},"實務上更好用的思考方式是反過來問：這個業務情境的本質是「累計次數」「即時狀\n態」還是「一批數值的分布」。",[248,249,250,266],"table",{},[251,252,253],"thead",{},[254,255,256,260,263],"tr",{},[257,258,259],"th",{},"業務情境",[257,261,262],{},"該問的問題",[257,264,265],{},"對應類型",[267,268,269,281,292,303,313,324,335],"tbody",{},[254,270,271,275,278],{},[272,273,274],"td",{},"訂單建立、付款請求、訊息發送",[272,276,277],{},"這件事發生了幾次？",[272,279,280],{},"Counter",[254,282,283,286,289],{},[272,284,285],{},"目前待出貨訂單數、線上人數",[272,287,288],{},"現在的狀態是多少？",[272,290,291],{},"Gauge",[254,293,294,297,300],{},[272,295,296],{},"API 回應時間、訂單金額分布",[272,298,299],{},"這批數值的分布長怎樣？p95 是多少？",[272,301,302],{},"Histogram",[254,304,305,308,311],{},[272,306,307],{},"Kafka Consumer Lag",[272,309,310],{},"現在落後多少（會漲會跌）？",[272,312,291],{},[254,314,315,318,321],{},[272,316,317],{},"付款成功率",[272,319,320],{},"一段時間內，成功／總數的比率？",[272,322,323],{},"兩個 Counter 相除（見下）",[254,325,326,329,332],{},[272,327,328],{},"快取命中率",[272,330,331],{},"命中／總請求數的比率？",[272,333,334],{},"帶 label 的 Counter 相除",[254,336,337,340,343],{},[272,338,339],{},"資料庫連線池使用數",[272,341,342],{},"現在用了幾條連線？",[272,344,291],{},[10,346,347],{"id":347},"常見地雷",[43,349,351],{"id":350},"_1-用-gauge-存每秒請求數","1. 用 Gauge 存「每秒請求數」",[15,353,354,355,358,359,362],{},"看起來很直覺：應用程式自己算好 QPS，寫進一個 Gauge。問題是這個數字",[19,356,357],{},"取決於你\n多久算一次、用什麼視窗算","，換一個監控週期結果就不一樣，而且沒辦法事後用不同\n時間窗口重新計算。正確做法：用 Counter 記錄累計請求數，查詢時用\n",[65,360,361],{},"rate(requests_total[1m])","，時間窗口可以在查詢當下自由調整。",[43,364,366],{"id":365},"_2-把比率百分比直接存成-gauge","2. 把比率／百分比直接存成 Gauge",[15,368,369,370,373,374,377,378,381],{},"「付款成功率」「快取命中率」這類比率，不要在應用程式裡自己算好百分比再存成\nGauge。正確做法是存",[19,371,372],{},"分子與分母兩個 Counter","（如\n",[65,375,376],{},"payments_success_total","、",[65,379,380],{},"payments_attempted_total","），比率交給 PromQL 算：",[58,383,386],{"className":384,"code":385,"language":63},[61],"rate(payments_success_total[5m]) \u002F rate(payments_attempted_total[5m])\n",[65,387,385],{"__ignoreMap":67},[15,389,390],{},"這樣你隨時可以改變時間窗口重新看比率的變化趨勢，存死的百分比 Gauge 做不到這\n件事。",[43,392,394],{"id":393},"_3-用高基數high-cardinality欄位當-label","3. 用高基數（High Cardinality）欄位當 Label",[15,396,397,398,377,401,377,404,407,408,411,412,377,415,377,418,421],{},"把 ",[65,399,400],{},"user_id",[65,402,403],{},"order_id",[65,405,406],{},"email"," 這種幾乎唯一的值放進 Label，會讓 Prometheus\n要為每一種組合維護一條獨立的時間序列，資料量瞬間爆炸，嚴重時直接拖垮\nPrometheus 本身。Label 應該用來描述",[19,409,410],{},"有限集合","的維度，例如\n",[65,413,414],{},"status_code",[65,416,417],{},"payment_method",[65,419,420],{},"service_name","，而不是任何形式的唯一識別\n碼。",[43,423,425],{"id":424},"_4-histogram-的-bucket-邊界照抄範例沒有貼合實際分布","4. Histogram 的 bucket 邊界照抄範例，沒有貼合實際分布",[15,427,428,429,432],{},"Prometheus 官方範例的預設 bucket（如 ",[65,430,431],{},"0.005, 0.01, 0.025, 0.05, ...","）是為\n一般 Web API 設計的。如果你的服務正常回應時間是 200ms～2s，用預設 bucket\n會讓大部分請求都落在同一個桶裡，算出來的 p95／p99 失真。應該先看一段時間的實\n際分布，再決定 bucket 邊界要切在哪裡。",[43,434,436],{"id":435},"_5-summary-用在多副本服務上","5. Summary 用在多副本服務上",[15,438,439,440,443],{},"如前面提到的，Summary 的分位數沒辦法跨實例正確聚合。在 Kubernetes 這種動輒\n數個到數十個副本的環境，用 Summary 監控 API 延遲，你看到的每個 Pod 的 p95\n都是「對」的，但你永遠沒辦法知道",[19,441,442],{},"整個服務","的 p95 是多少。",[10,445,446],{"id":446},"選型的一句話總結",[15,448,449,450,452],{},"先問這是「發生次數」「當下狀態」還是「一批數值的分布」；發生次數用 Counter\n搭配 ",[65,451,103],{},"，當下狀態用 Gauge，分布（尤其是要看分位數）用 Histogram，比率\n一律用兩個 Counter 相除算出來，不要直接存成 Gauge，也盡量避免在多副本環境用\nSummary。",{"title":67,"searchDepth":454,"depth":454,"links":455},2,[456,457,464,465,472],{"id":12,"depth":454,"text":13},{"id":40,"depth":454,"text":41,"children":458},[459,461,462,463],{"id":45,"depth":460,"text":46},3,{"id":111,"depth":460,"text":112},{"id":150,"depth":460,"text":151},{"id":219,"depth":460,"text":220},{"id":243,"depth":454,"text":243},{"id":347,"depth":454,"text":347,"children":466},[467,468,469,470,471],{"id":350,"depth":460,"text":351},{"id":365,"depth":460,"text":366},{"id":393,"depth":460,"text":394},{"id":424,"depth":460,"text":425},{"id":435,"depth":460,"text":436},{"id":446,"depth":454,"text":446},"2026-03-02",null,"md",{},true,"\u002Farticles\u002Fprometheus-metric-types",{"title":5,"description":67},"articles\u002Fprometheus-metric-types",[482,483,484,485],"Prometheus","Observability","SRE","指標設計","AWhUZMMxMUtfkWKUHMRc70Sy9uwbFaUspgEnEuYySSA",1792959150197]