promethues 之PromQL数据类型介绍(二)

promethues 之PromQL数据类型介绍(二)

1、PromQL 介绍

  • PromQL是promethues 监控系统内置的一种查询语言,类似于MySQL的SQL语句,该语言仅用于读取数据。PromQL是我们学习Promethues最困难也是最重要的部分。
  • 当Promethues从系统和服务收集到指标数据时,他会把数据存储在内置的时序数据库(TSDB)中,要对收集的数据进行处理,我们需要使用PromQL从TSDB中读取数据,同时可以对所选的数据执行过滤、聚合以及其他转换操作。
  • 通过PromQL的学习,能够有效的构建和理解PromQL查询。可以帮助我们对报警规则、仪表盘可视化等需求。能够避免一些在使用PromQL表达式的时候遇到的一些陷阱。

2、PromQL的执行方式

PromQL的执行可以通过两种方式来触发

2.1 配置规则时自动发生

在 Prometheus 服务器中,记录规则和警报规则会定期运行,并执行查询操作来计算规则结果(例如触发报警)。该执行在 Prometheus 服务内部进行,并在配置规则时自动发生。

图片.png-142.6kB

2.2 使用Promethues HTTP API 执行PromQL方式

外部用户和 UI 界面可以使用 Prometheus 服务提供的 HTTP API 来执行 PromQL 查询。这就是仪表盘软件(例如 Grafana、PromLens 以及 Prometheus 内置 Web UI)访问 PromQL 的方式。

图片.png-89.3kB

2.3 场景案例

我们可以利用PromQL来对收集的数据进行实时查询,这有助于去调式和诊断遇到的一些问题-。
我们一般也是直接使用内置的表达式在查询界面来执行这类查询:

2.3.1 查看内存信息

# 查看CPU的空闲内存
node_memory_MemFree_bytes

# 查看CPU的总内存
node_memory_MemTotal_bytes

# 查看CPU的可用内存
node_memory_MemAvailable_bytes

图片.png-123kB

2.3.2 查看CPU信息

我们平时习惯了top,uptime,sar,vmstat,iostat这些简便的方式查看CPU使用率,往往浅尝辄止根本没有好好深入理解所谓的CPU使用率在Linux中到底是怎么回事。

# 使用标签过滤器查看所有CPU核心的空闲状态的总时间
node_cpu_seconds_total{mode="idle"}
	
# 使用标签过滤器查看所有CPU核心的非空闲状态的总时间	
node_cpu_seconds_total{mode!="idle"}
	
# 使用标签过滤器查看mode名称以"i"开头的所有CPU核心	
node_cpu_seconds_total{mode=~"i.*"}
	
# 使用标签过滤器查看除了mode名称以"i"开头的所有CPU核心
node_cpu_seconds_total{mode!~"i.*"}
	
# 表示查看所有CPU核心的所有状态的耗费时间
node_cpu_seconds_total

图片.png-126.2kB

2.3.3 查看磁盘

# 查看磁盘最近10分钟总的增长量并以每秒的形式出图显式
rate(node_disk_write_time_seconds_total[10m])

图片.png-144.8kB

温馨提示:我们看到的图都是临时的,当关闭浏览器就不存在了,如果想要其永久存在,则可以借助grafana实现永久的图形的存储哟。

3、PromQL 中常用函数

3.1 increase函数

increase() 函数表示某段时间内数据的增量

  • 当我们获取数据比较精细的时候 类似于1m取样推荐使用rate()
  • 当我们获取数据比较粗糙的时候 类似于5m,10m甚至更长时间取样推荐使用increase()

表达式示例:

# 获取网卡1m内流量增量 
increase(node_network_receive_bytes_total{device="eth0"}[1m])

图片.png-169.8kB

3.2 sum函数

sum()函数就是求和函数前面已经说过,注意点是当你使用sum后是将所有的监控的服务器的值进行取和,所以当我们只看某一台时需要进行拆分

拆分常用方法:

  • 1 by increase()
  • 2 by (cluster_name) 属于自定义标签不是标准标签,我们可以手动将不痛功能的服务器进行分组展示

表达式示例:

