高基數(shù)問(wèn)題以及如何解決?
背景
近期發(fā)現(xiàn)自己實(shí)驗(yàn)用的 Prometheus 性能出現(xiàn)瓶頸, 經(jīng)常會(huì)出現(xiàn)如下告警:
PrometheusMissingRuleEvaluations
PrometheusRuleFailures
之后慢慢排查發(fā)現(xiàn)是由于 Prometheus 的某些 series 的高基數(shù)(High Cardinality)導(dǎo)致的. 本文是對(duì) Prometheus 高基數(shù)問(wèn)題的一次全面總結(jié).
什么是基數(shù)(Cardinality)?
基數(shù)的基本定義是指一個(gè)給定集合中的元素的數(shù)量。
在Prometheus和可觀察性的世界里,標(biāo)簽基數(shù)是非常重要的,因?yàn)樗绊懙侥愕谋O(jiān)控系統(tǒng)的性能和資源使用。
下面這張圖, 可以清晰地反應(yīng)基數(shù)的重要性:

簡(jiǎn)單地說(shuō)?;鶖?shù) 是指一個(gè)標(biāo)簽的總體數(shù)值的計(jì)數(shù)。在上面的例子中,標(biāo)簽status_code
的基數(shù)是5,(即:1xx
?2xx
?3xx
?4xx
?5xx
),environment
的基數(shù)是2(即prod
?dev
),而指標(biāo)server_responses
的總體基數(shù)是10。
多少算高基數(shù)?
一般來(lái)說(shuō):
較低的基數(shù) 1:5的標(biāo)簽值比率,
標(biāo)準(zhǔn)基數(shù) 1:80的標(biāo)簽值比率
高基數(shù) 1:10000的標(biāo)簽值比率。
還是上面的例子, 如果?status_code
?是詳細(xì)的code, 如200
?404
..., 那它的基數(shù)就可能高達(dá)數(shù)百個(gè),?environment
的基數(shù)再多一些, 指標(biāo)server_responses
的總體基數(shù)就會(huì)迅速膨脹.
高基數(shù)的典型案例
這還不夠形象, 再舉 2 個(gè)特別典型的例子:
有一個(gè)指標(biāo)叫做:?
http_request_duration_seconds_bucket
小規(guī)模也會(huì)有:?
100*10*400*5=2 000 000
?200萬(wàn)個(gè) series ??????如果大規(guī)模, url 近乎無(wú)窮的話, 那么這個(gè)基數(shù)根本無(wú)法計(jì)算出來(lái)??????
即使規(guī)模很小, url 可能也會(huì)有 400 個(gè) url
這里還有個(gè)特別恐怖的隱患, 就是對(duì)于大規(guī)模系統(tǒng)來(lái)說(shuō), 這個(gè) url 可能是近乎于無(wú)窮!!!
它有?
instance
?label, 對(duì)應(yīng) 100 個(gè)實(shí)例;有?
le
?label, 對(duì)應(yīng)的是不同的 buckets, 有 10 個(gè) buckets, 如(0.002
?0.004
?0.008
?...?=+inf
)它還有?
url
?這個(gè) label, 對(duì)應(yīng)的是不通的 url:它還有?
http_method
?這個(gè)label, 對(duì)應(yīng)有 5 個(gè) http method在這種情況下, 該指標(biāo)的 label
再有一種情況, 將?
user_id
?甚至是?session_id
?經(jīng)緯度
這種本來(lái)基數(shù)就很大, 甚至可能是無(wú)窮的參數(shù)設(shè)為 label, 那么對(duì)于 Prometheus 來(lái)說(shuō)就是災(zāi)難了.??????
高基數(shù)的負(fù)面影響
當(dāng) Prometheus 有高基數(shù)的時(shí)候,就會(huì)出現(xiàn)各種問(wèn)題:
監(jiān)控系統(tǒng)不穩(wěn)定甚至崩潰
儀表板加載很慢甚至加載失敗
監(jiān)控查詢很慢甚至失敗
計(jì)算存儲(chǔ)資源開(kāi)銷巨大
監(jiān)控充斥著大量噪音干擾
SRE 團(tuán)隊(duì)不得不疲于應(yīng)對(duì)海量的告警數(shù)據(jù), 反而耽誤 root cause 的分析定位
??Notes:
基數(shù) 與指標(biāo)系列(metrics series) 的數(shù)量相對(duì)應(yīng)。所以在這篇博文中,會(huì)把 series 的數(shù)量與基數(shù)交替提及。
如何分析高基數(shù)問(wèn)題?
分析高基數(shù)問(wèn)題有以下方法:
使用 Prometheus UI 分析
使用 Prometheus PromQL 分析
使用 Prometheus API 分析
使用 Grafana Mimirtool 分析未使用的指標(biāo)
使用 Prometheus UI 分析
從 Prometheus?v2.14.0?以后, 在 UI 上直接有?Head Cardinality Stats?這個(gè)菜單. 極大方便了我們進(jìn)行高基數(shù)問(wèn)題的分析! ?????????
位于: Prometheus UI -> Status -> TSDB Status -> Head Cardinality Stats, 截圖如下:
??Notes:
以下截圖的系統(tǒng)規(guī)模說(shuō)明: 這就是個(gè)我用來(lái)做實(shí)驗(yàn)的環(huán)境, 只有 4 個(gè) 1c2g 的 node


從上圖可以直觀看到:
值最多的 Label 是?
url
最多的 series 的指標(biāo)有:
apiserver_request_duration_seconds_bucket
?45524rest_client_rate_limiter_duration_seconds_bucket
?36971rest_client_request_duration_seconds_bucket
?10032內(nèi)存使用量最多的 Label:?
url
根據(jù) Label 鍵值對(duì)匹配, series 最多的鍵值對(duì)有: (這一項(xiàng)目前對(duì)我來(lái)說(shuō)用處不大)
endpoint=metrics
?105406service=pushprox-k3s-server-client
?101548job=k3s-server
?101543namespace=cattle-monitoring-system
?101120metrics_path=/metrics
?91761
使用 Prometheus PromQL 分析
如果 Prometheus 版本低于?v2.14.0, 那就需要通過(guò):
Prometheus PromQL
Prometheus API
來(lái)進(jìn)行分析.
以下提供一些實(shí)用的 PromQL:
topk(10, count by (__name__)({__name__=~".+"}))
對(duì)應(yīng)的查詢結(jié)果就是上文的?series 指標(biāo)最多的 Top10
知道了 Top10, 接下來(lái)可以進(jìn)一步查詢細(xì)節(jié), 由于基數(shù)巨大, 如果查詢 range 可能會(huì)一直失敗, 所以推薦使用?instant
?的方式查詢細(xì)節(jié).
如果要查詢標(biāo)簽的維度, 可以執(zhí)行如下 PromQL:
count(count by (label_name) (metric_name))
如:
count(count by (url) (apiserver_request_duration_seconds_bucket))
另外還有一些其他的 PromQL, 羅列如下:
sum(scrape_series_added) by (job)
?通過(guò) job Label 分析 series 增長(zhǎng)sum(scrape_samples_scraped) by (job)
?通過(guò) job Label 分析 series 總量prometheus_tsdb_symbol_table_size_bytes
使用 Prometheus API 分析
因?yàn)楦呋鶖?shù)問(wèn)題的特點(diǎn), 所以通過(guò) Prometheus PromQL 查詢可能經(jīng)常會(huì)超時(shí)或失敗. 那么可以通過(guò) Prometheus API 進(jìn)行分析: