写在最前
prometheus 断定高基数的三种办法
- prometheus tsdb 的统计接口
- prometheus 能够依据 query_log 中的 queryPreparationTime 来定位
- prometheus 通过 count by 统计
什么是高基数 high-cardinality
基数狭义上是指汇合中值的数量
在数据库畛域,基数是指数据库的特定列或字段中蕴含的惟一值的数量。
工夫序列数据集的基数通常由每个独自的索引列的基数的叉积定义
高基数示例:工业物联网
- 设想一下一个 IoT 场景,其中某个采石场中有大量的重型设施在开采岩石,破碎岩石和分选岩石。
- 假如有 10,000 件设施,每个设施带有 100 个传感器,运行 10 个不同的固件版本,散布在 100 个站点中:
timestamp | temper | mem_f | equipm | senso | firmwar | sit | (lat,long)
| ature | ree | ent_id | r_id | e_version | e_id |
--------------------+-------+--------+-------------------+------+-----------
2019-04-04 | 85.2 | 10.2 | 1 | 98 | 1.0 | 4 | (x,y)
09:00:00 | | | | | | |
2019-04-04 | 68.8 | 16.0 | 72 | 12 | 1.1 | 20 | (x1,y1)
09:00:00 | | | | | | |
2019-04-04 | 100.0 | 0.0 | 34 | 58 | 2.1 | 55 | (x2,y2)
09:00:00 | | | | | | |
2019-04-04 | 84.8 | 9.8 | 12 | 75 | 1.4 | 81 | (x3,y3)
09:00:00 | | | | | | |
2019-04-04 | 68.7 | 16.0 | 89 | 4 | 2.1 | 13 | (x4,y4)
09:00:00 | | | | | | |
... | | | | | | |
- 而后,此数据集的最大基数变为 10 亿[10,000 x 100 x 10 x 100]。
- 当初,假如设施也能够挪动,并且咱们想存储准确的 GPS 地位(纬度,经度),并将其用作索引的元数据进行查问。因为(lat,long)是一个间断字段(与诸如 equipment_id 之类的离散字段绝对),所以通过在地位上建设索引,此数据集的最大基数当初无限大(无界)。
高基数查问
- 艰深的说就是返回的 series 或者查问到的 series 数量过多
- 查问体现进去返回工夫较长,对应调用服务端资源较多的查问
- 数量多少算多 10w~100w
- 个别咱们定义在 1 小时内的 range_query 响应工夫超过
3 秒
则认为较重了
prometheus 断定高基数的三种办法
- prometheus tsdb 的统计接口
- prometheus 能够依据 query_log 中的 queryPreparationTime 来定位
- prometheus 通过 count by 统计
办法一 tsdb 的统计接口
- http://192.168.43.114:9090/ts…
- 接口地址
/api/v1/status/tsdb
- 是基于内存中的倒排索引 算最大堆取 top10
-
10 个最多的 metric_name 排序
seriesCountByMetricName: [{name: "namedprocess_namegroup_memory_bytes", value: 245},…] 0: {name: "namedprocess_namegroup_memory_bytes", value: 245} 1: {name: "namedprocess_namegroup_states", value: 245} 2: {name: "mysql_global_status_commands_total", value: 148} 3: {name: "namedprocess_namegroup_context_switches_total", value: 98} 4: {name: "namedprocess_namegroup_cpu_seconds_total", value: 98} 5: {name: "node_scrape_collector_success", value: 80} 6: {name: "node_scrape_collector_duration_seconds", value: 80} 7: {name: "namedprocess_namegroup_threads_wchan", value: 73} 8: {name: "namedprocess_namegroup_thread_cpu_seconds_total", value: 66} 9: {name: "namedprocess_namegroup_thread_io_bytes_total", value: 66}
-
思考采集器如果不是 prometheus 怎么办?
- 比方 m3db 没有提供高基数查问的接口
-
源码解析
// Stats calculates the cardinality statistics from postings. func (p *MemPostings) Stats(label string) *PostingsStats { const maxNumOfRecords = 10 var size uint64 p.mtx.RLock() metrics := &maxHeap{} labels := &maxHeap{} labelValueLength := &maxHeap{} labelValuePairs := &maxHeap{} numLabelPairs := 0 metrics.init(maxNumOfRecords) labels.init(maxNumOfRecords) labelValueLength.init(maxNumOfRecords) labelValuePairs.init(maxNumOfRecords) for n, e := range p.m { if n == "" {continue} labels.push(Stat{Name: n, Count: uint64(len(e))}) numLabelPairs += len(e) size = 0 for name, values := range e { if n == label {metrics.push(Stat{Name: name, Count: uint64(len(values))}) } labelValuePairs.push(Stat{Name: n + "=" + name, Count: uint64(len(values))}) size += uint64(len(name)) } labelValueLength.push(Stat{Name: n, Count: size}) } p.mtx.RUnlock() return &PostingsStats{CardinalityMetricsStats: metrics.get(), CardinalityLabelStats: labels.get(), LabelValueStats: labelValueLength.get(), LabelValuePairsStats: labelValuePairs.get(), NumLabelPairs: numLabelPairs, } }
办法二 query_log
- 能够依据 log 中的 queryPreparationTime 来定位
办法三 通过 count 统计
topk(5,count({__name__=~".+"}) by(__name__) > 100 )
- scrape_samples_scraped 能够阐明 job 的 instance 维度 sample 数量,也可能定位