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的数据类型定义

PrometheusPromQL中,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
      
      

这个方法返回VectorSample的总数。这可以用于确定Vector的大小或进行迭代操作。

  在Prometheus的PromQL中,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ɚ])

    • 定义: 一个单一的数值结果,通常是通过聚合函数(如sumavgcountminmax等)对一组时间序列或瞬时向量进行处理后得到的。

    • 特点: 标量没有与之关联的时间戳或标签,它只是一个纯数值。

    • 示例: sum(http_requests_total{method="GET"})返回所有使用GET方法的HTTP请求总数的总和。

    • sum(http_requests_total{method="GET"})
            
            

      这条查询将返回所有使用GET方法的HTTP请求总数的总和。

    • 代码解析: 这段代码定义了Scalar结构体,代表一个不与特定度量指标关联的数据点,包含时间戳T(以纳秒为单位)和值V(浮点类型)。此外,还实现了两个方法: String()方法:将Scalar实例格式化为字符串,格式为“scalar: 值 @[时间戳]”。 MarshalJSON()方法:将Scalar实例转换为JSON格式,格式为[时间戳/1000, 值]的数组,其中时间戳转换为秒。

// 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)

    • 注意: PrometheusPromQL查询语言本身不直接返回字符串类型的结果,但字符串在处理标签和进行某些特定操作时(如正则表达式匹配)是必需的。

    • 应用: 虽然查询不直接返回字符串类型,但字符串用于标签过滤、标签替换等场景。

    • 示例: 虽然不直接返回字符串,但可以使用label_replace函数来修改时间序列的标签,其中涉及字符串操作。

posted @ 2024-08-06 14:29  左扬  阅读(66)  评论(0编辑  收藏  举报
levels of contents