标签加一个维度会让序列数涨多少?序列数和 Prometheus 的内存、抓取、查询耗时是什么关系?标签值不断变化(比如请求 ID)会怎样?sample_limit 和 labeldrop 能不能保护 Prometheus?这篇用 Prometheus 3.15.0 逐项量出来。
暴露的序列数 N | Prometheus 里 count() 的结果 | Prometheus 刚启动时 RSS(MB) | 抓取稳定后 RSS(MB) | 抓取耗时(ms) | /metrics 体积(MB) | sum() 查询(ms) | topk(5) 查询(ms) ---------+--------------------------+-------------------------+---------------+----------+-----------------+--------------+--------------- 1,000 | 1,000 | 91 | 76 | 2 | 0.05 | 2 | 2 10,000 | 10,000 | 87 | 112 | 8 | 0.49 | 8 | 7 100,000 | 100,000 | 88 | 357 | 50 | 4.97 | 58 | 55 300,000 | 300,000 | 92 | 890 | 137 | 15.13 | 167 | 189 序列数从一千涨到三十万,内存、抓取耗时、/metrics 体积和查询耗时都随之增长;每个序列在内存里要存标签集合、倒排索引、最近的样本,抓取一次要解析所有序列。这里的值是固定的,真实的序列还要存时间戳和不同的值,内存会更多
内存、抓取耗时、/metrics 体积和查询耗时都随序列数增长。
标签 | 序列数 | /metrics 文本大小(KB) ------------------------+-------+------------------ method × route × status | 500 | 64 再加 user_id | 29180 | 4580 5 × 20 × 5 = 500 条;加上取值很多的标签(用户 ID、请求 ID、完整 URL、IP)之后,序列数由标签值的组合决定,而不是由请求量决定——3 万次请求产生了上表里这么多条序列
序列数由标签值的组合决定,取值很多的标签(用户 ID、请求 ID)会让它和请求量一起涨。
运行时间 | head 里的序列数 | 累计创建的序列数 | 当前能查到的“活”序列(count(rq)) | Prometheus RSS(MB) -----+------------+----------+------------------------+------------------- 10 s | 5,735 | 5,735 | 1,000 | 94 20 s | 10,735 | 10,735 | 1,000 | 100 30 s | 15,735 | 15,735 | 1,000 | 109 40 s | 20,735 | 20,735 | 1,000 | 116 50 s | 25,735 | 25,735 | 1,000 | 118 60 s | 30,735 | 30,735 | 1,000 | 125 每次抓取都产生 1000 条新序列,旧的序列停止更新、被标记为过期(stale),但仍然留在 head 里直到被压缩进磁盘块并回收;所以 head 里的序列数和内存会持续增长,即使同一时刻“活”的序列数不变
标签值不断变化时旧序列留在 head 里,序列数和内存持续增长。
配置 | up | 抓到的样本数 scrape_samples_scraped | 重新打标签之后的样本数 | 实际存进去的序列数 count() | Prometheus 自己的 sample_duplicate_timestamp 计数 | 日志里含 duplicate 的行数
-----------------------------+----+-------------------------------+-------------+-------------------+----------------------------------------------+-------------------
(a)sample_limit: 5000 | 0 | 10,000 | 10,000 | 0(没有存进去) | 0 | 0
(b)labeldrop user | 1 | 10,000 | 10,000 | 6 | 0 | 0
(c)hashmod 成 6 个桶后 labeldrop | 1 | 10,000 | 10,000 | 36 | 0 | 0
sample_limit 是整个抓取的熔断:超过限制,这一次抓取整体失败(up = 0),一条都不存;labeldrop 去掉区分序列的标签会让多条序列变成同一个标签集合,只能存下一个样本(这里一万条序列并成了 count() 那一列的条数);想保留一点分布信息,可以先 hashmod 再 labeldrop
ERRORS {}sample_limit 超限整次抓取失败;labeldrop 会让序列悄悄合并;hashmod 能保留一点分布。