はてな村定点観測所

運動、瞑想、睡眠、野菜350g

インフラエンジニアに便利な負荷計測コマンド【基礎編】

   

この記事は何?

この記事はインフラエンジニアが身につけるべき負荷計測コマンドについて解説しています。サーバーやアプリケーションの応答が遅延するなど本来のパフォーマンスを発揮できない時にインフラエンジニアに調査が依頼されることは多いでしょう。

大前提として日常的な負荷計測は手動コマンドで行うべきではありません。Mackerel / Zabbix / CloudWatchなどの監視ツールに委ねるべきです。しかし様々な状況や目的から手動で負荷計測したいケースも出てくるでしょう。そのような時に役立つコマンドを解説していきます。

なお、当記事はLinuxに関して初歩的なオペレーションを行ったことがある層を前提にしています。そのためtop / ps / uptime / free / df / netstatなどのコマンドは解説しません。初歩的なオペレーションからワンランクアップしたいエンジニアにお薦めです。

vmstat

このコマンドは何?

vmstatはシステム全体の負荷を出力するコマンドです。CentOSやDebian / UbuntuやopenSUSEなど多くの環境では標準でvmstatコマンドがインストールされています。細かなプロセス単位のボトルネック特定までは使えませんが、システム全体でどのような負荷が掛かっているかを簡単に知ることができます。

vmstatのインストール方法

CentOSやDebian / UbuntuやopenSUSEではvmstatコマンドは標準でインストールされています。

vmstaの出力

vmstatを実行してみましょう。vmstat 5で5秒間隔のリソースの使用状況を確認できます。

$ vmstat 5

f:id:netcraft3:20190706182523p:plain

第1引数は何秒間隔で行うかの数値設定ですが、第2引数で実行回数を指定できます。vmstat 5 10で5秒間隔で10回実行します。第2引数を指定しない場合は永続的に実行されます。何もオプションを指定しない場合は1回のみ実行されます。

各項目の意味

それぞれの項目の意味は以下の通りです。

項目 意味
r 実行待ち状態にあるプロセス数の合計
b ディスクI/Oやページングなどリソース確保のためにブロックされている状態のプロセス数の合計
swpd 使用中の仮想メモリ(スワップ)量
free 空きメモリ量
buff バッファメモリ量
cache キャッシュメモリ量
si スワップメモリからメモリに展開したデータ量(スワップ・イン)
so メモリからスワップメモリに書き込んだデータ量(スワップ・アウト)
bi ディスクなどブロックデバイスから読み込んだブロック数
bo ディスクなどブロックデバイスに書き込んだブロック数
in 割り込み回数
cs コンテキスト・スイッチの回数
us CPUのカーネルコード以外の実行に費やした時間の割合
sy CPUのカーネルコードの実行に費やした時間の割合
id CPUのアイドル状態の時間の割合
wa CPUのデータの入出力待ちに費やした時間の割合
st 仮想マシン(ゲストOS)がホストOSに割り当て要求をしたがしたが割り当てられなかったCPU使用率

メモリ量の表示単位を変更したい

デフォルトではメモリ量がキロバイト単位になっていますので、メガバイトに表示修正したい場合は、vmstat -SMオプションを使うと良いでしょう。

$ vmstat -SM

f:id:netcraft3:20190706182614p:plain

-Sは単位を指定するオプションであり、mは1,000,000、Mは1,048,576、kは1,000、Kは1,024バイト単位となります。オプション指定なしの場合は-SKと同値です。

メモリの使用量の情報が見たい

vmstat -mでメモリの詳細情報を見ることができます。

$ vmstat -m

f:id:netcraft3:20190708140401p:plain:w300

各ディスク別の統計情報を見たい

vmstat -dでディスク別の統計情報を表示します。

$ vmstat -d

f:id:netcraft3:20190708135942p:plain

ディスク全体の統計情報を見たい

ディスク全体の統計情報を見たい場合はvmstat -Dオプションを使うと良いでしょう。

$ vmstat -D