sum(rate(node_network_receive_bytes_total{device="eth0"}[1m]))

图片.png-159.7kB

3.3 by函数

by函数:将数据进行分组,类似于MySQL的"group by"。
举个例子:

  • by (instance):
    • 这里的"instance"代表的是机器名称,意思是将数据按照instance标签进行强行拆分。
    • 该函数通常会和sum函数搭配使用,比如"(sum(increase(node_cpu_seconds_total[1m])) by (instance))",表示把sum函数中累加和按照"instance"(机器名称)强行拆分成多组数据。当然,如果只有一个机器名称的话,你会发现只有一组数据,因此从结果上可能看不到明显的变化哟。

温馨提示:instance是node_exporter内置的标签,当然,我们也可以自定义标签,比如根据生产环境中不同的集群添加相应的标签。比如基于自定义的"cluster_name"标签进行分组等。

表达式示例:

(sum(increase(node_cpu_seconds_total[1m])) by (instance))

图片.png-140.9kB

3.4 rate 函数

它的功能是按照设置的一个时间段,取counter在这个时间段中的平均每秒的增量。因此是专门搭配counter类型数据使用的函数。

  • increase函数和rate函数如此相似如何选择?
    • 对于采集频率较低的数据采用建议使用increase函数,因为使用rate函数可能会出现断点(比如按照5分钟采样数据量较小的场景,以采集硬盘可用容量为例,可能会出现某次采集数据未采集到的情况,因为会按照平均每秒来计算最终的增量)的情况;
    • 对于采集频率较高的数据采用建议使用rate函数,比如对CPU,内存,网络流量等都可以基于rate函数来采样,当然,硬盘也是可以用rate函数来采样的哟;

温馨提示:在实际工作中,我们取监控频率为1分钟还是5分钟这取决与我们对于监控数据的敏感程度来挑选。

表达式示例:

# 获取CPU总使用时间在1分钟内的增加的总量并除以60秒,计算的是每秒的增量
rate(node_cpu_seconds_total[1m])

# 获取一分钟内网络接收的总量。查看的时间越短,某一瞬间的突起或降低在成图的时候会体现的更细致,更铭感
rate(node_network_receive_bytes_total[1m])

# 获取二十分钟内网络接收的总量
rate(node_network_receive_bytes_total[20m])

图片.png-116.2kB

3.5 topk 函数

取前几位的最高值。实际使用的时候一般会用该函数进行瞬时报警,而不是为了观察曲线图。

温馨提示:如下图所示,我们通常使用topk只会关注"Console"中的瞬时结果,不太会关心Graph的出图效果,因为关注他并没有太大意义,存在太多的断点啦!下图之所以会出现中断的情况,是因为在20分钟内这一刻的数据其并没有排进top3,自然就会出现断点的状况。

表达式示例:

topk(3,rate(node_cpu_seconds_total[1m]))

图片.png-179.2kB

3.6 count 函数

count() 是找出当前或者历史数据中某个key的数值大于或小于某个值的统计

把数值符合条件的,输出数目进行累计加和。一般用它进行一些模糊的监控判断。比如说企业中有100台服务器,那么只有10台服务器CPU使用率高于80%的时候,这个时候不需要报警,当符合80%CPU的服务器数量超过70台的时候那么就触发报警。

表达式示例:

count(oldboyedu_tcp_wait_conn > 500)

我们假设oldboyedu_tcp_wait_conn是咱们自定义的KEY,上述案例是找出当前(或者历史的)当前TCP等待数大于500的机器数量。

更多函数请参考官方文档:https://prometheus.io/docs/prometheus/latest/querying/functions/

4、企业级监控案例

企业基于Prromethues函数及PromQL查询

4.1 CPU相关

