Linuxサーバのパフォーマンス測定スクリプト

書けば書くほどニッチな方向に向かってる気がしています。
果たして需要があるのでしょうか？
脱力モードで書きますね( ´ｰ`)ﾝﾌﾌ

**2014-09-03 ジワジワ来てるので結果集計用エクセルを自分で用意してね☆（ゝω・）vｷｬﾋﾟってのが心苦しくなって来ました。**
**Evernote共有で申し訳ないですが一式ファイルへのリンク乗せておきます！**
》 監視ロガー20140903.zip https://www.evernote.com/shard/s12/sh/1180dd43-4d5a-4461-938f-45bb405fc715/bb939159f7a2b127 


## パフォーマンス測定！？

困りました。
そんなんした事無いのです。
色々と調べた結果、自分で書いちゃうのがベストかなと…。
1. 測定用シェルと2. 結果を処理するエクセルの2つを使用します。

## AWSのCPU負荷測定について

AWSは 50%us 近辺でCPU負荷MAXなので注意します。
cpu項目に %us と右端に %stとあります。
usとstの合計がcpu負荷合計と見ないと大変な事になります（白目）
stは Steal Time で仮想CPUのawsならではの項目になるのかな？
Steal Time を見落とすと死ぬぜ！死ぬなよ！

追記：検証してるアルパカさんがいた
microインスタンスはlimitかけると大きくパフォーマンスが向上する（※再追記あり） - アルパカDiary 
http://d.hatena.ne.jp/toritori0318/20140312/1394634304

Who Stole my CPU? Few Basics on CPU Steal Time | I am OnDemand http://iamondemand.com/blog/who-stole-my-cpu/

### 参考コンソール1

参考にコンソール貼り付けようと思いましたが、調整済みで Steal Time 出ていません。
なんの参考にもなりません。
ですが、瞬間的ですが CPU 71%出てます。すごいです。
この場合CPUが4発なので load average値が4.0以下になっていれば適正値です。
load averageが4.0を超えると加速度的にやばいことになり Steal Time が増加するんじゃないかな…。
※ 適当なこと言ってたらご指摘頂きたいです
ちなみに m2.2xlarge です。すごく早いです。

```shell-session:top_on_aws
top - 00:43:24 up 64 days, 22:49,  1 user,  load average: 1.63, 1.40, 0.91
Tasks:  88 total,   1 running,  87 sleeping,   0 stopped,   0 zombie
Cpu0  :  2.7%us,  2.7%sy,  0.0%ni, 84.6%id, 10.1%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu1  : 71.6%us,  0.7%sy,  0.0%ni, 16.4%id, 11.4%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu2  :  0.0%us,  0.7%sy,  0.0%ni, 98.3%id,  1.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu3  : 22.5%us,  1.3%sy,  0.0%ni, 25.5%id, 50.7%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:  35062104k total, 34898468k used,   163636k free,    86940k buffers
Swap:        0k total,        0k used,        0k free, 10977060k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
 6316 mysql     20   0 24.2g  22g 5092 S 101.4 66.3   8465:20 mysqld
  927 root      20   0     0    0    0 S  0.3  0.0 122:18.58 jbd2/xvda1-8
15802 root      20   0  115m 2612 1124 S  0.3  0.0  54:52.77 bash
    1 root      20   0 19360  672  364 S  0.0  0.0   0:04.07 init
    2 root      20   0     0    0    0 S  0.0  0.0   0:00.00 kthreadd
    3 root      20   0     0    0    0 S  0.0  0.0   0:11.83 ksoftirqd/0
    4 root      20   0     0    0    0 S  0.0  0.0   1:36.49 kworker/0:0
    5 root      20   0     0    0    0 S  0.0  0.0   0:00.00 kworker/u:0
```

### 参考コンソール2

load averageの話が出てきたので負荷が高い場合のコンソールも持ってきました。
mysqlを同時に6スレッド？だったけな？なので待ちが発生しLAも高くなっています。
Qiitaへ投稿したスレッドコントロール シェルスクリプトで同時Job数の調整をしています。
※わりと適当なこと言っているので、ちゃんと調べてください
このサーバも m2.2xlarge です（複数サーバ使ってます）

> ShellScript - シェルスクリプトでコマンド多重コントロール - Qiita http://qiita.com/TanukiTam/items/b64e0669e479c26d4790

```shell-session:top_on_aws
top - 00:50:22 up 78 days, 17:10,  1 user,  load average: 3.12, 1.81, 1.25
Tasks: 142 total,   1 running, 140 sleeping,   0 stopped,   1 zombie
Cpu0  : 26.1%us, 11.7%sy,  0.0%ni, 19.1%id, 43.1%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu1  : 22.7%us,  6.0%sy,  0.0%ni, 29.3%id, 41.7%wa,  0.0%hi,  0.0%si,  0.3%st
Cpu2  : 42.8%us, 19.7%sy,  0.0%ni, 19.1%id, 18.4%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu3  : 26.0%us, 10.1%sy,  0.0%ni,  2.7%id, 60.8%wa,  0.0%hi,  0.0%si,  0.3%st
Mem:  35062104k total, 34849072k used,   213032k free,    77040k buffers
Swap:        0k total,        0k used,        0k free, 10919984k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
  730 mysql     20   0 23.8g  22g 5680 S 140.0 66.2   5935:28 mysqld
15130 hogehoge  20   0  103m 5312 1812 S  4.0  0.0   0:00.14 mysql
15178 hogehoge  20   0  102m 4456 1812 S  3.7  0.0   0:00.11 mysql
15226 hogehoge  20   0  102m 4508 1812 S  1.7  0.0   0:00.05 mysql
  225 root      20   0     0    0    0 S  0.7  0.0 142:39.83 kswapd0
14415 hogehoge  20   0 11580 1644 1192 S  0.7  0.0   0:00.22 sh
  929 root      20   0     0    0    0 S  0.3  0.0  81:55.33 jbd2/xvda1-8
 5758 root      20   0  108m 2604 1108 S  0.3  0.0 196:41.45 bash
    1 root      20   0 19360 1200  892 S  0.0  0.0   0:11.26 init
    2 root      20   0     0    0    0 S  0.0  0.0   0:00.00 kthreadd
    3 root      20   0     0    0    0 S  0.0  0.0   0:28.84 ksoftirqd/0
    4 root      20   0     0    0    0 S  0.0  0.0   0:00.00 kworker/0:0
```

## 測定用シェルスクリプト

時間単位にプロセス状況を引っこ抜いてログ出力します。
読みにくいのは後でエクセル整形するので問題ないです。
メモリやネットワークを使わなくても取得しておくと安心です。

使っているデータ
* /proc/stat
* /proc/meminfo
* /proc/net/dev - eth0

※ 形式が違っていたら自分で直して使って下さい

```bash:proc_total.sh
#!/bin/bash
#
# パフォーマンステストのために書き起こし
#
# System 状況を sleep x 毎に整形しログ出力する
# 別の excel に貼り付けて計算後に状況を確認する
#
# /proc/stat      CPU使用率
# /proc/meminfo   メモリ使用状況
# /proc/net/dev   eth0トラフィック状況
#
LANG=C
PATH=/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:
export LANG PATH
umask 022

HEADER='"date","time"'
# /proc/stat
HEADER=${HEADER}',"hostname","cpu","user","nice","system","idel","iowait","irq","softirq","steal","guest"'
# /proc/meminfo
HEADER=${HEADER}',|,"MemTotal","MemFree","Buffers","Cached","SwapCached","Active","Inactive","Active(anon)","Inactive(anon)","Active(file)","Inactive(file)","Unevictable","Mlocked","SwapTotal","SwapFree","Dirty","Writeback","AnonPages","Mapped","Shmem","Slab","SReclaimable","SUnreclaim","KernelStack","PageTables","NFS_Unstable","Bounce","WritebackTmp","CommitLimit","Committed_AS","VmallocTotal","VmallocUsed","VmallocChunk","AnonHugePages","HugePages_Total","HugePages_Free","HugePages_Rsvd","HugePages_Surp","Hugepagesize","DirectMap4k","DirectMap2M"'
# /proc/net/dev - eth0
HEADER=${HEADER}',|,"face","bytes","packets","errs","drop","fifo","frame","compressed","multicast","|bytes","packets","errs","drop","fifo","colls","carrier","compressed"'

echo $HEADER
while [ true ]
do
   CPU=(`head -1 /proc/stat`)
   CPUS="${CPU[0]},${CPU[1]},${CPU[2]},${CPU[3]},${CPU[4]},${CPU[5]},${CPU[6]},${CPU[7]},${CPU[8]},${CPU[9]}"
   MEM=`awk '{ printf ",%d",$2 }' /proc/meminfo`
   TFC=(`cat /proc/net/dev | grep eth0`)
   TFCS="${TFC[0]},${TFC[1]},${TFC[2]},${TFC[3]},${TFC[4]},${TFC[5]},${TFC[6]},${TFC[7]},${TFC[8]},${TFC[9]},${TFC[10]},${TFC[11]},${TFC[12]},${TFC[13]},${TFC[14]},${TFC[15]},${TFC[16]}"
   echo `date '+%Y/%m/%d,%H:%M:%S.%N'`","`hostname`",${CPUS},|${MEM},|,${TFCS}"
   sleep 5s
   #sleep 1m
done
```

## 出力テキスト結果加工エクセル

削除したつもりですが固有名称的ヤバいものがあれば教えて下さい。

~~あれ？エクセル貼れない？
自分で頑張って作ってください（うひ）~~
~~![Invalid file type: application/zip]()~~

**Evernote共有で申し訳ないですが一式ファイルへのリンク乗せておきます！**
》 監視ロガー20140903.zip https://www.evernote.com/shard/s12/sh/1180dd43-4d5a-4461-938f-45bb405fc715/bb939159f7a2b127 

proc_totalログ解析.xlsx
proc_totalログ解析_サンプル.xlsx を参考にして下さい。

+ [貼り付け]シートにテキスト内容を貼り付け
+ [結果]シートで前後差分の計算結果が表示される
+ [結果]シートの必要な部分をコピー
+ 例:[250]シートのペースト開始位置を右クリックし値貼り付け
+ 後は適当に色つけたりチェックしたり

[説明]シートにちょっと説明


## 参考にいただいたソースと出典

その頃の明確な記憶が無いのでソースメモに残っている限りとなります。
ありがとうございました。
オレオレって人はご連絡下さい。

### cpu_check.sh

```bash:cpu_check.sh
#!/bin/bash
CPU1=(`head -1 /proc/stat`)

while [ true ]
do
   sleep 1
   CPU2=(${CPU1[@]})
   CPU1=(`head -1 /proc/stat`)

   total=`expr ${CPU1[1]} - ${CPU2[1]} + ${CPU1[2]} - ${CPU2[2]} + ${CPU1[3]} - ${CPU2[3]} + ${CPU1[4]} - ${CPU2[4]}`

   user=`echo "scale=2; (${CPU1[1]} - ${CPU2[1]}) * 100 / $total" | bc;`
   nice=`echo "scale=2; (${CPU1[2]} - ${CPU2[2]}) * 100 / $total" | bc;`
   sys=`echo "scale=2; (${CPU1[3]} - ${CPU2[3]}) * 100 / $total" | bc;`
   idle=`echo "scale=2; (${CPU1[4]} - ${CPU2[4]}) * 100 / $total" | bc;`

   printf "`date '+%Y/%m/%d d %H:%M:%S.%N'` `hostname` %3.2f %3.2f %3.2f %3.2f \n" $user $nice $sys $idle
done

# LinuxでCPU使用率を取得する。 - redtower's memo http://redtower.plala.jp/2010/06/06/linux-cpu.html
# ユーザモード（user）、低優先度のユーザモード（nice）、システムモード（sytem）、タスク待ち（idle）
# 1行目にCPUの状態を表す数値が格納されている。それ以外は「man proc」で確認すること。
#
# システムが起動してから現在までに消費した時間が記録されている
# cpu  21435 120 78001 50180652 13622 1 1321 69374 0
#      |     |   |     |        |     | |    |     |
#      |     |   |     |        |     | |    |     *- 9:guest がある。これは、 Linux カーネルの制御下のゲストオペレーティングシステムの仮想 CPU の実行に消費された時間である。
#      |     |   |     |        |     | |    |
#      |     |   |     |        |     | |    *- 8:steal (盗まれた時間; stolen time) が存在する。これは、仮想化環境での動作時に他のオペレーティングシステムにより消費された時間である。
#      |     |   |     |        |     | |
#      |     |   |     |        |     | *- 7:softirq (ソフト割り込みの処理を行った時間; 2.6.0-test4 以降)
#      |     |   |     |        |     |
#      |     |   |     |        |     *- 6:irq (割り込み処理を行った時間; 2.6.0-test4 以降)
#      |     |   |     |        |
#      |     |   |     |        *- 5:iowait (I/O の完了を待っていた時間; 2.5.41 以降)
#      |     |   |     |
#      |     |   |     *- 4:タスク待ち（idle）
#      |     |   |
#      |     |   *- 3:システムモード（sytem）
#      |     |
#      |     *- 2:低優先度のユーザモード（nice）
#      |
#      *- 1:ユーザモード（user）
```

### memory_size.sh

Apacheチューニングのためのメモリ使用量計算 - ひとりごと
http://d.hatena.ne.jp/youhey/20110115/1295060276

```bash:memory_size.sh
#!/bin/sh

GREP="/bin/grep"
AWK="/bin/awk"
PRINTF="/usr/bin/printf"

if [ $# -lt 1 ]; then
    echo "usage: ${0} [pid ...]" 1>&2
    exit 100
fi

$PRINTF "PID\tRSS\t(peak)\tVM\t(peak)\n"

for p in $@
do
    status="/proc/${p}/status"
    if [ -f $status ]; then
        rsssize=`$GREP '^VmRSS:' $status | $AWK '{print $2}'`
        rsspeak=`$GREP '^VmHWM:' $status | $AWK '{print $2}'`
        vmsize=`$GREP '^VmSize:' $status | $AWK '{print $2}'`
        vmpeak=`$GREP '^VmPeak:' $status | $AWK '{print $2}'`
        $PRINTF \
            "%d\t%d\t(%d)\t%d\t(%d)\n" \
            $p \
            $rsssize \
            $rsspeak \
            $vmsize \
            $vmpeak
    fi
done

# [root@ham1 apache]# ./memory_size.sh `pgrep httpd`
# PID     RSS     (peak)  VM      (peak)
# 11562   9788    (9812)  260064  (260088)
# 12816   9784    (9808)  260064  (260088)
# 12817   9820    (9844)  260064  (260088)
# 13591   9788    (9812)  260064  (260088)
# 13841   9784    (9808)  260064  (260088)
# 13958   9888    (9912)  260064  (260088)
# 14032   9832    (9856)  260064  (260088)
# 15380   9788    (9812)  260064  (260088)
# 15679   9788    (9812)  260064  (260088)
# 31681   11356   (11356) 256564  (256616)
# [root@ham1 apache]#

# PID
# RSS       VmRSS       topでのRES(Resident)、実際に使用している物理メモリ領域のサイズ。
#                       上結果では大体 9MB 使用している
# (peak)    VmHWM       mm->hiwater_rss か mm->rss のどちらかで高い値を示した物
#                       mm->hiwater_rss このプロセスがある時点で使っていたページフレームの最大数
#                       mm->rss         プロセスに割り当てられているページフレームの数
#                       ページフレームのサイズは固定なので、ページフレーム数 → バイト数に変換するとメモリサイズになります。
# VM        VmSize      topでのVIRT(Virtual)、仮想メモリ領域のサイズ
# (peak)    VmPeak      このプロセスがある時点で使っていた最大仮想メモリサイズ



# Apacheチューニングのためのメモリ使用量計算 - ひとりごと
# http://d.hatena.ne.jp/youhey/20110115/1295060276
#
# for p in `pgrep httpd`; do grep "^VmHWM:" /proc/$p/status |awk '{print $2}'; done
#
# $ ./memory_size.sh `pgrep httpd`
# $ sudo ./shared_memory_size.pl `pgrep httpd`
#
# 実メモリ上ページサイズ
# 平均26.77MB
# 最大31.38MB
# 最小20.9MB
#
# 実メモリ上ページサイズ（ピーク）
# 平均31.34MB
# 最大32.91MB
# 最小30.21MB
#
# 共有率
# 平均32%
# 最大41%
# 最小27%

# 計算結果から、Apacheプロセスのメモリ使用量を32MBと想定、平均して32%程度のメモリを共
# 有するものとして、Apacheプロセスが消費するメモリの予想は平均21.76MB程度か。
#
# Webサーバには4GBを搭載しているので、OSが512MB程度占有するものとして、
# 「(4GB - 512MB）/ 21.76MB」でApacheに割り当てられそうなプロセス数は164と算出できる。
#
# 余裕をもたせるとして、100〜150程度の設定が妥当そうか。
```

### none_shared_memory_fetcher.pl

Apacheとかforkしたプロセスのメモリチューニングに関するメモとスクリプト | hirobanex.net
http://hirobanex.net/article/2013/10/1381407737

```pl:none_shared_memory_fetcher.pl
#!/usr/bin/perl
use strict;
use warnings;

@ARGV or die "usage: %0 [pid ...]";

printf "PID\tRSS\tSHARED\tNONE_SHARED\n";

for my $pid (@ARGV) {
    open my $fh, "< /proc/$pid/smaps" or (warn  $! and next);
    my @rows = <$fh>;
    my $rss    = mem_size_fetcher('Rss',@rows) or next;
    my $shared = mem_size_fetcher('Shared_Clean',@rows) + mem_size_fetcher('Shared_Dirty',@rows);

    printf
        "%d\t%d\t%d (%d%%)\t%d\n",
        $pid,
        $rss,
        $shared,
        int(($shared / $rss) * 100),
        ($rss - $shared),
}

sub mem_size_fetcher {
    my ($target,@rows) = @_;

    my $mem_size = 0;

    for my $row (@rows) {
        my ($mem) = $row =~ /^$target:\s*(\d+)/i;
        $mem_size +=($mem||0);
    }

    return $mem_size;
}

# Apacheとかforkしたプロセスのメモリチューニングに関するメモとスクリプト | hirobanex.net
# http://hirobanex.net/article/2013/10/1381407737
#
# 使い方は、naoyaさんのと同じで、
#
# sudo perl none_shared_memory_fetcher.pl `pgrep apache2` | head
#
# ってたたけば、
# PID     RSS     SHARED  NONE_SHARED
# 31021   6600    5572 (84%)      1028
# 31024   5064    4868 (96%)      196
# 31025   5068    4868 (96%)      200
# 31026   5040    4840 (96%)      200
# 31027   5684    5172 (90%)      512
# 31028   5088    4892 (96%)      196
# 31029   5032    4840 (96%)      192
# 31030   5040    4844 (96%)      196
# 31031   5044    4840 (95%)      204
# 
# 
# って感じに出力される。NONE_SHAREDのkb数が子プロセス単独のメモリ使用量なので、ばらつ
# きがあるものこれだと、だいたい大目に見て、250くらいで、×プロセス数がApacheに使うメ
# モリってことになるみたい。
# 
# なお、リクエストの度にメモリリークとかいろいろで子プロセスは太る傾向にあるから、ある
# 程度リクエスト流して、MaxRequestsPerChildの上限近いプロセスで計算する必要があるみた
# い。
# 
# DSASチームのとてもありがたい下の方にMySQLのInnoDB周りのメモリ設定用ツールがあるんだ
# けど、ホントはこんな感じのがあるといいけど、いまどきApacheだけに限定するのもキモいの
# でそういうのはやめた。


# やってみた
# vi none_shared_memory_fetcher.pl
#
# chmod +x none_shared_memory_fetcher.pl
# ./none_shared_memory_fetcher.pl `pgrep httpd` | head
# [root@ham1 apache]# ./none_shared_memory_fetcher.pl `pgrep httpd` | head
# PID     RSS     SHARED  NONE_SHARED
# 11562   9796    8204 (83%)      1592
# 12816   9908    8292 (83%)      1616
# 12817   9916    8296 (83%)      1620
# 13591   9796    8188 (83%)      1608
# 13841   9816    8204 (83%)      1612
# 13958   9820    8212 (83%)      1608
# 14032   9808    8224 (83%)      1584
# 15380   9880    8260 (83%)      1620
# 15679   9880    8276 (83%)      1604
# [root@ham1 apache]#
# [root@ham1 apache]# ./memory_size.sh `pgrep httpd`
# PID     RSS     (peak)  VM      (peak)
# 11562   9788    (9812)  260064  (260088)
# 12816   9784    (9808)  260064  (260088)
# 12817   9820    (9844)  260064  (260088)
# 13591   9788    (9812)  260064  (260088)
# 13841   9784    (9808)  260064  (260088)
# 13958   9888    (9912)  260064  (260088)
# 14032   9832    (9856)  260064  (260088)
# 15380   9788    (9812)  260064  (260088)
# 15679   9788    (9812)  260064  (260088)
# 31681   11356   (11356) 256564  (256616)
# [root@ham1 apache]# for p in `pgrep httpd`; do grep "^VmHWM:" /proc/$p/status |awk '{print $2}'; done

# これを最大のデータを渡した時の状況を見てテストするといける
```

### proc_meminfo.sh

```bash:proc_meminfo.sh
#!/bin/sh

zbxHOSTNAME="$1"
zbxSERVER="$2"

TEMPFILE="/tmp/zbxTMP$$"

cat /proc/meminfo |while read LINE
do ARTICLE=`echo $LINE |cut -d":" -f1 | tr "()" "_"`
    ITEMNUM=`echo $LINE|cut -d":" -f2|sed -e "s/ kB/ * 1024/" |bc`
    echo `date '+%Y/%m/%d %H:%M:%S.%N'` `hostname` "$ARTICLE $ITEMNUM"
# done >$TEMPFILE
done

LANG=C;
(
    awk '
BEGIN
 { printf "\"DATE\",\"TIME\""}
 {printf ",\"%s(%s)\"",$1,$3}
END
{printf "\n"}' /proc/meminfo > meminfo.csv
); while true;
do ( awk 'BEGIN{ printf strftime("%Y/%m/%d, %H:%M:%S") } {printf ",%d",$2} END{printf "\n"}' /proc/meminfo >> meminfo.csv );sleep 1; done
```

### proc_stat.sh

```bash:proc_stat.sh
#!/bin/bash
while [ true ]
do
   sleep 1
   echo `date '+%Y/%m/%d %H:%M:%S.%N'` `hostname` `head -1 /proc/stat`
done
```