进程监控,有效的黑盒监控手段

介绍进程监控的目标、原理和 Categraf procstat 配置方法,说明如何通过 /proc、进程名、cmdline、资源指标和 JVM 采集实现进程存活与资源消耗监控。

作者 快猫

随着技术的进步以及研发人员意识提升,越来越多的进程已经内置暴露了健康检查的接口以及监控指标的接口,比如 Prometheus 生态的 /metrics 接口。但是,有一些进程并没有暴露这些接口,尤其是跑在宿主机上的一些进程,此时就需要一些黑盒监控手段了,比如本文要介绍的进程监控。

核心要点摘要

  • 进程监控是一种黑盒监控手段,重点关注进程是否存在,以及 CPU、内存、IO、线程、文件句柄等资源消耗。
  • 在 Linux 上,进程监控通常读取 /proc/<pid> 目录下的 status、cmdline、io、limits 等信息。
  • 用进程名匹配适合 nginx 这类名称明确的进程;Java 等名称不具备区分度的进程,更适合用 cmdline 匹配。
  • Categraf 的 procstat 插件可以按 search_exec_substringsearch_cmdline_substringsearch_win_service 等方式筛选进程。
  • 采集 JVM 信息时需要本机有 jstat 命令,并确保 Categraf 进程能从 PATH 中找到它。

进程监控的目标

进程监控主要是监控进程的存活性以及进程的资源消耗情况。有很多 agent 都可以采集这些信息,在夜莺社区里,我们推荐使用 Categraf 进行进程监控。Categraf 包含近百种采集插件,其中就包含了 procstat 插件,用于进程监控。本文以 Categraf 为例,介绍如何使用 Categraf 进行进程监控。其他 agent 也是类似的原理。

从告警角度看,进程监控至少要回答两个问题:

  1. 目标进程还在不在。
  2. 目标进程是否正在消耗异常资源。

第一个问题解决存活性,第二个问题解决资源异常。对于没有 /metrics、健康检查接口或业务埋点的进程,进程监控就是很实用的兜底手段。

进程监控的原理

以 Linux 为例,操作系统的 /proc 目录下存放了所有进程的信息,以进程 pid 作为目录名,下面包括进程的 name、cmdline、环境变量、limits、io 等各类信息,procstat 插件其实就是读取这些信息来监控进程的。

比如我知道某个机器部署了 n9e-foo 进程,想监控这个进程的存活性,其实就是遍历 /proc 下所有的进程,统计有几个进程其名字是 n9e-foo,如果有 0 个,那就说明进程挂了。从哪里读取进程名字?其实是从 /proc/pid/status 文件里读取的,比如我的环境里有个进程其 pid 是 4481,我们可以看一下这个进程的 status 文件:

root@ubuntu-linux-22-04-desktop:/proc/4481# head /proc/4481/status
Name:	node_exporter
Umask:	0022
State:	S (sleeping)
Tgid:	4481
Ngid:	0
Pid:	4481
PPid:	4296
TracerPid:	0
Uid:	0	0	0	0
Gid:	0	0	0	0

从第一行可以看到,这个进程的名字是 node_exporter

当然了,有些进程其名字不具备很好的区分度,比如所有的 Java 进程,不管是 Kafka 还是 Tomcat,其进程名字都是 java,这时候就需要结合 cmdline 信息来区分了。

下面我给大家找一个 Java 的进程,看看其 cmdline 信息:

[root@iZ2ze4oi71k3qgdxwsyn07Z ~]# cat /proc/1272973/cmdline | tr '\0' ' '
/usr/bin/java -server -Dlogback.configurationFile=/etc/zabbix/zabbix_java_gateway_logback.xml -classpath lib:lib/android-json-4.3_r3.1.jar:lib/logback-classic-1.2.9.jar:lib/logback-core-1.2.9.jar:lib/slf4j-api-1.7.32.jar:bin/zabbix-java-gateway-7.0.6.jar -Dsun.rmi.transport.tcp.responseTimeout=3000 com.zabbix.gateway.JavaGateway

如果直接 cat cmdline 文件,会发现是一串没有分隔的字符串,这是因为 cmdline 文件是以 \0 分隔的,而 \0 是一个不可见字符,所以我们需要用 tr 命令把 \0 替换成空格,这样就可以较为清晰地看到进程的启动命令了。

可以通过 name、cmdline 等信息过滤进程了,自然就可以统计进程的数量,也可以通过读取进程目录下的其他文件统计进程的资源消耗情况。下面我们来看看如何配置 Categraf 来监控进程。

什么时候用进程名,什么时候用 cmdline

选择匹配方式时,可以按进程是否容易区分来判断。

场景 推荐方式 原因
nginx、node_exporter 这类进程名明确的服务 search_exec_substring 进程可执行文件或进程名通常具备区分度
Kafka、Tomcat、Zabbix Java Gateway 等 Java 进程 search_cmdline_substring 进程名经常都是 java,需要通过启动参数区分
Windows 服务 search_win_service 直接按 Windows 服务名匹配
同一机器上同名进程由不同用户运行 search_user 配合其他筛选项 避免误采集其他用户启动的同名进程

Categraf 进程监控配置样例

机器上进程很多,我们要做进程监控,就要想办法告诉 Categraf 要监控哪些进程,通过 search 打头的那几个配置,可以做进程过滤筛选:

# 这是要监控的第一个进程
# [[instances]] 这一行默认是注释的,需要打开注释
[[instances]]
# # executable name (ie, pgrep <search_exec_substring>)
search_exec_substring = "nginx"

