Prometheus源码专题精讲——Prometheus的四种查询类型
Prometheus源码专题精讲——Prometheus的四种查询类型
https://github.com/prometheus/prometheus/blob/v2.53.1/promql/value.go
Prometheus的查询类型基于其强大的查询语言(PromQL),支持从瞬时查询到范围查询,再到聚合查询等多种场景。通过理解和应用这些查询类型,用户可以灵活地检索、分析和可视化他们的时间序列数据。结合Prometheus的源码,我们可以更深入地理解这些查询类型背后的实现机制,从而更好地利用Prometheus进行监控和警报。
在Prometheus中,查询类型主要由返回的数据类型决定。根据promql/parser/value.go
文件中的定义,主要有以下几种查询类型:
一、 瞬时向量(Instant Vector)
-
-
定义: 一组时间序列,每个时间序列代表一个度量指标(如
http_requests_total)
,这些时间序列由一组标签(如method="GET"
)唯一标识。 -
特点: 这组时间序列中的每个样本都代表了在查询执行时(即“现在”)的度量值。所有返回的样本在逻辑上被视为具有相同的时间戳(即查询执行的瞬间)。
-
示例: http_requests_total{method="GET"}返回所有标签为method="GET"的http_requests_total时间序列的当前值。
-
http_requests_total{method="GET"}
这条查询将返回所有使用GET方法的HTTP请求总数的当前值。
-
-
代码解析: 在Prometheus的源码中,
Vector
类型是一个重要的概念,它基本上是对[]Sample
类型的别名,但有一个重要的约定:在Vector中,所有的
Sample
都必须具有相同的时间戳。
-
D:\worker-go\prometheus-2.53.1\promql\value.go func (Vector) Type() parser.ValueType { return parser.ValueTypeVector } // Vector is basically only an alias for []Sample, but the contract is that // in a Vector, all Samples have the same timestamp. type Vector []Sample
type Vector []Sample Vector is basically only an alias for []Sample, but the contract is that in a Vector, all Samples have the same timestamp. func (vec Vector) ContainsSameLabelset() bool func (vec Vector) String() string func (vec Vector) TotalSamples() int func (Vector) Type() parser.ValueType promql.Vector on pkg.go.dev
1.1、Vector的数据类型定义
在Prometheus
的PromQL
中,Vector
是一个非常重要的类型,它用于表示一组具有相同时间戳的样本(Sample
)。这些样本通常代表了在某个特定时间点上的度量值。
// Vector is basically only an alias for []Sample, but the contract is that // in a Vector, all Samples have the same timestamp. type Vector []Sample
这段代码定义了Vector
类型,它实际上是[]Sample
(即Sample
类型的切片)的别名。但有一个重要的约定:在Vector
中,所有的Sample
都必须具有相同的时间戳。这个约定是Vector
类型与其他类型(如Matrix
)的主要区别之一。
1.2、Vector的方法
Vector
类型有几个方法,用于执行不同的操作:
1.2.1、Type()方法
func (Vector) Type() parser.ValueType { return parser.ValueTypeVector }
这个方法返回Vector
的类型,即ValueTypeVector
。这是parser.ValueType
枚举中的一个值,表示这是一个向量类型。
1.2.2、ContainsSameLabelset() 方法
func (vec Vector) ContainsSameLabelset() bool
这个方法检查Vector
中的所有Sample
是否包含相同的标签集。如果所有Sample
的标签都相同,则返回true
;否则返回false
1.2.3、String()方法
func (vec Vector) String() string
这个方法返回Vector
的字符串表示形式。这通常用于调试或日志记录,以便能够轻松地查看Vector
的内容。
1.2.4、TotalSamples()方法
func (vec Vector) TotalSamples() int
这个方法返回Vector
中Sample
的总数。这可以用于确定Vector
的大小或进行迭代操作。
Vector
是一个重要的类型,用于表示一组具有相同时间戳的样本。它提供了几个方法来执行不同的操作,如获取类型、检查标签集、转换为字符串和获取样本总数。这些方法和约定使得Vector
在PromQL查询中非常有用,特别是在处理瞬时向量时。
1.3、Vector的查询接口
对于Prometheus的HTTP
API,用于查询瞬时向量的基本地址是/api/v1/query
。当你想要执行一个PromQL查询(如http_requests_total{method="GET"}
)时,你需要向Prometheus服务器的这个API地址发送一个HTTP请求。
http://<prometheus-server-ip>:<prometheus-server-port>/api/v1/query
对应的接口查询:api/v1/query
curl -X POST http://192.168.1.100:9090/api/v1/query -d '{ "query": "http_requests_total{method=\"GET\"}" }' -H "Content-Type: application/json"
二、范围向量(Range Vector)
-
-
定义: 与瞬时向量类似,但返回的是一段时间内的时间序列样本集合,而不是单一时间点的值。
-
特点: 对于每个匹配的时间序列,它返回指定时间范围内(如过去5分钟)的所有样本。每个样本都有其自己的时间戳,表示实际记录的时间。
-
示例:
http_requests_total{method="GET"}[5m]
返回过去5分钟内所有使用GET
方法的HTTP
请求总数的样本数据。
-
http_requests_total{method="GET"}[5m]
这条查询将返回过去5分钟内,所有使用GET方法的HTTP请求总数的样本数据。
-
-
代码解析: 在
Prometheus
中,范围向量(Range Vector
)是时间序列数据的一种表示,它表示在一定时间范围内的数据点集合。在Prometheus
的查询语言PromQL
中,范围向量是通过对瞬时向量(Instant Vector
)应用时间范围选择器(如 [5m] 表示过去5分钟内的数据)来创建的。 在D:\worker-go\prometheus-2.53.1\promql\value.go
代码中,Matrix
类型是对范围向量的一个实现。Matrix
是一个Series
类型的切片,其中Series
包含了时间序列数据。每个Series
包含了一个Metric
(指标)和一些与之相关的数据点,这些数据点可以是浮点数(Floats
)或直方图(Histograms
)。D:\worker-go\prometheus-2.53.1\promql\value.go // Matrix is a slice of Series that implements sort.Interface and // has a String method. type Matrix []Series func (m Matrix) String() string { // TODO(fabxc): sort, or can we rely on order from the querier? strs := make([]string, len(m)) for i, ss := range m { strs[i] = ss.String() } return strings.Join(strs, "\n") } // TotalSamples returns the total number of samples in the series within a matrix. // Float samples have a weight of 1 in this number, while histogram samples have a higher // weight according to their size compared with the size of a float sample. // See HPoint.size for details. func (m Matrix) TotalSamples() int { numSamples := 0 for _, series := range m { numSamples += len(series.Floats) + totalHPointSize(series.Histograms) } return numSamples } func (m Matrix) Len() int { return len(m) } func (m Matrix) Less(i, j int) bool { return labels.Compare(m[i].Metric, m[j].Metric) < 0 } func (m Matrix) Swap(i, j int) { m[i], m[j] = m[j], m[i] } // ContainsSameLabelset checks if a matrix has samples with the same labelset. // Such a behavior is semantically undefined. // https://github.com/prometheus/prometheus/issues/4562 func (m Matrix) ContainsSameLabelset() bool { switch len(m) { case 0, 1: return false case 2: return m[0].Metric.Hash() == m[1].Metric.Hash() default: l := make(map[uint64]struct{}, len(m)) for _, ss := range m { hash := ss.Metric.Hash() if _, ok := l[hash]; ok { return true } l[hash] = struct{}{} } return false } }
-
三、标量(Scalar [ˈskelɚ])
-
-
定义: 一个单一的数值结果,通常是通过聚合函数(如
sum
、avg
、count
、min
、max
等)对一组时间序列或瞬时向量进行处理后得到的。 -
特点: 标量没有与之关联的时间戳或标签,它只是一个纯数值。
-
示例:
sum(http_requests_total{method="GET"})
返回所有使用GET方法的HTTP请求总数的总和。 -
代码解析: 这段代码定义了
Scalar
结构体,代表一个不与特定度量指标关联的数据点,包含时间戳T
(以纳秒为单位)和值V
(浮点类型)。此外,还实现了两个方法:String()
方法:将Scalar
实例格式化为字符串,格式为“scalar: 值 @[时间戳]”。MarshalJSON()
方法:将Scalar
实例转换为JSON格式,格式为[时间戳/1000, 值]的数组,其中时间戳转换为秒。
sum(http_requests_total{method="GET"})
这条查询将返回所有使用GET方法的HTTP请求总数的总和。
-
// Scalar is a data point that's explicitly not associated with a metric. type Scalar struct { T int64 V float64 } func (s Scalar) String() string { v := strconv.FormatFloat(s.V, 'f', -1, 64) return fmt.Sprintf("scalar: %v @[%v]", v, s.T) } func (s Scalar) MarshalJSON() ([]byte, error) { v := strconv.FormatFloat(s.V, 'f', -1, 64) return json.Marshal([...]interface{}{float64(s.T) / 1000, v}) }
四、字符串(String)
-
-
注意:
Prometheus
的PromQL
查询语言本身不直接返回字符串类型的结果,但字符串在处理标签和进行某些特定操作时(如正则表达式匹配)是必需的。 -
应用: 虽然查询不直接返回字符串类型,但字符串用于标签过滤、标签替换等场景。
-
示例: 虽然不直接返回字符串,但可以使用
label_replace
函数来修改时间序列的标签,其中涉及字符串操作。
-