写在最前
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数量,也能够定位
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。