株式会社えむぼま CTO 高見禎成
■swapさせずに最大プロセス数にせよ!
WWWサーバが最大パフォーマンスを出すには
1) SWAPさせないで
2) 最大プロセス数に設定する
ことが最大の条件です。
他にapacheのhttpd.confでHostNameLookups offにしてログ記録時の名前解決をなくす等細かい積み重ねはいくつかありますが、最大のポイントは上記2条件でしょう。
■最大プロセス数は揃えよ!
SWAPさせない最大プロセス数をいくつにするかはこの後見ていきますが、どの値にするにせよapacheとtomcatとDBの最大プロセス数は揃えましょう。
apacheのMaxClietnsは標準で255、tomcatのMaxThreadsは標準で150、MySQLのmax_connectionsは標準で100です。
apacheが2台でMySQL 1台に接続しているなら、MySQLのmax_connectionsはapacheのMaxClients x2以上に揃えましょう。
apacheとtomcatを1台に同居させてapache→tomcat接続させているなら、tomcatのMaxThreadsはapacheのMaxClientsと揃えましょう。
■事前準備 - sarの勧め
本来監視しておくべきですが、サーバが遅くなる日は突然やってきます。
対応するのはピークをすぎてからのことも多いでしょう。
ピーク時の稼働状況を後から調べられるようにするためにsar(sysstat)をインストールしておくことをお勧めします。
SWAPの有無、システムの稼働プロセス数、DISK I/O、ネットワークトラフィック等sarがあればほぼチューニングの基礎データはそろいます。
※付録1 -sar
○sarのオプション
-q loadとともにシステムの最大プロセス数がわかる。apacheやmysqlが最大プロセス数に達したか調べられる。
-W swap状況がわかる -rのメモリ状況と合わせて使う。
-b I/O数と転送量からDISK I/Oを調べられる
-n DEV NICの転送パケット数と転送料からトラフィックが調べられる
○sarの実行間隔
debianの標準では10分単位の集計になっている。変更の際は下記を変更する
/etc/cron.d/sysstat
---
# Activity reports every 10 minutes everyday
5-55/10 * * * * root [ -x /usr/lib/sysstat/sa1 ] && { [ -r "$DEFAULT" ] && . "$DEFAULT" ; [ "$ENABLED" = "true" ] && exec /usr/lib/sysstat/sa1; }
○過去のsar情報
debianでは/var/log/sysstat(RHは/var/log/sa)に過去分がある。
saDDでDDが日付の部分
cd /var/log/sysstat
sa01 sa03 sa05 sa28 sa30 sar01 sar03 sar2
/var/log/sysstat# ls7 sar29 sar31
sa02 sa04 sa27 sa29 sa31 sar02 sar04 sar28 sar30
# sar -f sa01 -u
Linux 2.4.27-2-686-smp 02/01/07
00:05:01 CPU %user %nice %system %iowait %idle
00:15:01 all 1.53 0.00 3.98 0.00 94.48
00:25:01 all 1.57 0.00 4.07 0.00 94.36
○sarの世代数
/usr/lib/sysstat/sa2
---
…
find /var/log/sysstat \( -name 'sar??' -o -name 'sa??' \) -mtime +7 -exec rm -f {} \;
^^ここで7日分で削除している
■システムの負荷状況に見方
○Linuxの稼働メモリ
Linuxは物理メモリを最大限キャッシュに利用します。
そのためfree,top等のメモリ使用量は常にほぼ100%です。
実際に利用されているメモリの調べ方です。
$ free -m
total used free shared buffers cached
Mem: 503 490 12 0 100 135
-/+ buffers/cache: 254 248
Swap: 509 192 317
used - buffers - cached = 実使用量
上記の例だと 490 - 100 - 135 = 255MBが実使用量。空きは最大248MBになります。
apacheやtomcat、msyql、postgresを止めて上記を調べるとカーネルを含む最低起動メモリ量がわかります。
○Linuxの過去のメモリ状況の調べ方
sar -rを使用する
$ sar -r|more
Linux 2.4.27-2-686-smp 02/05/07
00:05:01 kbmemfree kbmemused %memused kbbuffers kbcached kbswpfree kbswpused %swpused kbswpcad
00:15:01 30264 485108 94.13 33980 263084 461368 60864 11.65 10308
00:25:01 27816 487556 94.60 34616 265260 461368 60864 11.65 10308
00:35:01 28544 486828 94.46 35004 265092 461368 60864 11.65 10308
00:45:01 28484 486888 94.47 35340 265064 461368 60864 11.65 10308
00:55:01 28344 487028 94.50 35644 264520 461368 60864 11.65 10308
freeの読み方と同じです。swpusedが100%になるとシステムが停止します。
○Linuxの過去のメモリ不足(swap)の調べ方
sar -Wを使用する
$ sar -W
Linux 2.4.27-2-686-smp 02/05/07
00:05:01 pswpin/s pswpout/s
00:15:01 0.19 0.00
pswpin,pswpoutの値が高くなっているとswapが発生しています。
swapが発生するとloadも高くなりシステムは極端な遅延になります。
swapを消費しつくすとシステム停止になるので要注意です。
○Linuxの過去のCPU稼働率の調べ方
sar -uを使用する
$ sar -u|more
Linux 2.4.27-2-686-smp 02/05/07
00:05:01 CPU %user %nice %system %iowait %idle
00:15:01 all 1.50 0.00 4.01 0.00 94.49
00:25:01 all 1.55 0.00 4.07 0.00 94.38
00:35:01 all 1.50 0.00 3.99 0.00 94.51
00:45:01 all 1.52 0.00 4.01 0.00 94.47
00:55:01 all 1.50 0.00 3.69 0.00 94.81
01:05:02 all 2.15 0.00 5.90 0.00 91.95
01:15:01 all 1.55 0.00 3.91 0.00 94.54
CPU稼働率が高く100%になっても「システムは極端な遅延にならない!」のでCPU稼働100%は問題の優先順位が低いです。
CPU稼働が100%になった原因=SWAPによるDISK I/Oを特定することが重要です。
PHPの場合最大稼働CPU時間が設定されているので無限ループは発生しにくいですが、PerlのCGI等で無限ループが発生するとsar -qでプロセス数もloadも増えていないのにCPU稼働率が上がったりします。
筆者はsar -uはほぼ無限ループプロセスがいないか探すためだけに使っています。
繰り返しますがCPUの稼働率が高いことは「システム遅延の直接の原因ではない!!」と考えています。
○Linuxの過去の稼働プロセス数の調べ方
apacheが最大プロセス数に達したことは/var/log/apache/error_logに
[error] server reached MaxClients setting, consider raising the MaxClient s setting
と表示されます。grep -i max error_log 等で時間を調べることができますが、最大に達しないと出力されません。
Linuxで稼働するプロセス数を調べるにはsar -qを使用します。
$ sar -q
Linux 2.4.27-2-686-smp 02/05/07
00:05:01 runq-sz plist-sz ldavg-1 ldavg-5 ldavg-15
00:15:01 2 51 0.01 0.10 0.14
00:25:01 2 49 0.01 0.10 0.13
00:35:01 2 48 0.00 0.05 0.08
00:45:01 3 50 0.01 0.07 0.08
00:55:01 2 49 0.00 0.04 0.06
01:05:02 1 48 0.05 0.38 0.26
plist -szがシステムの稼働プロセス数です。この値が急に増えている場合、apacheやMySQLのプロセス数が増えている場合が多いです。 ちなみに ldavg-1は1分毎のloadです。loadとは待ちプロセス数の数でCPU稼働率よりシステムの負荷を表す基準に使います。loadがあがる典型例として以下の2つがあります。
1) DISK I/Oが増えて待ち行列が増えた
2) apacheのMaxClients等アプリの最大プロセス制限で待ちプロセス数が増えた
関係情報として、loadが5以上になるとsendmailはSMTPをrejectすることを覚えておくとよいでしょう。。
○Linuxの過去のDISK I/O調査
sar -bを使う
# sar -b
Linux 2.4.27-2-686-smp 02/05/07
00:05:01 tps rtps wtps bread/s bwrtn/s
00:15:01 15.75 0.65 15.10 10.50 58.24
00:25:01 15.21 0.23 14.98 2.72 57.80
00:35:01 19.74 0.03 19.71 0.17 67.56
00:45:01 15.32 0.19 15.13 1.65 58.76
00:55:01 14.95 0.03 14.92 0.29 58.11
SWAPも発生しておらず、プロセスも増えておらず、CPU稼働率も低いのに遅い場合
例えばDBで全文検索が頻繁に発生したり、distictで一時テーブルが頻繁に作成されている
場合にdisk I/Oが増える。
他のマシンとも比較して高い値になっていないかを調べる。
■apacheの最大プロセス数を割り出す方法
○プロセスモデルとスレッドモデル
まずプロセスについて解説します。
アプリケーションにはプロセスモデルとスレッドモデルがあります。
UNIXの伝統的なモデルはプロセスモデルで、apache1.xが同時複数アクセスを処理するためにapacheは子プロセスを生成しています。プロセスモデルはメモリ空間をコピーするため、プロセス起動は負荷が高いです。またapacheはプロセス毎にメモリ使用量が異なります。
プロセスの重さを解決するためにスレッドモデルが作られました。MySQLはスレッドモデルです。スレッドモデルはメモリ空間を共有するため起動の負荷が少ないのです。
apache2.0 よりプロセスモデル(prefork)とスレッドモデル(worker)を選べますが、スレッドモデルとして稼働するにはCGIではスレッドの意味がなく、PHP等スレッドモデルにする必要があります。PHPはスレッド未対応のため、apacheは原則preforkで稼働させています。
○プロセスのメモリ使用量
ps auxwとtopで確認します
$ ps auxw
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
mysql 901 0.0 4.1 70716 21444 ? S Jan26 1:25 /usr/sbin/mysqld --basedir=/usr --datadir=/var/lib/mysql --user=mysql
mysql 902 0.0 4.1 70716 21444 ? S Jan26 0:13 /usr/sbin/mysqld --basedir=/usr --datadir=/var/lib/mysql --user=mysql
www-data 32233 0.0 1.8 29200 9712 ? S 06:25 0:05 /usr/sbin/apache
www-data 32234 0.0 2.6 29200 13620 ? S 06:25 0:05 /usr/sbin/apache
www-data 32235 0.0 2.5 29208 13280 ? S 06:25 0:05 /usr/sbin/apache
www-data 32236 0.0 2.5 29224 13072 ? S 06:25 0:05 /usr/sbin/apache
VSZがメモリサイズ(KB)、RSSはReSident Sizeで実メモリサイズ(KB)
mysqlはスレッドモデルのため、全てのMYSQLで約21MB使用しています。
apacheはプロセスモデルのためRSSは個別に違います
ただしプロセス単位のメモリはtopを利用する方がわかりやすいように思います。
top - 17:09:09 up 9 days, 23:49, 2 users, load average: 0.08, 0.18, 0.16
Tasks: 49 total, 1 running, 48 sleeping, 0 stopped, 0 zombie
Cpu(s): 0.2% user, 5.4% system, 0.0% nice, 94.4% idle
Mem: 515372k total, 485780k used, 29592k free, 36088k buffers
Swap: 522232k total, 63892k used, 458340k free, 230688k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
901 mysql 9 0 53224 20m 18m S 0.0 4.2 1:25.56 mysqld
902 mysql 9 0 53224 20m 18m S 0.0 4.2 0:13.38 mysqld
903 mysql 9 0 53224 20m 18m S 0.0 4.2 0:00.00 mysqld
32233 www-data 9 0 12176 9712 5412 S 0.0 1.9 0:05.67 apache
32234 www-data 9 0 15672 13m 9332 S 0.0 2.6 0:06.08 apache
32235 www-data 9 0 15372 12m 8972 S 0.0 2.6 0:05.39 apache
32236 www-data 9 0 15368 12m 8764 S 0.0 2.5 0:06.06 apache
VIRTがメモリサイズ(KB)、RESがResidentで実メモリ使用量、SHRは共有メモリ量
スレッドモデルのMySQLの場合はRESをみれば実使用メモリがわかります。
この場合20MB
プロセスモデルのapacheの場合プロセス毎に上記では13MB、12MB,12MB使用しています
ただしSHR分は共有しているので、8〜9MBは共有です。
よって上記の場合、1プロセス当たりに必要なメモリは約5〜3MBとなります
■チューニング方法
apacheの最大プロセスに達した時何MB必要か、それは現在の空きメモリに足りるかを
算出して最大プロセス数の設定を行います。
freeコマンドで調べた used - buffer - cachedで使用量を求め空き容量がわかります。
この稿の例では248MBです。
MySQLのメモリ使用量ははプロセス数にあまり比例しないのでここでは考えません。
このapacheは5〜3MBなので、1プロセスあたり4MBとすると、248 / 4 = 62
この時点の起動apacheのプロセス数(ps auxw|grep apache|wc -lで求める)を足すと
最大プロセス数になります。
最大プロセス数が現在のMaxClientsより大きいなら増やしましょう。
最大プロセス数が現在のMaxClientsより小さいならswapするよりは小さくした方がよいですが、
いずれにしても性能が下がってしまいます。
a) 物理メモリを増やす
b) apacheのメモリ使用量を減らす
PHPで配列変数で大きなメモリを使っていたりしたら減らしましょう。
httpd.confのLoadしている不要なモジュールを減らすことである程度は減らせます。
一義的には物理メモリを増やすことをお勧めします。
※付録2 -ログの集計
WWWサーバのチューニングには1時間や1分単位のヒット数の集計ができると便利です。
awstatやwebalizerは1分単位の集計はできませんが、awkとsortコマンドを組み合わせるとログの集計が可能です。
grepを組み合わせることで障害時、チューニング時の原因究明が行いやすくなります。
下記はapacheのaccess_logの時間毎の集計例です。
※access_log
$ cat access.log|awk '{print $4}'|awk -F: '{print $1,$2}'|sort|uniq -c|sed "s/\[//"
2 05/Feb/2007 10
3 05/Feb/2007 11
369 05/Feb/2007 12
68 05/Feb/2007 15
936 05/Feb/2007 16
921 05/Feb/2007 17
225 05/Feb/2007 18
分単位の集計にしたい場合
$ cat access.log|awk '{print $4}'|awk -F: '{print $1,$2,$3}'|sort|uniq -c|sed "s/\[//"
56 05/Feb/2007 15 55
9 05/Feb/2007 15 56
23 05/Feb/2007 16 01
23 05/Feb/2007 16 06
23 05/Feb/2007 16 11