详细步骤:

  • 我们需要先找到查看CPU的key名称
    • node_cpu_seconds_total
  • 过滤cpu的空闲("idle")时间和全部CPU时间,使用"{}"做过滤
    • node_cpu_seconds_total{mode="idle"}:过滤空闲的CPU时间。
    • node_cpu_seconds_total{}:此处是可用省略"{}"的哟,因为里面没有任何参数,代表获取CPU的所有状态时间。
  • 把1分钟的增量的CPU时间取出来
    • increase(node_cpu_seconds_total{mode="idle"}[1m]):1分钟内CPU空闲状态的增量。
    • increase(node_cpu_seconds_total[1m]):1分钟内CPU所有状态的增量。
  • 将结果集进行加和统计
    • sum(increase(node_cpu_seconds_total{mode="idle"}[1m])):将1分钟内CPU空闲状态的增量数据进行加和计算。
    • sum(increase(node_cpu_seconds_total[1m])):将1分钟内CPU所有状态的增量数据进行加和计算。
      温馨提示:细心的小伙伴可能已经发现了,这里会有一个坑,因为它不光把每一台机器的多个核加载一起,还会把所有机器的CPU也全都加到了一起,这意味着变成了集群CPU的平均值了,需要解决该问题。
  • 按照"instance"(机器名称)强行拆分成多组数据
    • sum(increase(node_cpu_seconds_total{mode="idle"}[1m])) by (instance):将1分钟内CPU空闲状态的增量数据进行加和计算并按照"increase"(机器名称)强行拆分成多组数据。
    • sum(increase(node_cpu_seconds_total[1m])) by (instance):将1分钟内CPU所有状态的增量数据进行加和计算并按照"increase"(机器名称)强行拆分成多组数据。
  • 计算CPU空闲时间的百分比
    • sum(increase(node_cpu_seconds_total{mode="idle"}[1m])) by (instance) / sum(increase(node_cpu_seconds_total[1m])) by (instance)
  • 计算CPU使用率,计算公式: "(1 - CPU空闲时间的百分比) * 100%"。
    • (1 - ((sum(increase(node_cpu_seconds_total{mode="idle"}[1m])) by (instance)) / (sum(increase(node_cpu_seconds_total[1m])) by (instance)))) * 100

4.1.1 计算各节点的CPU的总使用率

(1 - ((sum(increase(node_cpu_seconds_total{mode="idle"}[1m])) by (instance)) / (sum(increase(node_cpu_seconds_total[1m])) by (instance)))) * 100

图片.png-141.8kB

4.1.2 计算CPU空闲时间的百分比

sum(increase(node_cpu_seconds_total{mode="idle"}[1m])) by (instance) / sum(increase(node_cpu_seconds_total[1m])) by (instance)

图片.png-143kB

4.1.3 计算用户态的CPU使用率

sum(increase(node_cpu_seconds_total{mode="user"}[1m])) by (instance) / sum(increase(node_cpu_seconds_total[1m])) by (instance) * 100

图片.png-61.7kB

4.1.4 计算内核态的CPU使用率

sum(increase(node_cpu_seconds_total{mode="system"}[1m])) by (instance) / sum(increase(node_cpu_seconds_total[1m])) by (instance) * 100

图片.png-59.1kB

4.1.5 计算IO等待的CPU使用率

sum(increase(node_cpu_seconds_total{mode="iowait"}[1m])) by (instance) / sum(increase(node_cpu_seconds_total[1m])) by (instance) * 100

图片.png-55.9kB

4.2 内存相关

4.2.1 内存使用率

100 - (node_memory_MemFree_bytes+node_memory_Cached_bytes+node_memory_Buffers_bytes) / node_memory_MemTotal_bytes * 100

图片.png-61kB

4.2.2 空闲内存剩余率

(node_memory_MemFree_bytes+node_memory_Cached_bytes+node_memory_Buffers_bytes) / node_memory_MemTotal_bytes * 100

图片.png-61.1kB

4.3 磁盘相关

4.3.1 磁盘使用率

100 - (node_filesystem_free_bytes{mountpoint="/",fstype=~"ext4|xfs"} / node_filesystem_size_bytes{mountpoint="/",fstype=~"ext4|xfs"} * 100)

图片.png-64.6kB

4.3.2 查看磁盘小于90%的系统

(node_filesystem_free_bytes / node_filesystem_size_bytes) < 0.90

图片.png-62.1kB

温馨提示:

  • 生产环境中建议大家将0.95改为0.20,表示当空闲硬盘小于20%的时候就显示在图上;
  • 我之所以些0.95是因为我的空闲硬盘挺大的,为了让大家看到出图的效果而已