# # pattern as argument for pgrep (ie, pgrep -f <search_cmdline_substring>)
# search_cmdline_substring = "n9e server"

# # windows service name
# search_win_service = ""

gather_total = true
gather_per_pid = false
gather_more_metrics = [
    "threads",
    "fd",
    "io",
    "uptime",
    "cpu",
    "mem",
    "limit",
]

# 这是要监控的第二个进程
[[instances]]
search_cmdline_substring = "kafka"

gather_total = true
gather_per_pid = false
gather_more_metrics = [
    "threads",
    "fd",
    "io",
    "uptime",
    "cpu",
    "mem",
    "limit",
	"jvm",
]
  • search_exec_substring 相当于拿 readlink -e /proc/<pid>/exe 与 search_exec_substring 的内容做字符串匹配,如果匹配上了,就采集这个进程的信息
  • search_cmdline_substring 相当于拿 cat /proc/<pid>/cmdline 与 search_cmdline_substring 的内容做字符串匹配,如果匹配上了,就采集这个进程的信息
  • search_win_service 用于 windows 机器,表示要监控的 windows 服务名字, 当然 windows 机器上也可以用 search_exec_substring 或者 search_cmdline_substring 来做进程筛选

上面三个 search 相关的配置,每个 [[instances]] 配置段选用其中一个。有一个额外的配置,search_user 配合search_exec_substring 或者 search_cmdline_substring 使用,表示匹配指定 username 的特定进程。

# # search process with specific user, option with exec_substring or cmdline_substring
# search_user = ""

procstat 插件其他关键配置

  • gather_total:比如进程名字是 mysql 的进程,同时可能运行了多个,我们想知道这个机器上的所有 mysql 进程占用的总 CPU、内存、文件句柄等,就设置 gather_total = true。对于 uptime 和 limit 的采集,gather_total 时取多个进程的最小值。
  • gather_per_pid:还是拿 mysql 举例,一个机器上可能同时运行多个 mysql 进程,如果想知道每个进程的资源占用情况,就设置 gather_per_pid = true。此时会采集每个进程的资源占用情况,并附上 pid 作为标签来区分。
  • gather_md5:计算二进制文件的 md5(binary_md5sum)以及 cmdline 的 md5(cmdline_md5sum),每个采集周期计算一次。因为涉及磁盘 IO,可能带来额外的 CPU 和 IO 开销。v0.3.61-v0.3.72 版本默认开启,v0.3.73 及以上版本默认关闭。
  • gather_more_metrics:默认情况下,procstat 插件只是采集进程数量。如果想采集进程占用的资源,就要启用 gather_more_metrics 中的项,启用哪个就额外采集哪个。

gather_more_metrics 中有一个 jvm 的采集类别。如果是 Java 进程,可以启用这个配置,会额外采集 Java 进程的 JVM 信息。

JVM 信息的采集方法是使用 jstat 命令,所以需要确保 Categraf 所在机器上有 jstat 命令,并且 Categraf 进程可以从环境变量 PATH 中找到它。对于使用 systemd 托管 Categraf 的用户要尤其注意,通常要在 systemd 的配置文件里设置类似这样的环境变量:

Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/java/jdk1.8.0_281/bin"

这样 Categraf 进程才能找到 JDK bin 目录下的 jstat 命令。

配置进程监控时的检查清单

配置完成后,可以按下面几项做自检:

  1. 匹配条件是否足够精确,是否会误匹配同名或相似进程。
  2. Java 进程是否使用 cmdline 过滤,而不是只匹配 java
  3. 多进程场景下,是需要聚合总量,还是需要按 pid 分别采集。
  4. 是否真的需要 gather_md5,以及额外 IO 开销是否可接受。
  5. 是否启用了需要的 threadsfdiouptimecpumemlimitjvm 等采集项。
  6. systemd 环境下,Categraf 是否能找到 jstat 等外部命令。

总结

进程监控是一种黑盒监控手段,可以监控进程的存活性以及进程的资源消耗情况。Categraf 是一个功能强大的 agent,包含了近百种采集插件,其中就包含了 procstat 插件,用于进程监控。本文介绍了进程监控的原理以及如何配置 Categraf 来监控进程。希望对大家有所帮助。

如果业务进程已经暴露了 /metrics 或健康检查接口,优先使用白盒指标会更清晰;如果进程没有暴露这些接口,或者需要从宿主机侧兜底确认进程是否存在、资源是否异常,procstat 这类进程监控就非常有价值。

FAQ

Q1:进程监控和 Prometheus /metrics 有什么区别? A:/metrics 是进程主动暴露内部指标,更偏白盒监控;进程监控通常从操作系统侧读取 /proc 或服务信息,更偏黑盒监控,适合作为兜底。

Q2:Java 进程为什么不建议只按进程名匹配? A:很多 Java 进程的进程名都是 java,只按名称匹配容易混淆 Kafka、Tomcat、Zabbix Java Gateway 等不同服务,使用 cmdline 更可靠。

Q3:gather_per_pid 什么时候打开? A:当同一机器上同类进程有多个,并且你需要分别观察每个 pid 的资源消耗时打开。如果只关心总消耗,用 gather_total 更简单。

延伸路径

继续看解决方案和产品对比

如果你正在做监控、可观测性或故障定位相关选型,建议从解决方案和产品对比继续往下看。

快猫星云 联系方式 快猫星云 联系方式
快猫星云 联系方式
快猫星云 联系方式
快猫星云 联系方式
快猫星云