はじめに
「なんかサーバが重たい」そう思った瞬間にどのようにボトルネックを調べるのか?
どのように対処すべきなのか?を知らない人が意外に多いので、自分の振り返りも含めまとめていきます。
サーバが重いと思ったら、、、
UNIXの開発者であり、現在はGolangの実装にも携わっているRobert C. Pike氏の、
「推測するな、計測せよ」
サーバが重いと思ったら、まずは計測していきましょう。
まずはロードアベレージを調査
まずはシステム全体の負荷指標であるロードアベレージを確認してみましょう。
確認方法はメジャーな物として、top、uptimeコマンドが存在します。
そもそもロードアベレージとは、単位時間あたりの待ちタスク数を指標としています。
uptimeコマンドを実行した場合
[moriyaman@web01 ~]$ uptime
00:57:24 up 223 days, 1:43, 1 user, load average: 0.14, 0.32, 0.43
topコマンドを実行した場合
基準値は個人的な感覚も含め、1以下なら待っているプロセスはほぼない状態なので問題ないですね。
3~5ぐらいの値が出るようになれば、サービス運営者としては問題だと認識して、
ボトルネックを探るのが正しいかと思います。
ロードアベレージが低い場合
これはネットワークがボトルネックになっている可能性大です。
netstatコマンドでコネクション数を確認しましょう。
[moriyama@web01 ~]$ netstat -an | wc -l
414
数万個のコネクションがはられている場合は分散する対応が必要です。
コネクション数が高くない場合は、DNSがおかしかったりほかのホスト部分が原因の可能性大です。
ロードアベレージが高い場合
ロードアベレージが高い=タスク待ちが多いという事なので以下どちらかが問題であることがほとんどです。
①CPU
②ディスクI/O
ではどちらかが問題か探っていきます。
sar(system activity reporter)コマンドを使おう
[moriyaman@web01 ~]$ sar
Linux 2.6.18-308.8.2.el5xen (web01.localdomain) 2015年09月10日
%userはユーザモードのCPU。つまりここが高い場合は、アプリケーション側のプログラムなどがボトルネックとなっている場合は多いです。
%systemはシステム(カーネル)モードのCPU。
これはカーネル空間の処理に時間を取られていることを意味します。
ちなみに昨今ではマルチCPUが当たり前なので、allとまとめられていますが、
それぞれのCPUでも見たほうが良いと思います。
[moriyaman@web01 ~]$ sar -P ALL | head
Linux 2.6.18-308.8.2.el5xen (web01.localdomain) 2015年09月10日
00時00分01秒 CPU %user %nice %system %iowait %steal %idle
00時10分01秒 all 5.04 0.00 0.55 2.33 0.02 92.06
00時10分01秒 0 20.05 0.00 1.55 10.14 0.07 68.20
00時10分01秒 1 2.85 0.00 0.45 2.14 0.01 94.55
00時10分01秒 2 1.70 0.00 0.29 0.33 0.00 97.68
00時10分01秒 3 1.89 0.00 0.38 0.31 0.00 97.41
00時10分01秒 4 1.85 0.00 0.35 0.51 0.00 97.28
00時10分01秒 5 1.92 0.00 0.31 0.52 0.00 97.25
このようにみるとそれぞれのCPUの状況も確認できます。
上記の場合だとCPU0の%userが高いですね。同時に%iowaitも高いので、
重たいデータを引っ張っていたり、データのやり取りの多い処理が走っているのだと思います。
CPUでプログラムサイドの負荷分散はできても、ディスクが1つしかない場合、このように偏りが出るのが普通です。
%userが高い
ユーザプロセスで重い処理が走っていることが考えられますので、特定しましょう。
topコマンドがcpuの使用率順にデフォルトでソートされているかと思います。
アプリケーション側であれば、Newrelicなどのツールを入れるとアプリケーション側の
重い原因が特定しやすくなります。
%systemが高い
vmstatでiowaitの値も確認します。
[moriyaman@web01 ~]$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------
r b swpd free buff cache si so bi bo in cs us sy id wa st
2 0 72076 4367992 213616 254156 45 33 68 93 0 0 8 1 88 3 0
1 0 72076 4367836 213616 254164 0 0 0 0 1778 1435 5 0 95 0 0
0 0 72076 4368084 213616 254236 0 0 0 0 1221 866 4 0 96 0 0
0 0 72076 4367952 213656 254132 0 0 0 548 5237 4471 7 0 93 0 0
0 0 72076 4367952 213688 254104 0 0 0 244 1608 1137 7 0 93 0 0
2 0 72076 4367952 213696 254096 0 0 0 88 923 576 6 4 89 0 0
2 0 72076 4366464 213700 254100 0 0 0 124 3941 3803 13 0 87 0 0
1 0 72076 4366016 213708 254092 0 0 0 240 3048 1704 12 1 87 0 0
2 0 72076 4366132 213732 254076 0 0 0 252 3556 2098 13 0 87 0 0
0 0 72076 4365016 213744 254144 0 0 0 440 1681 1028 16 1 83 0 0
多くの場合%systemが高い場合はiowaitも高いケースが多いようです。
まずはiowaitを疑いましょう。
iowaitが低い場合は、大きいプロセスを高頻度でforkしている可能性が高いので、topコマンドで確認して下さい。
%user/%systemに比べて%iowaitが高い
この場合はI/O要求に対して、ディスクの処理速度が追いついていない状態です。
メモリが不足してswapが発生していないか確認しましょう。
[moriyaman@web01 ~]$ sar -W
Linux 2.6.18-308.8.2.el5xen (web01.localdomain) 2015年09月10日
- pswpin/s 1秒間にスワップインしているページ数
- pswpout/s 1秒間にスワップアウトしているページ数
[moriyaman@web01 ~]$ sar -B
Linux 2.6.18-308.8.2.el5xen (web01.localdomain) 2015年09月10日
- pgpgin/s 1秒間にスワップ領域からメモリへページ・インしたページ数
- pgpgout/s 1秒間にメモリからスワップ領域へページ・アウトしたページ数
上記で調べたppswpout/sはスワップ・アウトしたページ数であり、pgpgout/sはページ・アウトしたキロバイト数である。故にスワップが多発しているか否かはpswpin/s pswpout/s を見て判断するようにして下さい。
スワップって何?
そもそもこの辺を勉強した事がない人(?)はスワップって何?って感じだと思います。
※僕も昔はそうでした
ディスク
- 参照) パソコンの基礎知識
少し基礎知識的に書いておくと一般的に、ディスクは容量あたりの値段がメモリに比べて圧倒的に安いです。
しかし上記のように物理的なアクセスまでの時間がかかるので、レスポンスは遅くなります。
メモリ
一方でメモリはディスクのような物理的なアクセスはなく、特定の番地にあるデータに対してアクセスします。
容量あたりの値段はディスクに比べて高いですが、その分アクセス速度はディスクの10万倍~100万倍です。
OS(Linux)
上記の事を踏まえると、データはできる限りメモリに保持してアクセスしたいですよね。
一般的なOSは積んでいるメモリのできる限りでデータのキャッシュを保持しようと勝手にしてくれます。
OSが仮想メモリ機構としプロセス⇔メモリ間のやりとりを行います。
iowaitが高い際に確認したいのが、このpage-inが多発していないかどうか?
これは、メモリが足りてなくてディスクとのやり取りを頻繁に行ってしまっている状況です。
こうなるとパフォーマンスがかなり低下するので、メモリを増設することを検討しましょう。。。
iowaitが高い場合はまずはスワップを確認 → page-inが高いとスラッシングが起こっているので要注意です!
重くならないサーバ設計とは?
-
CPUを喰いまくるようなプログラムは書かない
→ 書いてもnewrelicなどのモニタリングツールを入れてちゃんと監視・計測しておく -
ディスク容量とメモリをほぼイコールにできるのであれば、ディスクの内容をほぼメモリ上にキャッシュできるのでそういう設計を心がける。
(DBが大きすぎるのであれば、パーティションして分散させたりする)
※心が痛い・・・ -
基本的にはアクセスを分散させて集中させない。
とくにRDMSでの設計は気を配る
- 正規化がされているか?
- ディスク容量 = メモリで維持出来ているか?
- サービス上で不要なデータはDBを別で保持出来ないか? / パーティション出来ないか?
- switch_pointなどを使ってreadをslaveにwriteをmasterに飛ばすような分散は出来ているか?