4.3.3 监控磁盘IO使用情况

((rate(node_disk_read_bytes_total[1m]) + rate(node_disk_written_bytes_total[1m]))/1024/1024) > 0

图片.png-62.5kB

温馨提示:

  • 对于硬盘I/O是监控硬盘读写量的监控。上面的公式将默认的Bytes单位转换成MB单位啦。
  • 如果磁盘I/O飙高,这意味着CPU的iowait也会飙高,这可能会触发大批量的报警,因此我们要实现一个"真实链路报警",从根源切断无效的报警。

4.4 连接数使用率

参考案例:
(node_filefd_allocated / node_filefd_maximum) * 100

node_filefd_allocated:已分配的文件描述符。
node_filefd_maximum:一个进程运行最大打开文件描述符的总量。

图片.png-145.1kB

5 安装pushgateway

5.1 安装包下载

pushgateway包 下载链接

图片.png-103.3kB

[root@prometheus 1]# wget https://github.com/prometheus/pushgateway/releases/download/v1.6.0/pushgateway-1.6.0.linux-amd64.tar.gz

5.2 解压使用

[root@prometheus ~]# tar xf pushgateway-1.6.0.linux-amd64.tar.gz 
[root@prometheus ~]# mv pushgateway-1.6.0.linux-amd64 /usr/local/pushgateway

5.3 后台启动

[root@prometheus ~]# cd /usr/local/pushgateway/
[root@prometheus pushgateway]# nohup ./pushgateway &>/var/log/pushgateway.log &

5.4 配置监控的对象

[root@prometheus ~]# vim /usr/local/prometheus/prometheus.yml 
[root@prometheus ~]# tail -4 /usr/local/prometheus/prometheus.yml 
  - job_name: "pushgateway"
    file_sd_configs:
    - files:
      - /usr/local/prometheus/discovery/pushgateway.yml

[root@prometheus ~]# cat /usr/local/prometheus/discovery/pushgateway.yml
[
  {
    "targets":  ["192.168.200.15:9091"]
  }
]

5.5 重启prometheus

[root@prometheus ~]# ps -ef|grep prometheus|grep -v grep|awk '{print $2}'|xargs -i kill -9 {}
[root@prometheus ~]# cd /usr/local/prometheus
[root@prometheus prometheus]# nohup ./prometheus &>/var/log/prometheus.log &

图片.png-63.3kB

6 编写脚本通过pushgateway传递数据

6.1 监控网络I/O

参考案例:
rate(node_network_transmit_bytes_total[1m]) / 1024 / 1024

node_network_transmit_bytes_total:网络传输字节数

图片.png-118.8kB

6.2 网络延迟及丢包率监控(脚本)

(1)编写脚本
[root@prometheus ~]# mkdir -p /usr/local/node_exporter/script/
[root@prometheus ~]# vim /usr/local/node_exporter/script/network_delay.sh
[root@prometheus ~]# cat /usr/local/node_exporter/script/network_delay.sh
#!/bin/bash

# 以点号作为分割只取第一段作为本机的主机标签
instance_name=`hostname -f | cut -d '.' -f 1`

# 要求机器名不能是"localhost"不然标签就没有区分了
if [ $instance_name == "localhost" ]
    then
        echo "Must FQDN hostname"
        exit
fi

# 指定需要ping的主机
monitoring_site="www.baidu.com"

# 获取丢包率相关字段
package_loss_rate=`timeout 5 ping -q -A -s 500 -W 1000 -c 100 $monitoring_site | grep transmitted | awk '{print $6}'`

# 获取延迟情况的相关字段(本质上是执行ping命令所耗费的时间哟~)
delay_time=`timeout 5 ping -q -A -s 500 -W 1000 -c 100 $monitoring_site | grep transmitted | awk '{print $10}'`

# 获取数字类型
package_loss_rate_number=`echo $package_loss_rate | sed "s/%//g"`
delay_time_number=`echo $delay_time | sed "s/ms//g"`