f:id:netcraft3:20190708140044p:plain:w300

タイムスタンプ情報を付与したい

vmstatの出力結果には標準ではタイムスタンプ情報は付与されません。後からいつ出力したかを辿れるようにタイムスタンプ情報を付与したい場合もあるでしょう。タイムスタンプ情報を付与するには以下の2つ方法があります。

1番目の方法はvmstat -tオプションを付与する方法です。一番右側にタイムスタンプが表示されます。

f:id:netcraft3:20190706182836p:plain

あるいはvmstatにパイプで| awk '{print strftime("%F %T ") $0}'を付与すると良いでしょう。

$ vmstat 10 | awk '{print strftime("%F %T ") $0}'

f:id:netcraft3:20190706182905p:plain

sar

このコマンドは何?

sarコマンドはvmstatコマンドと似ていますが、このコマンドをインストールするだけで自動的に過去の統計情報を保存してくれます。例えば2日前にどんな負荷がシステムに掛かっていたのかを調査したい場合などsarコマンドはとても役に立ちます。

導入方法

sarコマンドの導入にあたってはsysstatというパッケージが必要です。sysstatはOS標準では付属していない場合が多くインストールが必要です。

導入方法:CentOSの場合

CentOSの場合は以下のコマンドでインストールできます。

$ sudo sudo yum install sysstat

導入方法:Debian / Ubuntuの場合

Debian / Ubuntuの場合は以下のコマンドでインストールできます。

$ sudo sudo apt install sysstat

Debian / Ubuntuの場合はインストール直後はsysstatは無効になっています。/etc/default/sysstatファイルを開き、ENABLED="false"になっている箇所をtrueに変えましょう。

$ sudo vi /etc/default/sysstat
ENABLED="true"

導入方法:openSUSEの場合(※注意が必要)

openSUSEの場合は以下のコマンドでインストールできます。

$ sudo sudo zypper in sysstat

ただ残念なことにopenSUSE15.0や15.1ではsysstatが必要としているgettextパッケージの依存関係に問題があるようです。

f:id:netcraft3:20190706182933p:plain

解決方法1を選択して標準でインストールされているgettext-runtime-miniのパッケージを削除すればsysstatをインストールすることができます。

インストール直後

インストールした直後は統計ログが蓄積されておらず、コマンドを実行しても以下のようなエラーになります。コーヒーでも飲みながログが溜まるまで待ちましょう。

$ sar
/var/log/sa/sa03 を開けません: そのようなファイルやディレクトリはありません

10分間以上待っても統計データが出力されない場合は、導入に問題があった可能性があります。設定を確認しましょう。

ちなみにこのsa03というのは日付に対応しています。7月3日ならば/var/log/sa/sa03というファイルに統計情報が蓄積されます。このようにしてデフォルトで28日前までの統計データを辿ることができます。

オプションなしでsarを実行した場合、あるいはsar -uを実行した場合は過去のCPU使用率を出力することができます。

f:id:netcraft3:20190708221248p:plain

各項目の意味

項目 意味
%user CPUのうちカーネル以外の処理に使われた時間の割合
%nice CPUのうちnice値を変更したプロセスに使われた時間の割合
%system CPUのうちカーネル処理に使われた時間の割合
%iowait CPUのうちI/O待ちに使われた時間の割合
%steal CPUのうちゲストOSがホストOSに割り当て要求をしたが割り当てられなかった時間の割合
%idle CPUのうちアイドル状態かつI/Oリクエスト待ちではなかった時間の割合

ロードアベレージを表示したい

ロードアベレージの推移を出力したい場合は、sar -qオプションを使うと良いでしょう。

$ sar -q

f:id:netcraft3:20190706223639p:plain

項目 意味
runq-sz 実行待ちのキューに入っているプロセス数
plist-sz プロセスリストの中のプロセス数とスレッド数
ldavg-1 過去1分間のロードアベレージ
ldavg-5 過去5分間のロードアベレージ
ldavg-15 過去15分間のロードアベレージ

