新手学习PromQL
前言
作为一个第一次接触PromQL的新手,我尝试记录一下,我学习的记录,希望对你们也有一点点用处。石墨文档来源于SRETalk分享的教程。
Prometheus
Prometheus是一款开源的监控系统,PromQL 是其查询语言。学习 PromQL 前,需要了解 Prometheus。类似于Kubernetes从Google的Brog系统演变而来,Promtheus项目也是受启发于Google的Borgmon监控系统,相对于传统的监控系统有很多先进的理念,并在众多监控系统中脱颖而出成为云原生架构领域里构建监控系统的事实标准。
Prometheus会将所有采集数据以时间序列(time-series)的方式保存在内存数据库(TSDB)中,数据按照时间戳和值的序列顺序存放的,称之为向量(vector)。
每条时间序列通过指标名称(metrics name)和一组标签集(labelset)命名。如果使用传统的SQL语言相对缺乏表达能力,而通过PromQL我们可以非常方便的对数据使用标签进行任意查询,过滤,以及聚合,还可以使用标签将不同的指标连接在一起进行算术操作。
让监控指标不再是一个单独存在的个体,而是一个个能够表达出正式业务含义的语言。
从存储上我们了解到所有的监控指标metric都是相同的,但不同场景下这些metric又有一些细微的差异,Prometheus定义了4种不同的指标类型(metric type)区分不同监控指标之间的差异:Counter(计数器)、Gauge(仪表盘)、Histogram(直方图)、Summary(摘要)。
- Counter:只增不减的计数器
- Gauge:可增可减的仪表盘
- 使用Histogram和Summary分析数据分布情况,只是为了上报监控数据的 Client 侧的便利,可以看做是组合使用了 Gauge 和 Counter
PromQL 基础语法和内置函数
mem_available_percent{app="clickhouse"} or {__name__="mem_available_percent", app="clickhouse"}
查询选择器
PromQL大括号里的部分是查询选择器(selector),用于从一大堆监控数据中,过滤出真正关心的数据,而且也可以看出指标名称也是一个标签,其标签Key是 ‘name’,第一种看起来更易懂。标签过滤支持四类操作符:
- =:完全匹配,比如 app="clickhouse"
- !=:完全不匹配,比如 app!="clickhouse"
- =~:正则匹配,比如 app=~"n9e-.*"
- !~:正则不匹配,比如 app!~"n9e-.*"
查询表达式
完整语句称为查询表达式,不同的表达式,会返回不同的内容,返回的内容总共有 4 种格式,分别是:
- Instant vector(瞬时向量)
- Range vector(范围向量)
- Scalar(标量)
- String(字符串)
返回瞬时向量的查询表达式,我们称为 Instant Query;返回范围向量的查询表达式,我们称为 Range Query。
- Range Query 理论上是没法绘制 Graph 的(当然有些时序库可能会做容错处理),绘图时需要传给后端一个数据间隔(step)参数用于控制分辨率,比如step=60,即表示希望每个series每分钟返回一个点,但如果是Range Query,相当于在某个时刻返回多个点。
这些PromQL查询语言中的数据类型,即查询类型和Metric Type一定不能混淆。
PromQL 支持基本的算术运算符和比较运算符,可以对不同的即时向量做运算,这为监控系统带来了巨大的进步.
算术运算符
- + (addition)
- - (subtraction)
- * (multiplication)
- / (division)
- % (modulo)
- ^ (power/exponentiation)
例如内存可用率的指标mem_available_percent,如果采集器没有计算,而是上报了原始指标mem_available和mem_total,我们仍然可以使用 promql 计算出可用率指标
mem_available{app="clickhouse"}/mem_total{app="clickhouse"}*100
需要注意如果分子和分母对应的selector查到的记录标签不同,就没法做除法运算了,比如 net_bytes_recv 比内存相关的指标多了一个interface的标签(标明网卡),二者是没法做运算的,结果为空:
net_bytes_recv{app="clickhouse"}/mem_total{app="clickhouse"}
比较运算符
- == (equal)
- != (not-equal)
- > (greater-than)
- < (less-than)
- >= (greater-or-equal)
- <= (less-or-equal)
例如如果认为内存可用率小于60就是有问题的,想找出所有有问题的数据,只要在 promql 中拼上 < 60 即可:
mem_available_percent{app="clickhouse"}<60
这也是告警引擎的核心逻辑。告警规则里会要求用户配置promql以及执行频率和持续时间,告警引擎就会根据执行频率周期性执行。
逻辑/集合运算符
运算符有三个:and、or、unless 用于 instant-vector 之间的运算。 and是交集,or是并集,unless需要解释一下。
- vector1 unless vector2
结果是一个由vector1中的元素组成的向量,在vector2中没有完全匹配标签集的元素,两个vector中的所有匹配元素都被删除。姑且可以理解为一个减法,vector1 - vector2。
举个例子,对于超过1个T的大盘,剩余量小于300G就告警,
disk_free{app="clickhouse"}/1024/1024/1024 < 300unlessdisk_total{app="clickhouse"}/1024/1024/1024 < 1024
使用 unless 排除掉小于1个T的盘,剩下的就只剩大于1个T的盘了,效果达成。
向量匹配
向量之间的操作试图在右侧的向量中为左侧向量的每个条目找到一个匹配的元素,匹配行为分为:one-to-one、many-to-one、one-to-many。
and、or、unless 和算数运算符对两个vector要求一样,标签集都是一样的,那如果有些标签略微有些差异,可以使用 on 和 ignoring 关键字来限制用于做匹配的标签集。
mysql_slave_status_slave_sql_running == 0
and ON (instance)
mysql_slave_status_master_server_id > 0
这个promql想表达的意思是如果这个mysql实例是个slave(master_server_id>0),则检查其slave_sql_running的值,如果slave_sql_running==0表示slave sql线程没有在运行。
两个指标的标签不完全一致,但二者都有个instance标签,且相同instance标签的数据从语义上来看就表示一个实例的多个指标数据,那就可以用on关键字,指定只使用instance标签做匹配,忽略其他标签。
与on相反的是ignoring关键字,是忽略掉某些标签,用剩下的标签来做匹配。
group_left 和 group_right这两个关键词用于 one-to-many 和 many-to-one 的匹配场景,我目前有完全搞懂TODO
聚合运算
- sum (calculate sum over dimensions)
- min (select minimum over dimensions)
- max (select maximum over dimensions)
- avg (calculate the average over dimensions)
- group (all values in the resulting vector are 1)
- stddev (calculate population standard deviation over dimensions)
- stdvar (calculate population standard variance over dimensions)
- count (count number of elements in the vector)
- count_values (count number of elements with the same value)
- bottomk (smallest k elements by sample value)
- topk (largest k elements by sample value)
- quantile (calculate φ-quantile (0 ≤ φ ≤ 1) over dimensions)
另外,我们有时会有分组统计的需求,比如我想分别统计clickhouse和canal的机器的内存可用率,可以使用by关键字指定分组统计的维度(与by相反的是without):
avg(mem_available_percent{app=~"clickhouse|canal"}) by (app)
offset
用于同环比需求,offset 后面跟一个时间段,比如 5m、1d、7d、1w,offset 要紧跟查询选择器,比如:
sum(http_requests_total{method="GET"} offset 1d)
函数
有很多函数,具体参考官方文档,常用包含absent_over_time,increase,rate,irate,histogram_quantile,<aggregation>_over_time
参考资料
https://shimo.im/docs/Ee32MV5VZeUGbQA2/
https://mp.weixin.qq.com/s/DFCTY0KPYlxlZMGOHcUSvw
https://github.com/yunlzheng/prometheus-book
https://blog.csdn.net/hualinux/article/details/108098442