#はじめに
皆さん、プロセス監視はどのように行なっていますか??
prometheusには、process_exporterというexporterがあるのですが、検証した結果を備忘録として残しておきます。
このexporterを実運用で使っていて、効果的に使えているという方はぜひ、教えてください!!!
#検証
検証環境は、vagrantを使用しローカルに構築し、少し古いですがUbuntu 14.04.6 LTSを使用しております。
##導入
以下の記事を参考に頑張りました。
https://qiita.com/nekoneck/items/a9deab623da277afc4be
githubのリポジトリは以下になります。
https://github.com/ncabatoff/process-exporter/blob/master/README.md
今回はdockerではなく、バイナリで導入しています。
まずは手動ダウンロードをして、展開しましょう。
$ curl -LO https://github.com/ncabatoff/process-exporter/releases/download/v0.2.11/process-exporter_0.2.11_linux_amd64.tar.gz
$ tar xvf process-exporter_0.2.11_linux_amd64.tar.gz
そうすると、以下のファイルが展開されます。
$ ls
LICENSE README.md process-exporter process-exporter_0.2.11_linux_amd64.tar.gz
##起動
process-exporterが実行ファイルになります。実際はflagをつけて、実行することになりますがどのようなオプションがあるか確認してみましょう。
$ ./process-exporter -h
Usage of ./process-exporter:
-children
if a proc is tracked, track with it any children that aren't part of their own group (default true)
-config.path string
path to YAML config file
-man
print manual
-namemapping string
comma-seperated list, alternating process name and capturing regex to apply to cmdline
-once-to-stdout
Don't bind, instead just print the metrics once to stdout and exit
-procfs string
path to read proc data from (default "/proc")
-procnames string
comma-seperated list of process names to monitor
-recheck
recheck process names on each scrape
-threads
report on per-threadname metrics as well
-web.listen-address string
Address on which to expose metrics and web interface. (default ":9256")
-web.telemetry-path string
Path under which to expose metrics. (default "/metrics")
基本的には外だししたconfigファイルを読みに行くか、-procnamesを指定して実行するかの二択かなと思われます。
でこの設定が地味によくわからないのが、今回微妙だと思った理由です。
まずは、今回対象にするプロセスをみていきましょう。postgresqlのプロセスを対象として見ます。
$ ps -ef |grep -v grep | grep postgres
postgres 21127 1 0 Apr15 ? 00:00:00 /usr/lib/postgresql/9.3/bin/postgres -D /var/lib/postgresql/9.3/main -c config_file=/etc/postgresql/9.3/main/postgresql.conf
postgres 21129 21127 0 Apr15 ? 00:00:00 postgres: checkpointer process
postgres 21130 21127 0 Apr15 ? 00:00:00 postgres: writer process
postgres 21131 21127 0 Apr15 ? 00:00:00 postgres: wal writer process
postgres 21132 21127 0 Apr15 ? 00:00:00 postgres: autovacuum launcher process
postgres 21133 21127 0 Apr15 ? 00:00:01 postgres: stats collector process
configファイルは以下のようにしました。commはgithubの説明では以下のようになっています。/proc/{pid}/statの2列目を取ってきているようですね。
# comm is the second field of /proc/<pid>/stat minus parens.
# It is the base executable name, truncated at 15 chars.
# It cannot be modified by the program, unlike exe.
- comm:
- bash
$ cat config.yaml
process_names:
- comm:
- postgresql
それでは、起動して見ましょう。
$ ./process-exporter -config.path config.yaml
2019/04/16 05:02:48 Reading metrics from /proc based on "config.yaml"
エンドポイントを叩いて見ましょう。
$ curl http://192.168.33.31:9256/metrics |grep postgresql
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 7215 100 7215 0 0 1081k 0 --:--:-- --:--:-- --:--:-- 1174k
・・・おう。取れていない。そしたら、configを少し変えてみよう。
$ cat config.yaml
process_names:
- comm:
- postgres
エンドポイントを叩いて見ます。
$ curl http://192.168.33.31:9256/metrics |grep postgres
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0namedprocess_namegroup_cpu_system_seconds_total{groupname="postgres"} 0
namedprocess_namegroup_cpu_system_seconds_total{groupname="postgres: autovacuum launcher process "} 0
namedprocess_namegroup_cpu_system_seconds_total{groupname="postgres: checkpointer process "} 0
namedprocess_namegroup_cpu_system_seconds_total{groupname="postgres: stats collector process "} 0
namedprocess_namegroup_cpu_system_seconds_total{groupname="postgres: wal writer process "} 0
namedprocess_namegroup_cpu_system_seconds_total{groupname="postgres: writer process "} 0
namedprocess_namegroup_cpu_user_seconds_total{groupname="postgres"} 0
namedprocess_namegroup_cpu_user_seconds_total{groupname="postgres: autovacuum launcher process "} 0
namedprocess_namegroup_cpu_user_seconds_total{groupname="postgres: checkpointer process "} 0
namedprocess_namegroup_cpu_user_seconds_total{groupname="postgres: stats collector process "} 0
namedprocess_namegroup_cpu_user_seconds_total{groupname="postgres: wal writer process "} 0
namedprocess_namegroup_cpu_user_seconds_total{groupname="postgres: writer process "} 0
namedprocess_namegroup_major_page_faults_total{groupname="postgres"} 0
namedprocess_namegroup_major_page_faults_total{groupname="postgres: autovacuum launcher process "} 0
namedprocess_namegroup_major_page_faults_total{groupname="postgres: checkpointer process "} 0
namedprocess_namegroup_major_page_faults_total{groupname="postgres: stats collector process "} 0
namedprocess_namegroup_major_page_faults_total{groupname="postgres: wal writer process "} 0
namedprocess_namegroup_major_page_faults_total{groupname="postgres: writer process "} 0
namedprocess_namegroup_memory_bytes{groupname="postgres",memtype="resident"} 1.2640256e+07
namedprocess_namegroup_memory_bytes{groupname="postgres",memtype="virtual"} 2.52489728e+08
namedprocess_namegroup_memory_bytes{groupname="postgres: autovacuum launcher process ",memtype="resident"} 2.822144e+06
namedprocess_namegroup_memory_bytes{groupname="postgres: autovacuum launcher process ",memtype="virtual"} 2.5337856e+08
namedprocess_namegroup_memory_bytes{groupname="postgres: checkpointer process ",memtype="resident"} 3.244032e+06
namedprocess_namegroup_memory_bytes{groupname="postgres: checkpointer process ",memtype="virtual"} 2.52628992e+08
namedprocess_namegroup_memory_bytes{groupname="postgres: stats collector process ",memtype="resident"} 1.794048e+06
namedprocess_namegroup_memory_bytes{groupname="postgres: stats collector process ",memtype="virtual"} 1.04841216e+08
namedprocess_namegroup_memory_bytes{groupname="postgres: wal writer process ",memtype="resident"} 1.695744e+06
namedprocess_namegroup_memory_bytes{groupname="postgres: wal writer process ",memtype="virtual"} 2.52489728e+08
namedprocess_namegroup_memory_bytes{groupname="postgres: writer process ",memtype="resident"} 2.506752e+06
namedprocess_namegroup_memory_bytes{groupname="postgres: writer process ",memtype="virtual"} 2.52489728e+08
namedprocess_namegroup_minor_page_faults_total{groupname="postgres"} 0
namedprocess_namegroup_minor_page_faults_total{groupname="postgres: autovacuum launcher process "} 0
namedprocess_namegroup_minor_page_faults_total{groupname="postgres: checkpointer process "} 0
namedprocess_namegroup_minor_page_faults_total{groupname="postgres: stats collector process "} 0
namedprocess_namegroup_minor_page_faults_total{groupname="postgres: wal writer process "} 0
namedprocess_namegroup_minor_page_faults_total{groupname="postgres: writer process "} 0
namedprocess_namegroup_num_procs{groupname="postgres"} 1
namedprocess_namegroup_num_procs{groupname="postgres: autovacuum launcher process "} 1
namedprocess_namegroup_num_procs{groupname="postgres: checkpointer process "} 1
namedprocess_namegroup_num_procs{groupname="postgres: stats collector process "} 1
namedprocess_namegroup_num_procs{groupname="postgres: wal writer process "} 1
namedprocess_namegroup_num_procs{groupname="postgres: writer process "} 1
namedprocess_namegroup_num_threads{groupname="postgres"} 1
namedprocess_namegroup_num_threads{groupname="postgres: autovacuum launcher process "} 1
namedprocess_namegroup_num_threads{groupname="postgres: checkpointer process "} 1
namedprocess_namegroup_num_threads{groupname="postgres: stats collector process "} 1
namedprocess_namegroup_num_threads{groupname="postgres: wal writer process "} 1
namedprocess_namegroup_num_threads{groupname="postgres: writer process "} 1
namedprocess_namegroup_oldest_start_time_seconds{groupname="postgres"} 1.55536655e+09
namedprocess_namegroup_oldest_start_time_seconds{groupname="postgres: autovacuum launcher process "} 1.55536655e+09
namedprocess_namegroup_oldest_start_time_seconds{groupname="postgres: checkpointer process "} 1.55536655e+09
namedprocess_namegroup_oldest_start_time_seconds{groupname="postgres: stats collector process "} 1.55536655e+09
namedprocess_namegroup_oldest_start_time_seconds{groupname="postgres: wal writer process "} 1.55536655e+09
namedprocess_namegroup_oldest_start_time_seconds{groupname="postgres: writer process "} 1.55536655e+09
namedprocess_namegroup_open_filedesc{groupname="postgres"} 0
namedprocess_namegroup_open_filedesc{groupname="postgres: autovacuum launcher process "} 0
namedprocess_namegroup_open_filedesc{groupname="postgres: checkpointer process "} 0
namedprocess_namegroup_open_filedesc{groupname="postgres: stats collector process "} 0
namedprocess_namegroup_open_filedesc{groupname="postgres: wal writer process "} 0
namedprocess_namegroup_open_filedesc{groupname="postgres: writer process "} 0
namedprocess_namegroup_read_bytes_total{groupname="postgres"} 0
namedprocess_namegroup_read_bytes_total{groupname="postgres: autovacuum launcher process "} 0
namedprocess_namegroup_read_bytes_total{groupname="postgres: checkpointer process "} 0
namedprocess_namegroup_read_bytes_total{groupname="postgres: stats collector process "} 0
namedprocess_namegroup_read_bytes_total{groupname="postgres: wal writer process "} 0
namedprocess_namegroup_read_bytes_total{groupname="postgres: writer process "} 0
namedprocess_namegroup_states{groupname="postgres",state="Other"} 0
namedprocess_namegroup_states{groupname="postgres",state="Running"} 0
namedprocess_namegroup_states{groupname="postgres",state="Sleeping"} 1
namedprocess_namegroup_states{groupname="postgres",state="Waiting"} 0
namedprocess_namegroup_states{groupname="postgres",state="Zombie"} 0
namedprocess_namegroup_states{groupname="postgres: autovacuum launcher process ",state="Other"} 0
namedprocess_namegroup_states{groupname="postgres: autovacuum launcher process ",state="Running"} 0
namedprocess_namegroup_states{groupname="postgres: autovacuum launcher process ",state="Sleeping"} 1
namedprocess_namegroup_states{groupname="postgres: autovacuum launcher process ",state="Waiting"} 0
namedprocess_namegroup_states{groupname="postgres: autovacuum launcher process ",state="Zombie"} 0
namedprocess_namegroup_states{groupname="postgres: checkpointer process ",state="Other"} 0
namedprocess_namegroup_states{groupname="postgres: checkpointer process ",state="Running"} 0
namedprocess_namegroup_states{groupname="postgres: checkpointer process ",state="Sleeping"} 1
namedprocess_namegroup_states{groupname="postgres: checkpointer process ",state="Waiting"} 0
namedprocess_namegroup_states{groupname="postgres: checkpointer process ",state="Zombie"} 0
namedprocess_namegroup_states{groupname="postgres: stats collector process ",state="Other"} 0
namedprocess_namegroup_states{groupname="postgres: stats collector process ",state="Running"} 0
namedprocess_namegroup_states{groupname="postgres: stats collector process ",state="Sleeping"} 1
namedprocess_namegroup_states{groupname="postgres: stats collector process ",state="Waiting"} 0
namedprocess_namegroup_states{groupname="postgres: stats collector process ",state="Zombie"} 0
namedprocess_namegroup_states{groupname="postgres: wal writer process ",state="Other"} 0
namedprocess_namegroup_states{groupname="postgres: wal writer process ",state="Running"} 0
namedprocess_namegroup_states{groupname="postgres: wal writer process ",state="Sleeping"} 1
namedprocess_namegroup_states{groupname="postgres: wal writer process ",state="Waiting"} 0
namedprocess_namegroup_states{groupname="postgres: wal writer process ",state="Zombie"} 0
namedprocess_namegroup_states{groupname="postgres: writer process ",state="Other"} 0
namedprocess_namegroup_states{groupname="postgres: writer process ",state="Running"} 0
namedprocess_namegroup_states{groupname="postgres: writer process ",state="Sleeping"} 1
namedprocess_namegroup_states{groupname="postgres: writer process ",state="Waiting"} 0
namedprocess_namegroup_states{groupname="postgres: writer process ",state="Zombie"} 0
namedprocess_namegroup_worst_fd_ratio{groupname="postgres"} 0
100 18856 100 18856 0 0 1769k 0 --:--:-- --:--:-- --:--:-- 1841k
namedprocess_namegroup_worst_fd_ratio{groupname="postgres: autovacuum launcher process "} 0
namedprocess_namegroup_worst_fd_ratio{groupname="postgres: checkpointer process "} 0
namedprocess_namegroup_worst_fd_ratio{groupname="postgres: stats collector process "} 0
namedprocess_namegroup_worst_fd_ratio{groupname="postgres: wal writer process "} 0
namedprocess_namegroup_worst_fd_ratio{groupname="postgres: writer process "} 0
namedprocess_namegroup_write_bytes_total{groupname="postgres"} 0
namedprocess_namegroup_write_bytes_total{groupname="postgres: autovacuum launcher process "} 0
namedprocess_namegroup_write_bytes_total{groupname="postgres: checkpointer process "} 0
namedprocess_namegroup_write_bytes_total{groupname="postgres: stats collector process "} 0
namedprocess_namegroup_write_bytes_total{groupname="postgres: wal writer process "} 0
namedprocess_namegroup_write_bytes_total{groupname="postgres: writer process "} 0
おお!なんか取れましたね。どうやら、postgresql系のパラメータはgroupnameというパラメータでそれぞれ分けられているようですね。
これだとまあ、使えそう。
続いて、-procnamesオプションを指定して起動して見ましょう。
$ ./process-exporter -procnames postgres
2019/04/16 05:15:46 Reading metrics from /proc for procnames: [postgres]
エンドポイントを叩いて見ます。
$ curl http://192.168.33.31:9256/metrics |grep postgres
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0namedprocess_namegroup_cpu_system_seconds_total{groupname="postgres"} 0.010000000000000009
namedprocess_namegroup_cpu_user_seconds_total{groupname="postgres"} 0
namedprocess_namegroup_major_page_faults_total{groupname="postgres"} 0
namedprocess_namegroup_memory_bytes{groupname="postgres",memtype="resident"} 2.4702976e+07
namedprocess_namegroup_memory_bytes{groupname="postgres",memtype="virtual"} 1.368317952e+09
namedprocess_namegroup_minor_page_faults_total{groupname="postgres"} 61
namedprocess_namegroup_num_procs{groupname="postgres"} 6
namedprocess_namegroup_num_threads{groupname="postgres"} 6
namedprocess_namegroup_oldest_start_time_seconds{groupname="postgres"} 1.55536655e+09
namedprocess_namegroup_open_filedesc{groupname="postgres"} 0
namedprocess_namegroup_read_bytes_total{groupname="postgres"} 0
namedprocess_namegroup_states{groupname="postgres",state="Other"} 0
namedprocess_namegroup_states{groupname="postgres",state="Running"} 0
100 10261 100 10261 0 0 1126k 0 --:--:-- --:--:-- --:--:-- 1252k
namedprocess_namegroup_states{groupname="postgres",state="Sleeping"} 6
namedprocess_namegroup_states{groupname="postgres",state="Waiting"} 0
namedprocess_namegroup_states{groupname="postgres",state="Zombie"} 0
namedprocess_namegroup_worst_fd_ratio{groupname="postgres"} 0
namedprocess_namegroup_write_bytes_total{groupname="postgres"} 0
お。出力が変わりました。どうやら、これは先ほど出力されていたものがまとめられて表示されているようです。
groupnameの表示名を変えたければ、以下のようにconfigを書き直します。
$ cat config.yaml
process_names:
- name: aaaaaa
comm:
- 'postgres'
またまた、エンドポイントをたたいてみます。
$ curl http://192.168.33.31:9256/metrics |grep namedprocess_namegroup_num_procs
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0# HELP namedprocess_namegroup_num_procs number of processes in this group
# TYPE namedprocess_namegroup_num_procs gauge
namedprocess_namegroup_num_procs{groupname="aaaaaa"} 6
100 10009 100 10009 0 0 1094k 0 --:--:-- --:--:-- --:--:-- 1221k
さてここからです。
exeというselecorを使ってみます。ちなみにgithubの説明では、以下のようにあります。
# exe is argv[0]. If no slashes, only basename of argv[0] need match.
# If exe contains slashes, argv[0] must match exactly.
- exe:
- postgres
- /usr/local/bin/prometheus
ということで、以下のようにconfigを設定してみました。プログラム名を取ってくるイメージですね。
process_names:
- name: postgres master process
exe:
- '/usr/lib/postgresql/9.3/bin/postgres'
エンドポイントをたたいてみる。あれ?6つ取れている。子プロセスもカウントされるのかな。そうするとcommとの違いがよくわからない。。
$ curl http://192.168.33.31:9256/metrics |grep namedprocess_namegroup_num_procs
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0# HELP namedprocess_namegroup_num_procs number of processes in this group
# TYPE namedprocess_namegroup_num_procs gauge
namedprocess_namegroup_num_procs{groupname="postgres process"} 6
100 10180 100 10180 0 0 1145k 0 --:--:-- --:--:-- --:--:-- 1242k
最後、cmdlineについて。これは正規表現が使えまっせというもの。
# cmdline is a list of regexps applied to argv.
# Each must match, and any captures are added to the .Matches map.
- name: "{{.ExeFull}}:{{.Matches.Cfgfile}}"
exe:
- /usr/local/bin/process-exporter
cmdline:
- -config.path\s+(?P<Cfgfile>\S+)
こんな感じで設定しました。
process_names:
# - name: postgres process
- exe:
- '/usr/lib/postgresql/9.3/bin/postgres'
cmdline:
- .*postgresql.conf
エンドポイントをたたいてみます。以下見るとわかるのですが、nameをしてしなければ、デフォルトでは、Commの値で名前が入ります。
$ curl http://192.168.33.31:9256/metrics |grep namedprocess_namegroup_num_procs
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0# HELP namedprocess_namegroup_num_procs number of processes in this group
# TYPE namedprocess_namegroup_num_procs gauge
namedprocess_namegroup_num_procs{groupname="postgres"} 6
100 10239 100 10239 0 0 1225k 0 --:--:-- --:--:-- --:--:-- 1249k
んー変わらないですね。
結論
使えそうなメトリクスとしては、namedprocess_namegroup_num_procs、namedprocess_namegroup_statesかなと思いますが、どちらもグルーピングされたもののカウントが表示されるだけになります。
プロセスの全死などの検知をしたい場合には使えるというところでしょうか。
例えば、特定のjavaのプロセスを監視したい場合などは全て、javaというグルーピングになると思われるため、厳しいかもしれないです。
もし、使い方間違っているなど、ご指摘ありましたら教えてください!
2019/5/16 追記
この記事を投稿後、もう少し触っていたら、異なる使い方を見つけたので、追記します。
configファイルにcommとcmdlineの合わせ技を使うと異なるプロセスidを持っていれば、異なるプロセスとして認識させることができました。
サンプルでportをリッスンするjavaアプリケーションを作り、起動させておきます。
$ ps -ef |grep java
vagrant 4136 4060 0 05:14 pts/1 00:00:00 java -jar Sample1.jar 8080
vagrant 4148 4060 1 05:14 pts/1 00:00:00 java -jar Sample2.jar 8081
vagrant 4161 4060 0 05:14 pts/1 00:00:00 grep --color=auto java
以下configファイルとなります。
$ cat config.yaml
process_names:
- name: test1
comm:
- java
cmdline:
- Sample1.jar
- name: test2
comm:
- java
cmdline:
- Sample2.jar
それぞれの説明をします。
name でgroupnameを指定します。今回だと、test1,test2となります。
commで/proc/{pid}/stateの2列目にある文字列を指定します。
これだけだと、javaという文字列全てで引っかかってしまうとため、cmdlineを使用します。このパラメータでは引っ掛ける文字列を指定します。正規表現も使えます。ここにはプロセスを一意に判定できるような文字列を指定すると良いと思います。(例えばjarファイル名など)
エンドポイントを叩いてみましょう。
$ curl http://192.168.33.31:9256/metrics | grep namedprocess_namegroup_num_procs
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0# HELP namedprocess_namegroup_num_procs number of processes in this group
# TYPE namedprocess_namegroup_num_procs gauge
namedprocess_namegroup_num_procs{groupname="test1"} 1
namedprocess_namegroup_num_procs{groupname="test2"} 1
100 11500 100 11500 0 0 1169k 0 --:--:-- --:--:-- --:--:-- 1247k
javaのプロセスを分けて取得することができました。
※注意点
postgresのような親プロセスから子プロセスがフォークされるようなものでは、子プロセスでは、この方法で判別することができますが、親プロセスに対してはこの方法が効かないです。(子プロセスの分までカウントされる。)