RHEL7の性能情報取得ツール「njmon」について(前編：データ取得まで)


# 本記事の記載内容

1. nmonとは
2. nmonの後継であるnjmonとは
3. nmonではなくnjmonを使うべき理由
4. njmonのセットアップ方法
5. njmonの動作確認 〜データの取得〜

# 1. nmonとは

##### 概要

nmon(Nigel's performance Monitor)とは、LinuxやAIX等のOS上に常駐し、定期的にOSのリソース情報(CPU/Memoroy/DiskIO/NetIO)をcsvファイルに出力するツール。
出力されたcsvファイルを、nmon analyzerと呼ばれるクライアントツール（実態はExcelマクロ）に読み込ませる事で、OSのリソース情報を可視化（グラフ化）してくれる。

##### 詳細については、以下リンク先ご参照

- nmon for Linux

http://nmon.sourceforge.net/pmwiki.php

- IBM Power Systems JPN Wiki >‎ IBM Power Systems >‎ AIX 技術情報 >‎ nmon、nmon analyser

https://www.ibm.com/developerworks/community/wikis/home?lang=en#!/wiki/W8214c473fef0_444f_886a_cd015ca34c89/page/nmon%E3%80%81nmon%20analyser

> nmonは、CPU、メモリー、ディスクI/O、ネットワーク等、システム・リソースの使用状況をリアルタイム（フォアグラウンド）で表示したり、 ファイルに出力することができるパフォーマンス分析ツールです。
システム・リソースの使用率やピーク特性、システムのボトルネックがどこにあるかを把握するのに役立ちます。

# 2. nmonの後継であるnjmonとは

>http://nmon.sourceforge.net/pmwiki.php?n=Site.Njmon
>> njmon is like nmon but collects a lot more performance and configuration data and outputs in JSON format ready for immediate uploading to a performance stats database for near real-time graphing by online graphing tools. There is a version of njmon for AIX and another njmon for Linux.
>> ・ njmon for Linux the performance stats come mostly from /proc filesystem and system calls.
>> 　　　 Roughly: 130 stats - possible future stats include: Fibre-Channel SAN, GPFS, GPU and Process stats.

njmonはnmonに似ているが、より多くのパフォーマンス統計情報と構成情報をJSON形式で収集し、準リアルタイムに統計データベースにアップロードし、オンラインのグラフ作成ツールによりグラフ化する事が可能。
nmonと同様、AIX用とLinux用のnjmonが存在する。
njmonはパフォーマンス統計情報の大部分を、OS上の/procファイルシステム及び、システムコールにより取得している。
約130のパフォーマンス統計情報を取得している。（FC-SAN、GPFS、GPUやプロセスの統計情報も含まれる）

# 3. nmonではなくnjmonを使うべき理由

##### ・ nmonとnjmonの比較
 
|  | nmon | njmon |
|:---:|:---:|:---:|
| 対象OS | AIX、Linux | AIX、Linux | 
|性能情報取得項目数| 確認中 | 約130 |
|データフォーマット| csv | JSON |
|グラフ化方法| ・nmonchart <br> ・nmon_analyzer <br> (Excelマクロ)|・InfluxDB + Grafana <br> ・Splunk <br> ・ELK Logstash <br> ・Kafka <br> ・Prometheus <br> ・・・  | 

##### ・nmonではなくnjmonを使うべき理由

1. nmonのデータフォーマットはcsv形式であり、プログラムで加工しにくいが、njmonはJSON形式であり利便性が高い
2. nmonの場合、取得する統計データは限定的だが、njmonの場合100以上の統計情報を取得可能
3. njmonの場合、準リアルタイムに統計収集用DBに取得したデータを格納する事が可能(拡張性が高い)
4. njmonの場合、ツールを利用する事で取得したデータを動的にグラフ化する事が可能
5. RHEL7の空きメモリ容量の正確な値(MemAvailable)は、nmonでは取得できないが(計算が必要)、njmonでは取得可能



# 4. njmonのセットアップ方法

### 4-0. 環境前提（njmon導入環境情報）

```console
[root@localhost /]# cat /etc/redhat-release 
Red Hat Enterprise Linux Server release 7.6 (Maipo)
[root@localhost /]#
[root@localhost /]# uname -a
Linux localhost.localdomain 3.10.0-957.1.3.el7.x86_64 #1 SMP Thu Nov 15 17:36:42 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
[root@localhost /]#
```

### 4-1. njmonのモジュールをダウンロード

>http://nmon.sourceforge.net/pmwiki.php?n=Site.Njmon
┗ njmon for Linux：njmon_linux_binaries_v22.zip
※ここではコンパイル済バイナリをダウンロード

### 4-2. njmon導入先の環境に転送 & zipの展開

```console
[root@localhost njmon]# ls -l /work/njmon/
合計 260
-rw-r--r-- 1 root root 262323  5月  5 16:03 njmon_linux_binaries_v22.zip
[root@localhost njmon]#
[root@localhost njmon]# unzip njmon_linux_binaries_v22.zip
Archive:  njmon_linux_binaries_v22.zip
  inflating: njmon_linux_ppc_RHEL75_v22  
  inflating: njmon_linux_ppc_ubuntu18_v22  
  inflating: njmon_linux_x86_rhel75_v22  
  inflating: njmon_linux_x86_ubuntu18_v22  
[root@localhost njmon]# 
[root@localhost njmon]# ls -ltr 
合計 1020
-rw-r--r-- 1 root root 277232  4月  1 23:29 njmon_linux_ppc_ubuntu18_v22
-rw-r--r-- 1 root root 192008  4月  1 23:30 njmon_linux_x86_ubuntu18_v22
-rw-r--r-- 1 root root 138192  4月  1 23:32 njmon_linux_x86_rhel75_v22
-rw-r--r-- 1 root root 166624  4月  1 23:38 njmon_linux_ppc_RHEL75_v22
-rw-r--r-- 1 root root 262323  5月  5 16:03 njmon_linux_binaries_v22.zip
[root@localhost njmon]#
```
備考
`LinuxPPCは、PowerPCを用いたプラットフォーム向けに、有志が集まって最初に作られたLinuxディストリビューション`
`AWSや仮想環境のRHEL上で利用する場合は、 「njmon_linux_x86_rhel75_vXX」を利用しておけば良い`



### 4-3. njmonモジュールの権限の変更

```console
[root@localhost njmon]# chmod u+x ./njmon_linux_x86_rhel75_v22
[root@localhost njmon]#
[root@localhost njmon]# ls -l ./njmon_linux_x86_rhel75_v22
-rwxr--r-- 1 root root 138192  4月  1 23:32 ./njmon_linux_x86_rhel75_v22
[root@localhost njmon]#
```

以上でセットアップは完了

# 5. njmonの動作確認 〜データの取得〜


##### njmonのオプション一覧の表示

```console:helpコマンドの実行
[root@localhost njmon]# ./njmon_linux_x86_rhel75_v22 -h
./njmon_linux_x86_rhel75_v22: help information. Version:22@31/03/2019

- Performance stats collector outputing JSON format. Default is stdout
- Core syntax:     ./njmon_linux_x86_rhel75_v22 -s seconds -c count
- JSON style:      -M  (default) or older style -S or -O
- File output:     -m directory -f
- njmon collector output: -i host -p port -X secret
- Other options: -?

	-s seconds : seconds between snapshots of data (default 60 seconds)
	-c count   : number of snapshots (default forever)

	-S         : Single level output format - section names form part of the value names
	-M         : Multiple level output format - section & subsection names (default)
	-O         : Old Multiple level output format - like -M but identity before samples

	-m directory : Program will cd to the directory before output
	-f         : Output to file (not stdout) to two files below
	           : Data:   hostname_<year><month><day>_<hour><minutes>.json
	           : Errors: hostname_<year><month><day>_<hour><minutes>.err
	-k         : Read /tmp/njmon.pid for a running njmon PID & if found running then this copy exits
	-?         : This output and stop
	-d         : Switch on debugging
Push data to collector: add -h hostname -p port
	-i ip      : IP address or hostname of the njmon central collector
	-p port    : port number on collector host
	-X         : Set the remote collector secret or use shell NJMON_SECRET

Examples:
    1 Every 5 mins all day
	/home/nag/njmon -s 300 -c 288 -f -m /home/perf
    2 Piping to data handler using half a day
	/home/nag/njmon -s 30 -c 1440 | myprog
    3 Use the defaults (-s 60 forever) and save to a file 
	./njmon > my_server_today.json
    4 Crontab entry
	0 4 * * * /home/nag/njmon -s 300 -c 288 -f -m /home/perf
    5 Crontab - hourly check/restart remote njmon, pipe stats back & insert into local DB
	* 0 * * * /usr/bin/ssh nigel@server /usr/lbin/njmon -s 300 -c 288 | /lbin/injector
    6 Crontab - for pumping data to the njmon central collector
	* 0 * * * /usr/local/bin/njmon -s 300 -c 288 -i admin.acme.com -p 8181 -X SECRET42 

[root@localhost njmon]#
```

##### オプション一覧の解説

| オプション | 説明 |
|:---|:---|
| -s seconds | データの取得間隔の指定。デフォルトは60秒。 |
| -c count | データの取得回数の指定。デフォルトは永遠に取得。 |
| -S | 【JSONの形式指定】　※詳細については後述 <br> 単一レベルの出力フォーマット。セクション名は値の名前を結合し生成される。 <br> 例："identity_hostname" : "localhost"|
| -M | 【JSONの形式指定】　※詳細については後述 <br> マルチレベル出力フォーマット。セクションとサブセクションの名前で対象を指定（デフォルト） <br> 例："identity": { "hostname" : "localhost" }|
| -O | 【JSONの形式指定】　※詳細については後述 <br> 旧マルチレベル出力フォーマット。-M指定とほぼ同等だが、sampleセクションの前にidentityのセクション(OSの基本情報)を1度だけ出力し、その後はidentityセクションは出力しない。(-Mの場合は、データ出力の都度、identityセクションが出力される)|
| -m directory | JSONファイル出力ディレクトリの指定。（プログラム内でcdしファイルを出力）|
| -f | データを標準出力ではなく、ファイルに出力させる指定。出力ファイル名は以下となる。 <br> Data:   hostname&#95;< year >< month >< day >&#95;< hour >< minutes >.json <br> Errors: hostname&#95;< year >< month >< day >&#95;< hour >< minutes >.err |
| -k | 実行中のnmonのPIDについては/tmp/njmon.pidを読み、もし実行中であればコピーを終了する。（※挙動未確認）|
| -? | njmonオプションのヘルプを表示（-hと同じ出力結果）|
| -d | デバッグモードに変更（※挙動未確認）|
| -h hostname -p port | njmonのデータを転送する先のホスト名とポート番号を指定。|
| -i ip -p port | njmonのデータを転送する先のIPアドレスとポート番号を指定。|
| -X | (-h -i -p と共に利用)リモートコレクターに送信する際のシークレットトークンを指定。（パスワードのようなもの）njmonとnjmon_collector間で共有され、接続要求時の暗号化されたリクエストにこのシークレットトークンも含まれる。　|

##### 起動引数例

```console:間隔：5分(300秒)、期間：1日(86400秒÷間隔(300秒)=288)、データ出力先：/LOG/njmon/
[root@localhost njmon]# /work/njmon/njmon_linux_x86_rhel75_v22 -s 300 -c 288 -f -m /LOG/njmon/
[root@localhost njmon]# ls -tlr /LOG/njmon/
-rw-r--r-- 1 root root      0  5月  5 17:38 localhost.localdomain_20190505_1738.err
-rw-r--r-- 1 root root  38112  5月  5 17:49 localhost_20190505_1738.json
[root@localhost njmon]# 
```


### JSONの出力フォーマット詳細(-S/-M/-Oオプションの違い)

- JSONの出力フォーマットとして-Sを指定した場合

```console:JSONの出力フォーマットとして-Sを指定した場合
[
  {
          # 1回目の出力
          "identity_hostname": "localhost.localdomain",
          "identity_shorthostname": "localhost",
          〜中略〜
          "timestamp_datetime": "2019-05-05T18:19:26",
          "timestamp_UTC": "2019-05-05T09:19:26",
          "timestamp_snapshot_seconds": 10,
          "timestamp_snapshot_maxloops": 2,
          〜中略〜
          "MemAvailable_MemAvailable": 1619884,
          〜中略〜
  },
  {
          # 2回目の出力
          "identity_hostname": "localhost.localdomain",
          "identity_shorthostname": "localhost",
          ・・・略・・・
          "timestamp_datetime": "2019-05-05T18:19:36",
          "timestamp_UTC": "2019-05-05T09:19:36",
          "timestamp_snapshot_seconds": 10,
          "timestamp_snapshot_maxloops": 2,
          ・・・略・・・
          "MemAvailable_MemAvailable": 1619760,
          ・・・略・・・
  }
]
```

- JSONの出力フォーマットとして-Mを指定した場合(デフォルト)

```console:JSONの出力フォーマットとして-Mを指定した場合(デフォルト)
{
  "samples": [
  {
  	# 1回目の出力
     "timestamp": {
          "datetime": "2019-05-05T18:25:51",
          "UTC": "2019-05-05T09:25:51",
          "snapshot_seconds": 10,
          "snapshot_maxloops": 2,
          "snapshot_loop": 0
     },
     "identity": {
          "hostname": "localhost.localdomain",
          "shorthostname": "localhost",
          ・・・略・・・
       },
          ・・・略・・・
     "proc_meminfo": {
          "MemTotal": 1882300,
          "MemFree": 1502784,
          "MemAvailable": 1618616,
          ・・・略・・・
     },
          ・・・略・・・
  },
  {
  	 # 2回目の出力
     "timestamp": {
          "datetime": "2019-05-05T18:26:01",
          "UTC": "2019-05-05T09:26:01",
          "snapshot_seconds": 10,
          "snapshot_maxloops": 2,
          "snapshot_loop": 1
     },
     "identity": {
          "hostname": "localhost.localdomain",
          "shorthostname": "localhost",
          ・・・略・・・
     },
          ・・・略・・・
     "proc_meminfo": {
          "MemTotal": 1882300,
          "MemFree": 1502768,
          "MemAvailable": 1618616,
          ・・・略・・・
     },
          ・・・略・・・     
  }
 ]
}
```

- JSONの出力フォーマットとして-Oを指定した場合

```console:JSONの出力フォーマットとして-Oを指定した場合
{
     # identityのセクションは最初に1度だけ出力
     "identity": {
          "hostname": "localhost.localdomain",
          "shorthostname": "localhost",
          ・・・略・・・
     },
  "samples": [
  {
     # 1回目の出力
     "timestamp": {
          "datetime": "2019-05-05T18:11:49",
          "UTC": "2019-05-05T09:11:49",
          "snapshot_seconds": 10,
          "snapshot_maxloops": 2,
          "snapshot_loop": 0
     },
          ・・・略・・・
     "proc_meminfo": {
          "MemTotal": 1882300,
          "MemFree": 1502824,
          "MemAvailable": 1618596,
          ・・・略・・・
     },
          ・・・略・・・
  },
  {
     # 2回目の出力
     "timestamp": {
          "datetime": "2019-05-05T18:11:59",
          "UTC": "2019-05-05T09:11:59",
          "snapshot_seconds": 10,
          "snapshot_maxloops": 2,
          "snapshot_loop": 1
     },
          ・・・略・・・
     "proc_meminfo": {
          "MemTotal": 1882300,
          "MemFree": 1502948,
          "MemAvailable": 1618736,
          ・・・略・・・
     },
          ・・・略・・・
  }
 ]
}
```

結論：特に何も指定しない（デフォルト：-M）で良いと考える。

取得したデータのグラフ化については、別記事でまとめます。