# 将数据上传到pushgateway
echo "lyly_linux_package_loss_rate_$instance_name $package_loss_rate_number" | curl --data-binary @- http://prometheus:9091/metrics/job/lyly_linux_package_loss_rate_$instance_name/instance/localhost:9092
echo "lyly_linux_delay_time_$instance_name $delay_time_number" | curl --data-binary @- http://prometheus:9091/metrics/job/lyly_linux_package_loss_rate_$instance_name/instance/localhost:9092
(2)为脚本添加执行权限
[root@prometheus ~]# chmod +x /usr/local/node_exporter/script/network_delay.sh
(3)编写周期性任务
[root@prometheus ~]# crontab -l

...
# 网络延迟及丢包率监控
* * * * * /usr/local/node_exporter/script/network_delay.sh
* * * * * (sleep 10;/usr/local/node_exporter/script/network_delay.sh)
* * * * * (sleep 20;/usr/local/node_exporter/script/network_delay.sh)
* * * * * (sleep 30;/usr/local/node_exporter/script/network_delay.sh)
* * * * * (sleep 40;/usr/local/node_exporter/script/network_delay.sh)
* * * * * (sleep 50;/usr/local/node_exporter/script/network_delay.sh)
(4)在Prometheus server中查看KEY
lyly_linux_package_loss_rate_prometheus	
lyly_linux_delay_time_prometheus

图片.png-130.6kB
温馨提示:对于较多的网络监控我建议还是使用专业的smokeping监控系统,尤其是在IDC公司,smokeping基本上是必用软件哟。

6.3 监控TCP状态(脚本)

(1)编写采集脚本
[root@prometheus ~]# vim /usr/local/node_exporter/script/node_exporte.sh
[root@prometheus ~]# cat /usr/local/node_exporter/script/node_exporte.sh
#!/bin/bash

# 以点号作为分割只取第一段作为本机的主机标签
instance_name=`hostname -f | cut -d '.' -f 1`

# 要求机器名不能是"localhost"不然标签就没有区分了
if [ $instance_name == "localhost" ]
    then
        echo "Must FQDN hostname"
        exit
fi

# 定义Prometheus抓取的KEY值,用于保存TCP的wait状态相关的连接(connections)
label="lyly_tcp_wait_conn"

# 通过netstat工具抓取wait链接的数量
lyly_tcp_wait_conn=`netstat -an| grep -i wait|wc -l`

echo "$label $lyly_tcp_wait_conn" | curl --data-binary @- http://prometheus:9091/metrics/job/lyly_linux_$instance_name/instance/$instance_name
  • echo "$label $lyly_tcp_wait_conn":指定KEY和VALUE,注意中间是空格分割,不要尝试用其它字符分割。如果你使用":"分割,可能在Prometheus server端是无法查询到数据的哟;
  • "curl --data-binary":表示发起的是POST请求数据为纯二进制数据。
  • "http://prometheus:9091/metrics":表示pushgateway的服务器地址
  • "job/lyly_linux":表示第一个标签,相当于推送到prometheus server配置文件中"prometheus.yml"中定义的job名称。该名称咱们完全是可以自定义的哟~
  • "instance/$instance_name":推送有关于instance这个变量其对应的主机名。方便后期我们在prometheus server的WebUI界面使用{instance="server"}对主机进行过滤哟~

温馨提示:注意Prometheus server支持的数据类型,如果类型不支持,则无法在Prometheus server的Web UI中进行查看。

(2)为脚本添加执行权限
[root@prometheus ~]# chmod +x /usr/local/node_exporter/script/node_exporte.sh
(3)编写周期性任务
[root@prometheus ~]# crontab -l

...
# 监控TCP状态脚本
* * * * * /usr/local/node_exporter/script/node_exporte.sh
* * * * * (sleep 10;/usr/local/node_exporter/script/node_exporte.sh)
* * * * * (sleep 20;/usr/local/node_exporter/script/node_exporte.sh)
* * * * * (sleep 30;/usr/local/node_exporter/script/node_exporte.sh)
* * * * * (sleep 40;/usr/local/node_exporter/script/node_exporte.sh)
* * * * * (sleep 50;/usr/local/node_exporter/script/node_exporte.sh)
(4)在Prometheus server中查看KEY
lyly_tcp_wait_conn

图片.png-130.2kB