欢迎光临散文网 会员登陆 & 注册

高基数问题以及如何解决?

2023-03-22 11:08 作者:Cpp程序员  | 我要投稿

背景

近期发现自己实验用的 Prometheus 性能出现瓶颈, 经常会出现如下告警:

  • PrometheusMissingRuleEvaluations

  • PrometheusRuleFailures

之后慢慢排查发现是由于 Prometheus 的某些 series 的高基数(High Cardinality)导致的. 本文是对 Prometheus 高基数问题的一次全面总结.

什么是基数(Cardinality)?

基数的基本定义是指一个给定集合中的元素的数量。

在Prometheus和可观察性的世界里,标签基数是非常重要的,因为它影响到你的监控系统的性能和资源使用。

下面这张图, 可以清晰地反应基数的重要性:

简单地说。基数 是指一个标签的总体数值的计数。在上面的例子中,标签status_code的基数是5,(即:1xx 2xx 3xx 4xx 5xx),environment的基数是2(即prod dev),而指标server_responses的总体基数是10。

多少算高基数?

一般来说:

  • 较低的基数 1:5的标签值比率,

  • 标准基数 1:80的标签值比率

  • 高基数 1:10000的标签值比率。

还是上面的例子, 如果 status_code 是详细的code, 如200 404..., 那它的基数就可能高达数百个, environment的基数再多一些, 指标server_responses的总体基数就会迅速膨胀.

高基数的典型案例

这还不够形象, 再举 2 个特别典型的例子:

  1. 有一个指标叫做: http_request_duration_seconds_bucket

    1. 小规模也会有: 100*10*400*5=2 000 000 200万个 series 💀💀💀

    2. 如果大规模, url 近乎无穷的话, 那么这个基数根本无法计算出来💥💥💥

    3. 即使规模很小, url 可能也会有 400 个 url

    4. 这里还有个特别恐怖的隐患, 就是对于大规模系统来说, 这个 url 可能是近乎于无穷!!!

    5. 它有 instance label, 对应 100 个实例;

    6. 有 le label, 对应的是不同的 buckets, 有 10 个 buckets, 如(0.002 0.004 0.008 ... =+inf)

    7. 它还有 url 这个 label, 对应的是不通的 url:

    8. 它还有 http_method 这个label, 对应有 5 个 http method

    9. 在这种情况下, 该指标的 label

  2. 再有一种情况, 将 user_id 甚至是 session_id 经纬度这种本来基数就很大, 甚至可能是无穷的参数设为 label, 那么对于 Prometheus 来说就是灾难了.💥💥💥

高基数的负面影响

当 Prometheus 有高基数的时候,就会出现各种问题:

  • 监控系统不稳定甚至崩溃

    • 仪表板加载很慢甚至加载失败

    • 监控查询很慢甚至失败

  • 计算存储资源开销巨大

  • 监控充斥着大量噪音干扰

    • SRE 团队不得不疲于应对海量的告警数据, 反而耽误 root cause 的分析定位

📝Notes:

基数 与指标系列(metrics series) 的数量相对应。所以在这篇博文中,会把 series 的数量与基数交替提及。

如何分析高基数问题?

分析高基数问题有以下方法:

  1. 使用 Prometheus UI 分析

  2. 使用 Prometheus PromQL 分析

  3. 使用 Prometheus API 分析

  4. 使用 Grafana Mimirtool 分析未使用的指标

使用 Prometheus UI 分析

从 Prometheus v2.14.0 以后, 在 UI 上直接有 Head Cardinality Stats 这个菜单. 极大方便了我们进行高基数问题的分析! 👍️👍️👍️

位于: Prometheus UI -> Status -> TSDB Status -> Head Cardinality Stats, 截图如下:

📝Notes:

以下截图的系统规模说明: 这就是个我用来做实验的环境, 只有 4 个 1c2g 的 node

从上图可以直观看到:

  1. 值最多的 Label 是 url

  2. 最多的 series 的指标有:

    1. apiserver_request_duration_seconds_bucket 45524

    2. rest_client_rate_limiter_duration_seconds_bucket 36971

    3. rest_client_request_duration_seconds_bucket 10032

  3. 内存使用量最多的 Label: url

  4. 根据 Label 键值对匹配, series 最多的键值对有: (这一项目前对我来说用处不大)

    1. endpoint=metrics 105406

    2. service=pushprox-k3s-server-client 101548

    3. job=k3s-server 101543

    4. namespace=cattle-monitoring-system 101120

    5. metrics_path=/metrics 91761

使用 Prometheus PromQL 分析

如果 Prometheus 版本低于 v2.14.0, 那就需要通过:

  • Prometheus PromQL

  • Prometheus API

来进行分析.

以下提供一些实用的 PromQL:

topk(10, count by (__name__)({__name__=~".+"}))

对应的查询结果就是上文的 series 指标最多的 Top10

知道了 Top10, 接下来可以进一步查询细节, 由于基数巨大, 如果查询 range 可能会一直失败, 所以推荐使用 instant 的方式查询细节.

如果要查询标签的维度, 可以执行如下 PromQL:

count(count by (label_name) (metric_name))

如:

count(count by (url) (apiserver_request_duration_seconds_bucket))

另外还有一些其他的 PromQL, 罗列如下:

  • sum(scrape_series_added) by (job) 通过 job Label 分析 series 增长

  • sum(scrape_samples_scraped) by (job) 通过 job Label 分析 series 总量

  • prometheus_tsdb_symbol_table_size_bytes

使用 Prometheus API 分析

因为高基数问题的特点, 所以通过 Prometheus PromQL 查询可能经常会超时或失败. 那么可以通过 Prometheus API 进行分析:

分析各个指标的 series 数量


高基数问题以及如何解决?的评论 (共 条)

分享到微博请遵守国家法律