メモリの状態を表示したい

メモリの推移を出力したい場合は、sar -rオプションを使うと良いでしょう。

$ sar -r

f:id:netcraft3:20190706230147p:plain

項目 意味
kbmemfree 物理メモリ空き容量
kbmemused 物理メモリ使用量
%memused 物理メモリ使用率
kbbuffers バッファに使用されている物理メモリ使用量
kbcached キャッシュに使用されている物理メモリ使用量
kbcommit 現在のワークロードに必要なメモリ容量
%commit 総メモリ容量(RAM+スワップ)に対する現在のワークロードに必要なメモリ容量の比率

ディスクI/Oを表示したい

ディスクI/Oの推移を出力したい場合は、sar -bオプションを使うと良いでしょう。

$ sar -b

f:id:netcraft3:20190706224440p:plain

項目 意味
tps 1秒あたりのI/Oリクエスト数
rtps 1秒あたりの読み込みI/Oリクエスト数
wtps 1秒あたりの書き込みI/Oリクエスト数
bread/s 1秒あたりの読み込みデータ量(ブロック単位)
bwrtn/s 1秒あたりの書き込みデータ量(ブロック単位)

ネットワークの通信状態を表示したい

ネットワークの通信状態を表示したい場合は、sar -n DEVオプションを使うと良いでしょう。

$ sar -n DEV

f:id:netcraft3:20190706232751p:plain

項目 意味
IFACE ネットワークインターフェース名
rxpck/s 1秒あたりの総受信パケット数
txpck/s 1秒あたりの総送信パケット数
rxkB/s 1秒あたりの総受信キロバイト数
txkB/s 1秒あたりの総送信キロバイト数
rxcmp/s 1秒あたりの総受信圧縮パケット数
txcmp/s 1秒あたりの総送信圧縮パケット数
rxmcst/s 1秒あたりの総受信マルチキャストパケット数

ネットワークの通信エラー状態を表示したい

先ほどのコマンドのDEVオプションをEDEVに変えると通信エラーの統計を出力できます。

$ sar -n EDEV

f:id:netcraft3:20190706233443p:plain

項目 意味
IFACE ネットワークインターフェース名
rxerr/s 1秒あたりの総受信エラーパケット数
txerr/s 1秒あたりのパケット送信エラー数
coll/s 1秒あたりのパケット送信衝突数
rxdrop/s 1秒あたりのバッファ領域不足で発生した受信パケットのドロップ数
txdrop/s 1秒あたりのバッファ領域不足で発生した送信パケットのドロップ数
txcarr/s 1秒あたりのパケット送信キャリアエラー数
rxfram/s 1秒あたりのフレーム・アライメント・エラー数
rxfifo/s 1秒あたりの受信パケットのFIFOオーバーランエラー数
txfifo/s 1秒あたりの送信パケットのFIFOオーバーランエラー数

過去の情報を取得したい

過去の日付の統計結果を得たい場合は、sar -fオプションでログファイルを指定すると過去の日付のデータが確認できます。

$ sar -f /var/log/sa/sa05

トラブルシューティング:ファイルが開けない

サーバーの大きな構成変更をした場合に過去のログファイルが以下のエラーで開けないことがあります。

$ sar -f /var/log/sa/sa05
システム動作情報ファイルの形式が正しくありません

このような場合は以下のコマンドで過去のファイルを開くことができます。

$ sar -f /var/log/sa/sa05 --legacy

過去のデータの蓄積期間を延長したい

sarコマンドでデフォルトで記録される期間は28日間ですが、これを延長することもできます。/etc/sysconfig/sysstatに以下のデフォルト値が保存されています。

# Run system activity accounting tool every 10 minutes
*/10 * * * * root /usr/lib64/sa/sa1 1 1
# 0 * * * * root /usr/lib64/sa/sa1 600 6 &
# Generate a daily summary of process accounting at 23:53
53 23 * * * root /usr/lib64/sa/sa2 -A

