prometheus学习笔记之进程监控process_exporter
项目地址:https://github.com/ncabatoff/process-exporter
一、安装process-exporter
https://github.com/ncabatoff/process-exporter/releases/download/v0.8.3/process-exporter-0.8.3.linux-amd64.tar.gz
tar xf process-exporter-0.8.3.linux-amd64.tar.gz
mv process-exporter-0.8.3.linux-amd64 /usr/local/process-exporter
cd /usr/local/process-exporter
vim process-exporter.yaml #监控所有进程,具体配置参考官方文档
process_names:
- name: "{{.Matches}}" #匹配一个或多个
cmdline:
- 'redis-server'
- name: "{{.Comm}}" #匹配所有
cmdline:
- '.+'
vim /usr/lib/systemd/system/process_exporter.service
[Unit]
Description=Prometheus exporter for processors metrics, written in Go with pluggable metric collectors.
Documentation=https://github.com/ncabatoff/process-exporter
After=network.target
[Service]
Type=simple
WorkingDirectory=/usr/local/process-exporter/
ExecStart=/usr/local/process-exporter/process-exporter -config.path=/usr/local/process-exporter/process-exporter.yaml
Restart=on-failure
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl start process_exporter
systemctl enable process_exporter
netstat -tnlp|grep 9256
浏览器查看数据抓取
二、process-exporter配置简解
1.配置格式及优先级
YAML 文件的一般格式是顶级 process_names 部分,其中包含名称匹配器列表,如果一个进程被多个匹配项匹配,则谁在前谁匹配到:
process_names:
- matcher1
- matcher2
...
- matcherN
2.模板及模板变量
process_names 中的每个项目都提供了用于标识和命名进程的方法。可选的 name 标签定义用于命名匹配进程的模板;如果未指定,则 name 默认为 {{.ExeBase}}
模板的可用变量:
{{.Comm}} 包含原始可执行文件的基本名称,即 /proc/<pid>/stat 中的第 2 个字段,并截取前15个字符
{{.ExeBase}} 包含可执行文件的基本名称
{{.ExeFull}} 包含可执行文件的完全限定路径
{{.Username}} 包含有效用户的用户名
{{.Matches}} map 包含应用 cmdline 正则表达式产生的所有匹配项
{{.PID}} 包含进程的 PID。请注意,使用 PID 意味着该组将仅包含一个进程
{{.StartTime}} 包含进程的开始时间。这与 PID 结合使用时非常有用,因为 PID 会随着时间的推移而被重用。
{{.Cgroups}} 包含(如果支持)进程的 cgroups (/proc/self/cgroup)。这对于识别进程属于哪个容器特别有用
#不建议使用 PID 或 StartTime:结果不一定符合预期
补充说明:name选项其实影响的是metrics中的key:groupname,以监控redis作为例子
前提:redis的进程信息如下:
[root@izx7dvghztbiorz process-exporter]# ps -ef | grep redis
redis 771 1 0 Jun05 ? 00:45:49 /usr/bin/redis-server *:6379
{{.Comm}} | groupname="redis-server" | exe或者sh文件名称 |
{{.ExeBase}} | groupname="redis-server *:6379" | / |
{{.ExeFull}} | groupname="/usr/bin/redis-server *:6379" | ps中的进程完成信息 |
{{.Username}} | groupname="redis" | 使用进程所属的用户进行分组 |
{{.Matches}} | groupname="map[:redis]" |
表示配置到关键字“redis” |
3.进程选择器
process_names中的每个项目都必须包含一个或多个选择器(comm、exe 或 cmdline);如果存在多个 selector,则它们必须全部匹配。每个选择器都是一个字符串列表,
用于匹配进程的 comm argv[0],或者在 cmdline 的情况下,用于应用于命令行的正则表达式。cmdline regexp 使用 Go 语法(https://pkg.go.dev/regexp) 对于 comm 和 exe,字符串列表是 OR,这意味着与任何字符串匹配的任何进程都将添加到项目的组中。 对于 cmdline,正则表达式列表是 AND,这意味着它们都必须匹配。regexp 中的任何捕获组都必须使用 ?P<name> 选项为捕获分配名称,该名称用于填充 .Matches 性能提示:除了任何 cmdline 子句外,还要提供 exe 或 comm 子句,这样就可以避免在可执行文件名称不匹配时执行 regexp。
为避免与 cmdline YAML 元素混淆,我们将进程/proc/<pid>/cmdline
的命令行参数称为数组argv[]
如以下示例
process_names:
#comm是/proc/<pid>/stat减去parens的第二个字段,截断前15个字符
- comm:
- bash
# exe是argv[0]。如果没有斜线,则只需要匹配argv[0]的基名,如果exe包含斜线,则argv[0]必须完全匹配
- exe:
- postgres
- /usr/local/bin/prometheus
# cmdline是应用于argv的正则表达式列表 每个捕获都必须匹配,任何捕获都将添加到 .Matches
- name: "{{.ExeFull}}:{{.Matches.Cfgfile}}"
exe:
- /usr/local/bin/process-exporter
cmdline:
- -config.path\s+(?P<Cfgfile>\S+)
4.组指标
process-exporter 假设每个指标都将附加到一组进程 - 不是技术意义上的进程组,只是一个或多个满足配置规范的进程应该监控什么以及如何命名它
指标都以 namedprocess_namegroup_ 开头,并且至少具有标签 groupname
namedprocess_namegroup_num_procs 组中的进程数。
namedprocess_namegroup_cpu_seconds_total CPU 使用, /proc/[pid]/stat 字段 utime(14)和 stime(15),即用户和系统时间。这类似于 node_exporter 的node_cpu_seconds_total
namedprocess_namegroup_read_bytes_total 基于 /proc/[pid]/io 字段read_bytes读取的字节数,需要root用户运行process-exporter才有权限读取io数据
namedprocess_namegroup_write_bytes_total 根据 /proc/[pid]/io 字段write_bytes写入的字节数
namedprocess_namegroup_major_page_faults_total 基于 /proc/[pid]/stat 字段 majflt(12) 的主要页面错误数。
namedprocess_namegroup_minor_page_faults_total 基于 /proc/[pid]/stat 字段 minflt(10) 的次要页面错误数。
namedprocess_namegroup_context_switches_total基于 /proc/[pid]/status 字段 voluntary_ctxt_switches 和 nonvoluntary_ctxt_switches 的上下文切换数。额外标签 ctxswitchtype 可以有两个值:voluntary 和 nonvoluntary。
namedprocess_namegroup_memory_bytes 已使用的内存字节数。额外的标签 memtype 可以有三个值:1.resident:/proc/[pid]/stat 字段 rss(24) 2:virtual vsize(23)虚拟内存大小 3:swapped VmSwap字段
namedprocess_namegroup_open_filedesc 文件描述符的数量,基于目录 /proc/[pid]/fd 中的条目数
namedprocess_namegroup_worst_fd_ratio
namedprocess_namegroup_在组中的所有进程中,打开的 filedesc 与 filedesc 限制的比率最差。该限制是基于 /proc/[pid]/limits 的 fd 软限制
namedprocess_namegroup_oldest_start_time_seconds 组中最早的进程开始的纪元时间(自 1970/1/1 以来的秒数)。这是从 /proc/[pid]/stat 的字段 starttime(22) 派生的,添加到引导时间中以使其相对于纪元。
namedprocess_namegroup_num_threads 组中所有进程的线程数之和。基于 /proc/[pid]/stat 中的 num_threads(20) 字段
namedprocess_namegroup_states 组中处于各种状态的线程数,基于 /proc/[pid]/stat 中的字段 state(3)
5.组线程指标
namedprocess_namegroup_thread_cpu_seconds_total 与 cpu_user_seconds_total 和 cpu_system_seconds_total 相同,但按线程细分子组
namedprocess_namegroup_thread_io_bytes_total 与 read_bytes_total 和 write_bytes_total 相同,但按线程细分子组
namedprocess_namegroup_thread_major_page_faults_total 与 major_page_faults_total 相同,但按线程子组划分
namedprocess_namegroup_thread_minor_page_faults_total 与 minor_page_faults_total 相同,但按线程子组划分
namedprocess_namegroup_thread_context_switches_total 与 context_switches_total 相同,但按线程细分子组
三、配置prometheus抓取
vim prometheus.yml
- job_name: 'yty-process' #进程监控
static_configs:
- targets: ['192.168.100.131:9256']
curl -X POST http://127.0.0.1:9090/-/reload
四、grafana模板
https://grafana.net/dashboards/249
五、常用告警规则
1.进程数
alert: 进程告警
expr: sum(namedprocess_namegroup_states) by (cluster,job,instance) > 500
for: 20s
labels:
severity: warning
annotations:
value: 服务器当前已产生 {{ $value }} 个进程,大于告警阈值
2.僵尸进程数
alert: 进程告警
expr: sum by(cluster, job, instance, groupname) (namedprocess_namegroup_states{state="Zombie"}) > 0
for: 1m
labels:
severity: warning
annotations:
value: 当前产生 {{ $value }} 个僵尸进程
3.进程重启
alert: 进程重启告警
expr: ceil(time() - max by(cluster, job, instance, groupname) (namedprocess_namegroup_oldest_start_time_seconds)) < 60
for: 25s
labels:
label: alert_once
severity: warning
annotations:
value: 进程 {{ $labels.groupname }} 在 {{ $value }} 秒前发生重启
4.进程退出
alert: 进程退出告警
expr: up{export="process_exporter"} == 0 or max by(cluster, job, instance, groupname) (delta(namedprocess_namegroup_oldest_start_time_seconds{groupname=~"^map.*"}[10d])) < 0
for: 55s
labels:
severity: warning
annotations:
value: 进程 {{ $labels.export}} 已退出
"一劳永逸" 的话,有是有的,而 "一劳永逸" 的事却极少