<性能テスト>
■ボトルネックの解析の基本
性能限界が生じた場合にいきなり、システムリソースの計測値から
調査するのはふさわしくない。
サーバーリソースの細かい計測値を複数取得して比較検討しても
ボトルネックが切り分けしずらい。
ボトルネックの発生するタイミングはサーバーリソースを計測せずともわかる。↓
応答時間:性能ボトルネックが発生するまでは一定で推移
=>途中応答遅延している時点でボトルネック
スループット:性能ボトルネックが発生するまでは増加を続ける
=>途中頭打ちになっている時点がボトルネック
■ボトルネック詳細要因の切り分け方法
ボトルネックのタイミングのサーバーリソースを確認
=>ノード単位の切り分け、どのサーバーがボトルネックか?
ネットワーク機器
性能限界時に顕著にわかる現象:CPU使用率100%、帯域使用率100%
主な劣化要因:物理ボードの処理能力限界
システムバス処理上限
単純なCPU処理限界
バッファメモリ不足
Webサーバー
性能限界時に顕著にわかる現象:CPU使用率100%、NIC帯域使用率100%
主な劣化要因:単純にOSの応答処理能力を超えている
H/Wのスループットの上限
APサーバー
性能限界時に顕著にわかる現象:CPU使用率100%
主な劣化要因:非効率なプログラム・アプリ設計
不適切なヒープ配分
不適切なスレッド数定義
メモリ不足
DBサーバー
性能限界時に顕著にわかる現象:CPU使用率100%、ディスクI/O増加(20~40%以上)
主な劣化要因:非効率なクエリ
不適切なインデックス設定
非効率なテーブル設計
不適切なバッファキャッシュの配分
メモリ不足
=>ノードがわかれば、アプリケーション毎に詳細にボトルネック要因を確認
追求していく。(計測方法や負荷実施方法を何度も変え、繰り返し負荷生成を
行ってボトルネックを特定していく)
◎まとめ
ボトルネック解析上の最大の障壁は「どの担当者が解析すべき問題なのか」判断
できないことであり、その切り分けを行うためにボトルネック解析へのアプローチ
があると考える。
■パフォーマンス問題と切り分け
◎1トラブルの再現
手動もしくは負荷生成ツールによりトラブルを再現する
◎2トラブル箇所の切り分け
・どのサーバーの部分で問題になっているかを切り分ける
・多くの場合、システムのパフォーマンスが低下する要因は、H/WやS/Wのリソース不足により
発生するボトルネックである
効率的に切り分ける↓
1.H/Wリソース分析
まず大まかにサーバーリソースのハードウェアリソースを分析
2.要因特定
H/Wリソースの分析、再現方法、各種ログから原因を特定
3.DBサーバーがボトルネック
H/Wリソース分析で原因を特定できない場合、DBサーバーがボトルネック
になっているか否かを判断する
————-
4.AP詳細分析
APサーバーがボトルネック or 各サーバーに顕著なボトルネックがみられない場合
=>AP詳細分析。
*Web/AP/DB構成のWebシステムではDB,APでボトルネックとなっている可能性が高い
=>リクエストを前段で受けているAPサーバーから分析したほうが早く要因を特定できる場合がある。
5.原因を特定
APサーバーを詳細分析して原因を特定できない場合、DBサーバーを分析する
————-
6.DB詳細分析
APサーバーを分析してもボトルネックを特定できない場合、実施する。
Oracleであれば、STATSPACKやAWRなどを利用して分析します。
7.原因を特定
DB詳細分析で原因を特定できない場合、もう一度、これまでの分析を見直す
◎3トラブルへの対応
一口にボトルネック対策といっても、ボトルネックには多種多様な原因がある。
複数考えられる対策から、最善の策を選択することが重要
・コストと効果
・解消のためにアプリケーションやミドルウェアのパラメータをチューニング
=>再テスト
=>コストが発生
・ボトルネックは無限
したがってボトルネックが存在しないという基準は設けてはいけない。
・ハードウェアの追加
必ずしもハードウェアの追加で解消することができるとは限らない。
<主なチューニング>
OS(Linux):プロセス数(threads-max)、ファイルディスクリプタオープン数(file-max)
OS(Windows):メモリ空間リサイズ
Webサーバー:待ち受けプロセス数やスレッド数
APサーバー:待ち受けプロセス数やスレッド数、データベースコネクションプール数、JVMヒープサイズ
DBサーバー:セッション数、共有メモリ容量
アプリケーション:効率のよい処理に置き換える↓
無駄な処理の削除
適度な同期の解消
ループ内のオブジェクト生成
アルゴリズム見直し
オブジェクトプーリング
indexの張りなおし
SQL文の修正
ハードウェア:CPU,メモリ、サーバー
◎4トラブル対策後
パフォーマンストラブルが解消したか否かを評価する具体的な判断基準を
設けておく。
↓実作業
————————–
■ボトルネックを見分ける
・リアルタイム監視による調査
「top」
# top -d 1
load average:
過去1,5,15分の「実行待ち状態のプロセス平均数」
*CPUx4を超えているとボトルネック?
・ログ取得による調査
CPU関連
使用率、vmstat、us/sy/waの合計
us:ユーザーレベルのCPU実行時間の割合
sy:カーネルレベルのCPU実行時間の割合
wa:I/O待機の割合
*waが大きいとCPUリソースをI/O処理待ちでかなり使っていることになる。
メモリ関連
実行待ちプロセス、vmstat、r
r:実行待ち状態であるプロセス数
スワップイン発生量、vmstat、si
si:Swap領域からメモリ領域に返却されたメモリ量(Kバイト/秒)
スワップアウト発生量、vmstat、so
so:Swap領域にメモリ領域から移されたメモリ量(Kバイト/秒)
ディスク関連
ディスクビジー率、iostat -d -x、%util
%util:I/Oリクエストを発行しているときのCPU利用率
実行待ちトランザクション数、iostat -d -x、avgqu-sz
avgqu-sz:サービスを待機中のトランザクション数の平均値
ネットワーク関連
*netstatをつかってネットワーク通信量の監視はできないのでsar
通信料、sar -n、rxbyt/sとtxbyt/sの合計
rxbyt/s:受信バイト量(バイト/秒)
txbyt/s:送信バイト量(バイト/秒)
■ログをグラフ化する
■分析する
1つのリソースだけ判断するのではなく、1元的、多角的に分析する。
<ボトルネック判断基準>
CPU
使用率、実行待ちプロセス数:
CPU利用率85%を超えている、且つ実行待ちプロセス数がCPUコア数x4を超えている
*スレッドもプロセスとして管理されるため、実行待ちプロセス数にはスレッド数が含まれる
メモリ
スワップイン、アウトの発生量:両者が同時に大量発生している
*起動後一定時間使用されないメモリ領域は、スワップ領域に退避する機能があり、
「スワップアウト」だけが発生するのは正常な動作
ディスク
ディスクビジー率:一般に40%を超えると注意、50%を超えると警告レベル
*ディスクビジー率50%を越えると、ディスクがアイドルの時に比べて、ディスク処理時間が2倍になる
実行待ちトランザクション数:搭載物理ディスク数x2を超えている
*DBサーバーは高め
ネットワーク
通信量:帯域を使い尽くしている
*実行帯域をあらかじめ測定しておく
——————————————-
負荷計測によるツール
ps
ps auxw(BSDスタイル)
VSZ: 仮想メモリに割り当てられたメモリ量
RSS: 実際に割り当てられた物理メモリ量
*プロセスから見た場合、自身が利用しているメモリサイズと、実際に物理メモリの中で
そのプロセスが使っているメモリサイズとの間にはギャップがある。これがVSZとRSSの差。
仮想メモリ機構:
・物理メモリ上は不連続な領域を、プロセスに対して連続したメモリ領域としてみることができる
・それぞれのプロセスに対して、プロセス毎に独立したメモリ空間を持てるように見せかけられる
=>他のプロセスによる不正なメモリ変更から、プロセスを保護できる
・本来物理メモリに搭載されている容量以上のメモリを扱えるかのように、プロセスに見せかけられる
STAT:プロセスの状態
R今まさにCPU上で実行されている
S仕事がない、or何かの事象を待ってスリープしている
DディスクI/Oを待って仕事ができない状態
Tデバックのためトレースされている
Zゾンビ
TIME:プロセスがCPUをどのくらいの時間消費したかを示す値
暴走しているプロセスがあった場合、このTIMEの絶対数、もしくは
何度psを実行した際の差分をみる
*例えば、無限ループするようなプロセスはSTATがRでTIMEが目に見えて上昇する
Linuxのマルチスレッドの実装
最近はNPTLに統一されているが、ディストリビューションやスタティックリンクされている
バイナリによっては、LinuxThreadsを採用しているものもある。
2つのマルチスレッドの実装には、パフォーマンスとpsのプロセス表示に差がある。
– LinuxThreads
スレッド1本1本を、通常のプロセスと同様、1つのプロセスとして表示する
– NPTL
-Lオプション(スレッド数、スレッドIDを表示するオプション)を加えない限り、スレッド
を1本のプロセスとして表示する。
psコマンドのうまいつかいかた
問題等発生時に状況を回避する前psで状態を保存しておく。
# ps auxw -L –sort=-vsz > /tmp/ps.20070101
*メモリ使用量順にソート
top
– 負荷のおおよその目安になるload average
「実行したいが、何らかの待ち(CPUの割り当て待ちやディスクI/O待ち)などで実行できず
待たされているプロセス(スレッド)の数」
1.00である時
「ある瞬間待ち状態にあったプロセスが○分間の間、常に1つ以上あった。」という意味。
・この値がいくつ以上であったらまずいという指標は存在しない。
・CPU数にも依存する
=>あくまで目安、システム全体の負荷指標(個々のH/Wリソースの状況を表すものではない)
通常1以下の低い値であったのに、ある日突然5、10といった値に跳ね上がったらなんらかし
らの異常があると考えられる。
CPUのモード
カーネルモード
ユーザーモード
usが高い:ユーザーモードのプログラム処理で時間を消費している。
=>つまりカーネル以外のところに原因がある。
syが高い:カーネルモードで時間を消費してる。
=>つまりカーネル内部での処理で時間がかかっている、もしくは何らかの
プログラムからシステムコール呼び出し回数が多い
id:高いと、アイドル、CPUリソースが十分にある
wait:高いと、ディスクI/Oがシステム全体のボトルネックになっている証明
=>ディスクの処理遅延発生
メモリ利用状況
Linuxはディスクからデータを読み取ると、それをメモリ上に可能な限りキャッシュする
=>ページキャッシュ機構
Linuxはページキャッシュの上限を決めていないのでメモリの空きがある限りその空き分をページ
キャッシュに確保する。
アプリケーションでメモリが必要になった場合は、ページキャッシュで確保した分が優先的に開放
され、アプリに割り当てられる。
sar
sar 1 100 :1秒おきに100回
・当日のデータを見たい場合はオプションなし
・当日よりも過去データをみたい場合はsar -f
・リアルタイムに監視したい場合は「sar 1 100」
sar -u:CPU負荷を見る
sar -u -P ALL:CPUごとの状況
<表示>
all:全てのCPUの合計を割り算した総計
0,1などは:個々のCPUの消費時間を表示
sar -r:メモリ利用状況を見る
sar -q:load averageとランキューにたまったプロセスの数
-runq-sz:ランキュー(CPU時間割り当てを待っているプロセスが並んでいるキュー)に
溜まっているプロセスの数
-plist-sz:稼動しているプロセスの総数
sar -W:スワップ発生状況
OSは物理メモリが不足してくると優先度の低いメモリ領域を2次記憶装置上のスワップ
領域に退避させて、物理メモリに空きを作ろうとする。
この際、ディスクI/Oが発生し、システム全体のスループットは急激に低下する。
=>vmstatでもわかる。
sar -c:単位時間のプロセス生成数
■load averageの詳細
load averageが低い:ランキュー内で待たされているプロセスがほとんどない
load averageが高い:ランキュー内でたくさんのぷろせすが待たされている状態
2.6.20では・・・
TASK_RUNNING(psでのSTATはR):CPUでの実行準備が整ったプロセス、実行可能状態
TASK_UNINTERRUPTIBLE(psでのSTATはD):ディスクのI/O待ちなどで待たされているプロセス
ということで、load averageが高いとは・・・
・計算を実行したくてもCPU割り当てが行われず実行できていないプロセス
=CPUアイドルが不足している
・ディスクI/O待ちで待たされているプロセス
=ディスクI/Oが多すぎて待たされている
つまりこの2つの状態であるプロセスを探し分析すればボトルネックを見極められる!
TASK_UNINTERRUPTIBLE=
・・・本来実行したい処理の実行をプロセスが待たされる事もあるので”負荷”と換算される。
■マルチCPU環境における、CPU時間とload average値
マルチCPUである場合、0番に若干負荷が偏るのは正常である。
タスクスケジューラはある程度負荷があるときに限り、他のCPUにタスクを割り振る。
そうでない場合は、常に特定のCPU(多くの場合は0番)が負荷を請け負うのでこうなる。
ここで、iowaitが発生している場合はどうか、
(例)allでみると、iowait値は20%となるが個別にみた場合、0番の%iowatが
80%となっている。=>分散されていない!
『理由』
タスクスケジューラーによるCPU間のタスク分散(sched.cのload_balance()関数)は
「TASK_RUNNING状態のプロセスがランキューに溜まっている場合は負荷を分散する」
ロジックだから。
I/O待ちはTASK_RUNNING状態ではなく、TASK_UNINTERRUPTIBLE状態でのプロセスである。
だからどんなにI/O待ちプロセスがランキューに溜まっていても、そのプロセスは他の
プロセスに分散されれない。
<まとめ>
・CPUに負荷がかかっている場合、ある程度の負荷になると別のCPUにタスクが割り当てられる。
・I/Oがボトルネックになっている場合は、CPU性能を活かす事ができない。
・マルチCPU環境では個別の値を見なければ判明しないことがある。
■よくある説明
「CPUの数をベースにload averageの値を見ましょう、CPUが1つなら1.00以下に、4つなら4.00以下に。」
以下のことから、ボトルネックがI/Oにある場合は誤りである。
「I/Oがボトルネックになっている場合は、CPUが他のCPUへタスクの分散は行はない、
一方でload average値は上昇する」
逆に、負荷がメモリやI/Oではなく、CPUにかかっているという理想的な状態であれば
「load average値はCPUの数で割れ」という説が意味を持つ。
■ページキャッシュと物理メモリの関係
・空きメモリを十分に用意しておけば、アプリが利用するデータはキャッシュできる。
・OSとユーザープロセスが使用するメモリ量と搭載している物理メモリ量にあまり差がない場合、
ページキャッシュ用に十分なメモリ領域は確保されない。
・ページキャッシュに乗り切らない部分のデータへのI/Oは常に物理デバイスへのI/Oとなり
プロセスを長く待たせることになる。
■その他ケーススタディ
トラフィックが平常時と変わらないにもかかわらず、CPU利用率が突然上昇するのは、
多くの場合アプリケーションの欠陥が原因。
(syが高くなり、アプリケーションの何らかの処理がシステムコールを頻繁に呼び出し、
カーネルの処理を増やしている、など)