faust@ip-172-31-29-53:~% sudo cat /etc/sysconfig/sysstat
# sysstat-9.0.4 configuration file.

# How long to keep log files (in days).
# If value is greater than 28, then log files are kept in
# multiple directories, one for each month.
HISTORY=28

# Compress (using gzip or bzip2) sa and sar files older than (in days):
COMPRESSAFTER=31

# Parameters for the system activity data collector (see sadc manual page)
# which are used for the generation of log files.
SADC_OPTIONS="-S DISK"

# Compression program to use.
ZIP="bzip2"

HISTORY=28となっているのがログの保存期間です。1年間取り続けたいならばこれをHISTORY=365に変えると良いでしょう。

なお、HISTORYを28より大きい数字にした場合、データ保存ファイル名が/var/log/sa/sa{DD}であったのが、/var/log/sa/{YYYYMM}/{DD}に自動的に変わります。ディレクトリは自動的に作成されます。

COMPRESSAFTER=31はログを圧縮するデータ経過日数です。ここで指定した日数を経過したログはgzipまたはbzip2で圧縮されます。この圧縮形式を決めているのがZIP="bzip2"オプションです。

実行間隔を短くしたい

sysstatの記録間隔は/etc/cron.d/sysstatで設定されています。デフォルトでは10分間隔です。また23時53分に前日のログとしてアーカイブされます。

*/10 * * * * root /usr/lib64/sa/sa1 1 1
# 0 * * * * root /usr/lib64/sa/sa1 600 6 &
# Generate a daily summary of process accounting at 23:53
53 23 * * * root /usr/lib64/sa/sa2 -A

もしこの間隔を5分おきのように短く設定したい場合は、/10となっている部分を/5に変更すると良いでしょう。ただしその分、ログのファイルサイズと負荷は少し上がります。

時間帯を指定して統計データを取得したい

sarコマンドで時間帯を指定したい場合は、sar -s hh:mm:ss -e hh:mm:ssで指定すると良いでしょう。過去の日付ファイルから時間帯を絞り込むこともできます。

$ sar -s 15:00:00 -e 20:00:00

f:id:netcraft3:20190706222943p:plain

iostat

このコマンドは何?

iostatはディスクI/Oの負荷を計測するのに便利なコマンドです。

導入方法

sarコマンドで紹介したsysstatパッケージを導入すると使えるようになります。

iostatコマンドの出力結果

iostatをオプション無しで初回実行した場合、出力結果は以下のようになります。

f:id:netcraft3:20190707152934p:plain

iostat -xで表示項目を増やすことができます。

f:id:netcraft3:20190707153305p:plain

iostat -x 5で5秒間隔のI/O負荷が表示されます。

$ iostat -x 5

f:id:netcraft3:20190707153854p:plain

iostatの注意点として初回実行時はディスクデバイスが有効になってから現在までの累積値が表示されます。リアルタイムなデータを得たいならば2回目以降の結果を元に計測するのが良いでしょう。

各項目の意味

項目 意味
rrqm/s 1秒間あたりのデバイスへマージされた読み込みリクエスト数
wrqm/s 1秒あたりのデバイスへマージされた書き込みリクエスト数
r/s 1秒あたりの読み込みリクエスト数
w/s 1秒あたりの書き込みリクエスト数
rsec/s 1秒あたりの読み込みセクタ数
wsec/s 1秒あたりの書き込みセクタ数
avgrq-sz デバイスへのI/Oリクエストの平均ヘクタサイズ
avgpu-sz デバイスへのI/Oリクエストのキューの平均ヘクタサイズ
await デバイスへのI/Oリクエストの平均待ち時間(ミリ秒)
svctm デバイスへのI/Oリクエストの平均処理時間(ミリ秒)
%util デバイスへのI/Oリクエスト時のCPUの使用率

mpstat

このコマンドは何?

mpstatコマンドはCPU別の処理負荷を調べるのに便利なコマンドです。

導入方法

sarコマンドで紹介したsysstatパッケージを導入すると使えるようになります。

CPU処理の偏りを調べたい

