Prometheus 的查询有一套专用语言,叫做 PromQL。其表达式可能是受了 golang 的影响,非常的紧凑和符号化。这使得其易于书写但难以理解(对不熟悉这种 DSL 的人来说)。因而有了这篇文章。
以下内容基于官方文档(2.0)编译。
数据类型
表达式的值一定属于以下四种数据类型其一:
瞬时向量(Instant Vector)一组时序数据。其中每个时序都只有一个时间点,且一组数据的该时间点相同,比如今天 12:05:30 时所有服务器的 CPU 负载。
范围向量(Range Vector)一组时序数据,但每个时序都有一段时间的采样点。
标量(Scalar)单纯的浮点数
字符串(String)单纯的字符串(暂未使用)
向量和标量的区别仅在于向量是来自于时序数据的一个采样点,因此其带有时间戳、metric、labels 等属性。
我们主要关注两种向量的区别。从字面上来看,也许会觉得,画图(如 /graph)用的是范围向量,因为画图就是画的时序在一段时间范围内采样的值嘛。但其实能够用来画图的只有 瞬时向量。Prometheus 的运算逻辑是这样的:表达式只是返回一次计算的值,当画图的时候,先把总的时间段分割(downsample),然后分别计算每段上的瞬时向量,并赋予该时间段的起始时间戳。最后所有的段连接起来就是一张图。有点像 map/reduce 的过程。
字面量
字面量是最简单的一种表达式,所见即所得。但也有一些需要注意的地方,比如字符串。
单引号和双引号作用类似,使用 "\" 来进行转义。反引号括起来的字符串则完全不进行转义。其转义规则与 golang 相同。
时序查询语句
瞬时向量查询
即选取(select)一组时序数据的语句,是表达式的基本语句。从到现在的描述可以看出,PromeQL 并不明确区分一条和一组时序数据。可能在它的逻辑里这两者的本质是一样的,一条不过是一组的一个特例而已。
最简单的语句是一个 metric 名称
http_requests_total
然后可以加一些过滤条件(label)
http_requests_total{job="prometheus",group="canary"}
label 运算也支持除 = 外的其他运算符号,比如 != 不等于;=~ 正则匹配;!~正则不匹配。如
http_requests_total{environment=~"staging|testing|development",method!="GET"}
匹配运算有一个特殊问题就是如何处理空值。Prometheus 的方式是,key=""这种可以匹配不包含该 key 的时序,而 key=~'.*' 这种同样支持空值的正则表达式则只匹配包含该 key 的时序。
Prome 比较有趣的地方是支持不包含 metric 的查询语句,前提是至少有一个 label 不匹配空值,即避免 select all。
{job=~".+"} # Good!
{job=~".*"} # Bad!
更有趣的地方是,这种 label 匹配语句还可以匹配 metric 的名字,通过使用 __name__ 这个内置变量:
{__name__=~"^http.*"}
范围向量查询
范围向量的查询语法就是在瞬时向量的后面加一个 [] 标识从该瞬时向量的时间戳起向前选取多久的时间范围。中括号内支持一系列的形如 \d+\s的时间段表达式,表达式单位从小到大包含
s
m
h
d
w
y
注意里面没有月。一个主要的原因可能是月并非一个明确的时间段,另一个原因可能是和分钟的首字母冲突。虽然可以用大写 M 代替,但结合理由一,似乎引入这个单位带来的麻烦比好处要多。
offset 修饰符
用来将查询语句向更早平移的修饰符,可以修饰两种向量。使用时需注意一定要紧贴查询语句,如瞬时向量:
sum(http_requests_total{method="GET"} offset 5m) // GOOD.
sum(http_requests_total{method="GET"}) offset 5m // INVALID.
亦如范围向量
rate(http_requests_total[5m] offset 1w)
运算符
像刚展示的 sum, rate 等,PromeQL 支持很多二元或聚合运算符。他们的详细描述可以参考:OPERATORS
聚合
提供一个分组 label 和一个运算方法,如:以 job 分组,每组qps求和:
sum(rate(http_requests_total[5m])) by (job)
运算
如果两个 metric 的 label 完全匹配,那么他们之间就可以进行四则运算,比如减法:
(instance_memory_limit_bytes - instance_memory_usage_bytes) / 1024 / 1024
回到瞬时向量和范围向量上,可以看到运算符的运算过程是可以转化这两种向量的。比如最简单的 sum,可以把一个范围向量加和成为一个瞬时向量。这样你在 /graph 里不能展示的 http_requests_total[5m] 在套上一个 sum 后就可以画图了。
因为运算符的种类细节并不影响对 PromeQL 的理解,所以这里直接跳过。
函数