mpstatをオプション無しで実行した場合はCPU全体の情報が出力されますが、mpstat -P ALLを指定することでCPU別の処理状況を表示できます。どこかのCPUに処理が偏っていないかを調査できます。以下は1秒間隔でCPUの偏りを調査する例です。

$ mpstat -P ALL 1

f:id:netcraft3:20190706235052p:plain

dstat

このコマンドは何?

dstatはvmstatより詳細に負荷要因になっているプロセスを特定することができます。

導入方法:CentOSの場合(※注意が必要)

CentOS系の場合は以下のコマンドでインストールできますが、CentOS6の場合は注意が必要です。

$ sudo yum install dstat

CentOS6のYumでインストールしたdstatでは、ディスクI/Oが最も多いプロセスをプロセスIDつきで表示する--top-io-advや、ブロックベースで最もディスクI/Oが多いプロセスをプロセスIDつきで表示する--top-bio-advなどのオプションが標準で無効になっています。CentOS7では標準で有効になっていますので問題ありません。

$ sudo dstat -ta --top-io-adv --top-bio-adv
dstat: option --top-bio-adv not recognized, try dstat -h for a list of all the options

CentOS6の場合の対応策として、ソースコードからインストールした場合はこのオプションが標準で有効になります。

$ git clone https://github.com/dagwieers/dstat
$ cd dstat
$ make
$ sudo make install

まあ、--top-io-advや--top-bio-advが使えなくても、そのミニマム版である--top-ioや--top-bioなどで近い結果は得られるのですが、--top-io-advや--top-bio-advが使えた方がプロセスIDが取得できるなど何かと便利です。

導入方法:Debian / Ubuntuの場合

Debian / Ubuntuの場合は以下のコマンドでインストールできます。

$ sudo apt install dstat

導入方法:openSUSEの場合

openSUSEの場合は以下のコマンドでインストールできます。

$ sudo zypper in dstat

dstatの実行結果

オプション無しでdstatを実行した結果は以下の通りです。

$ dstat

f:id:netcraft3:20190706185930p:plain

vmstatとかなり似ていますがカラフルになっていますね。ネットワーク通信やページングに関する情報も表示されています。なお、オプション無しで実行した場合はdstat -cdngyというオプションを指定したのと同値になります。仮にdstat -t(タイムスタンプ情報付与)などでオプションを追加したい場合は、dstat -taなどと-aオプションを付けると、-cdngyをつけるのと同じ意味になります。

最もCPU使用率が高いプロセスを特定したい

dstat --top-cpu-advを使うと最もCPU使用率が高いプロセスをPIDつきで表示させることができます。なお、この特定結果は一般ユーザー権限では出てこない場合が多くsudoをつけて実行すると良いでしょう。

$ sudo dstat -t --top-cpu-adv

f:id:netcraft3:20190708000344p:plain:w300

最もメモリ使用量が多いプロセスを表示したい

dstat --top-memを使うと最もCPU使用率が高いプロセスを表示させることができます。

$ sudo dstat -t --top-mem

f:id:netcraft3:20190708003007p:plain:w300

最もディスクI/Oを行っているプロセスを特定したい

dstat --top-io-advdstat --top-bio-advオプションを使うと最もディスクIOを行っているプロセスをPIDつきで表示させることができます。

$ sudo dstat -t --top-io-adv --top-bio-adv

f:id:netcraft3:20190707235323p:plain

最もOOM Killerの発動要因となりそうなプロセスを特定したい

-dstat --top-oomを実行すると最もOOM Killer発動要因となりそうなプロセスが表示されます。

$ sudo dstat -t --top-oom

f:id:netcraft3:20190707235024p:plain:w300

dstatのプラグイン導入方法

dstatのオプションはプラグイン形式で拡張できます。プラグインはPythonで書くことができ、/usr/share/dstat/のディレクトリにdtsta_hogehoge.pyのような名前で入れればオプションで指定できるようになります。多くの場合、標準で以下のプラグインが同梱されています。

f:id:netcraft3:20190706190518p:plain

lsof

このコマンドは何?

ある程度原因となるプロセスが絞られてきたらlsofコマンドを実行するのもお薦めです。lsofによって現在プロセスがオープンしているファイル(ファイルディスクリプタ)を調査できます。

導入方法:CentOSの場合

CentOSの場合は以下のコマンドでインストールできます。

$ sudo sudo yum install lsof

導入方法:Debian / Ubuntuの場合

Debian / Ubuntuの場合は以下のコマンドでインストールできます。

$ sudo sudo apt install lsof

lsofは多くのディストリビューションに標準でインストールされています。

プロセスがオープンしているファイル一覧を調べたい

lsofはオプションをつけずに実行すると全プロセスの全てのオープンしているファイル一覧を出力してしまいますので、lsof -p ****でプロセスIDを指定するか、プロセス名でgrepするようにしましょう。

$ sudo lsof -p MySQLのプロセスID

f:id:netcraft3:20190708144157p:plain

stress

このコマンドは何?

stressコマンドはシステムに対して意図的に負荷を与えることができます。

導入方法:CentOSの場合

CentOSの場合は以下のコマンドでインストールできます。

$ sudo sudo yum install stress

導入方法:Debian / Ubuntuの場合

Debian / Ubuntuの場合は以下のコマンドでインストールできます。

$ sudo sudo apt install stress

導入方法:openSUSEの場合

残念なことにopenSUSEの標準のリポジトリにはstressパッケージは保管されていません。

以下のリンクを参考に環境に合わせたRPMをインストールする必要があります。

software.opensuse.org

CPUに負荷を掛けたい

stressを使ってCPUに負荷を掛けてみましょう。CPU負荷はstress -c 2 -t 10などのオプションで掛けることができます。-cで指定するのはワーカーの数、-tは実行時間(秒)です。manによると内部的にはsqrt()を実行しています。2コアのサーバーで動かす場合はワーカーは2つに設定すると良いでしょう。

$ stress -c 2 -t 10

f:id:netcraft3:20190707225929p:plain

dstatでCPU負荷を見てみましょう。CPU使用率が100%になっています。

f:id:netcraft3:20190707225357p:plain

mpstatで見ても各コアに均等に負荷が掛かっています。

f:id:netcraft3:20190707225616p:plain

メモリに負荷を掛けたい

stressでメモリに負荷を掛ける場合はstress --vmオプションを使います。--vmはmalloc()free()を繰り返すワーカーの数です。-vm-bytesでメモリ量を指定することができます。デフォルトではメモリの確保と解放を繰り返しますが、--vm-keepオプションでメモリの確保を継続させることができます。

今回は1GBのメモリを確保し続けるワーカーを2つ動かしてみましょう。

$ stress --vm 2 --vm-bytes 1G --vm-keep -t 30

それではdstatの結果を見てみましょう。stressによってメモリ負荷が掛かったのが確認できます。

f:id:netcraft3:20190708002239p:plain:w300

トラブルシューティング

以下のエラーが出たらメモリが少なってアロケートできず新たにmalloc()を実行するワーカーが追加できません。ほどほどにしましょう。

stress: info: [25009] dispatching hogs: 0 cpu, 0 io, 2 vm, 0 hdd
stress: FAIL: [25011] (494) hogvm malloc failed: Cannot allocate memory
stress: FAIL: [25009] (394) <-- worker 25011 returned error 1
stress: WARN: [25009] (396) now reaping child worker processes
stress: FAIL: [25009] (400) kill error: No such process
stress: FAIL: [25010] (494) hogvm malloc failed: Cannot allocate memory
stress: FAIL: [25009] (394) <-- worker 25010 returned error 1
stress: WARN: [25009] (396) now reaping child worker processes
stress: FAIL: [25009] (400) kill error: No such process
stress: FAIL: [25009] (451) failed run completed in 0s

応用編へ向けて

今回紹介しきれなかったコマンドは応用編にて書いていきます。