つれづれなるままに、日ぐらしパソコンに向かひて、心にうつりゆくデータベースの性能問題の切り分け方法をそこはかとなく書き付くれば、あやしうこそ物狂ほしけれ。なエントリ(書きかけ)。一度、脳内をフラッシュしてからまとめるべし。
性能問題の原因
性能問題の原因を以下の2つに分類する。
切り分け手順の分類
システム全体が遅いケースと一部の処理が遅いケースで切り分け手順は変わる。
切り分けはOSレイヤーとデータベースレイヤーの2つの観点から行う。
- システム全体が遅いケース
- 交通量が多いか
- 経路の途中で詰まっていないか
- 一部の処理が遅いケース
- 交通量が多いか
- 経路の途中で詰まっていないか
切り分けフロー
ワイルドな切り分けフローを書いてみる。
- システム全体が遅いケース
- 交通量が多いか(OSレイヤー)
sar でだいたいのことはできると思うが、とりあえずベタに書いてみる。
$ uptime 13:30:10 up 2 days, 23:46, 1 user, load average: 3.78, 3.01, 1.76
uptime で load average を見る*1。load average は CPU待ち*2 + I/O待ち*3のプロセス数*4の平均値。左から1分間、5分間、15分間の平均値。この数をCPUコア数で割って2以上だと待ちが発生している*5。例えると、load average はマック*6のレジに並んでいるお客さんの行列の人数。例えば、合計でお客さん3人並んでいても、レジが3台あれば待ちは発生していないので無問題。ちなみにこの環境は2コアなので、load average の直近1分間の平均が 3.78 は結構重い状態。2コアとも常に処理を実行中で1プロセスが待ちの状態が1分続いている。
$ sar -s 13:00:00 01:00:01 PM CPU %user %nice %system %iowait %steal %idle 01:10:01 PM all 0.11 0.00 0.06 15.45 0.10 84.28 01:20:01 PM all 0.04 0.00 0.05 15.60 0.11 84.21 01:30:01 PM all 74.00 0.00 0.06 2.56 0.07 23.31 Average: all 24.72 0.00 0.06 11.20 0.09 63.93
次に sar でCPU使用率を見る。-sオプションで表示開始時刻を指定している*7。まず %user と %system を見る。DBのプロセスなどユーザープログラムが忙しいときは %user の値が大きくなる。%system はシステムコールやカーネルスレッドなどOSカーネルがCPUを使用した割合*8。通常 %system がそんなに大きい値になることは少ない。%user でも %system でもCPU使用率が高くなる要因として、単純に処理量が多い以外にスピンロックで大量のプロセスやスレッドがCPUを使いながら待機したり、スピン*9してハングしているなどのケースがある。100 ÷ CPUコア数*10の倍数の場合は、一部のコアの使用率が100%になっているかもという感覚を持っておくとよい。例えば、4コアで25%だと1コアが100%になっていることがある。%iowait が高い場合は、CPUは空いていてプロセスがI/O待ちでスリープしている割合が高くI/Oがボトルネックになっていることが多い*11。
$ sar -P ALL -s 13:00:00 01:00:01 PM CPU %user %nice %system %iowait %steal %idle 01:10:01 PM all 0.11 0.00 0.06 15.45 0.10 84.28 01:10:01 PM 0 0.16 0.00 0.07 29.06 0.11 70.60 01:10:01 PM 1 0.06 0.00 0.05 1.84 0.10 97.95 01:20:01 PM all 0.04 0.00 0.05 15.60 0.11 84.21 01:20:01 PM 0 0.06 0.00 0.07 29.72 0.11 70.04 01:20:01 PM 1 0.02 0.00 0.03 1.48 0.10 98.37 01:30:01 PM all 74.00 0.00 0.06 2.56 0.07 23.31 01:30:01 PM 0 75.46 0.00 0.08 4.98 0.08 19.40 01:30:01 PM 1 72.55 0.00 0.04 0.13 0.07 27.21 Average: all 24.72 0.00 0.06 11.20 0.09 63.93 Average: 0 25.23 0.00 0.07 21.25 0.10 53.34 Average: 1 24.21 0.00 0.04 1.15 0.09 74.51
sar -P ALL でCPUコア別の使用率を確認する。この環境は0番と1番の2コアであることがわかる。全コアの平均ではCPU使用率が低く見えても、内訳を見ると実は一部のコアだけ100%で他のコアは暇ということもある。
$ top top - 13:46:10 up 3 days, 2 min, 4 users, load average: 4.83, 3.90, 2.93 Tasks: 116 total, 5 running, 111 sleeping, 0 stopped, 0 zombie Cpu(s): 97.1%us, 2.9%sy, 0.0%ni, 0.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st Mem: 2097152k total, 2085004k used, 12148k free, 143416k buffers Swap: 6258680k total, 61344k used, 6197336k free, 1513876k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 15042 oracle 25 0 77860 1416 1116 R 99.7 0.1 23:39.52 perl -e while(1){} 15046 oracle 25 0 77860 1420 1116 R 97.8 0.1 17:50.85 perl -e while(1){} 1 root 15 0 10348 684 576 S 0.0 0.0 0:00.16 init [3] 2 root RT -5 0 0 0 S 0.0 0.0 0:00.14 [migration/0] 3 root 34 19 0 0 0 S 0.0 0.0 0:00.03 [ksoftirqd/0] 4 root RT -5 0 0 0 S 0.0 0.0 0:00.00 [watchdog/0] 5 root 10 -5 0 0 0 S 0.0 0.0 0:00.01 [events/0] 6 root 10 -5 0 0 0 S 0.0 0.0 0:00.00 [khelper] 7 root 10 -5 0 0 0 S 0.0 0.0 0:00.00 [kthread]
全体、もしくは一部のコアのCPU使用率が高い場合は top でどのプロセスが原因か調べる。top 起動後、「c」を押すとプログラム名ではなくコマンドラインが表示されるのでわかりやすい*12。例えば、Oracle Database は $ORACLE_HOME/bin/oracle を実行しているので、プログラム名だとサーバープロセスもバックグラウンドプロセスも oracle と表示されるが、コマンドラインにすると、ora_lgwr_orcl のように表示され、どのプロセスかわかりやすい。次に「O」を押すと、ソートする項目を選ぶことができる。ここでは「k」を押してCPU使用率が高い順にソートして表示させている。「n」ならメモリ使用量が大きい順になる。*13
デフォルトで3秒間隔で表示が更新されるが、%CPU はその3秒間に1コアを使用していた割合を表す。この例では一番上の perl ワンライナーが 99.7% となっているが、これは1コアを3秒間のほぼ占有している。
$ vmstat 5 procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------ r b swpd free buff cache si so bi bo in cs us sy id wa st 2 2 60580 25848 100408 1482816 0 0 880 40 7 50 5 0 75 19 0 4 2 60580 25600 100424 1482820 0 0 20837 36 697 489 99 1 0 0 0 3 2 60580 31600 100436 1482820 0 0 28834 66 881 485 99 0 0 0 0 2 2 60580 31600 100440 1482824 0 0 23909 58 771 478 100 0 0 0 0 4 2 60580 31600 100472 1482812 0 0 38050 62 1093 501 99 1 0 0 0 3 4 60580 31600 100476 1482836 0 0 24733 56 787 473 99 1 0 0 0 2 7 60580 31724 100476 1482836 0 0 29248 37 891 478 99 1 0 0 0
vmstat ではまずr列とb列を見る。r列はランキューつまりCPU待ち、b列はI/O待ちのプロセス数*14。si、soの値が大きいとメモリ枯渇によりスワップが発生していると考えられる*15。bi*16、bo*17はブロックデバイスに対してI/Oを行ったブロック数。
$ mpstat -P ALL 5 10:09:48 AM CPU %user %nice %sys %iowait %irq %soft %steal %idle intr/s 10:09:53 AM all 0.00 0.00 0.00 11.67 0.00 0.00 0.10 88.24 177.84 10:09:53 AM 0 0.00 0.00 0.00 23.35 0.00 0.00 0.20 76.45 169.66 10:09:53 AM 1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00 8.18 10:09:53 AM CPU %user %nice %sys %iowait %irq %soft %steal %idle intr/s 10:09:58 AM all 0.00 0.00 0.00 31.39 0.00 0.00 0.10 68.51 159.60 10:09:58 AM 0 0.00 0.00 0.00 62.40 0.00 0.00 0.20 37.40 150.20 10:09:58 AM 1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00 9.40 10:09:58 AM CPU %user %nice %sys %iowait %irq %soft %steal %idle intr/s 10:10:03 AM all 0.10 0.00 0.10 1.38 0.00 0.00 0.10 98.32 167.00 10:10:03 AM 0 0.20 0.00 0.00 2.80 0.00 0.00 0.20 96.80 156.40 10:10:03 AM 1 0.00 0.00 0.20 0.00 0.00 0.00 0.00 99.80 10.60
mpstat でCPUコア別の使用率と割込みなどの情報を確認する。特定のCPUに偏りがないか見る。また、%irq、%soft を確認することで割込みでCPUを使用している割合がわかる。%irq はハードウェア割込み、%soft はソフトウェア割込み。例えば、特定のCPUで %irq の割合が高い場合は Solaris の場合、intrstat で、どのデバイスで割込みが多く発生しているか確認することができる。異常に偏りがある場合は、OSサポートベンダーに調査を依頼するなり、オープンソースなら自分でソースを追い掛けるなりすると良い。
-
- 交通量が多いか(DBレイヤー)
- 経路の途中で詰まっていないか(OSレイヤー)
- 経路の途中で詰まっていないか(DBレイヤー)
- 一部の処理が遅いケース
- 交通量が多いか(OSレイヤー)
- 交通量が多いか(DBレイヤー)
- 経路の途中で詰まっていないか(OSレイヤー)
- 経路の途中で詰まっていないか(DBレイヤー)
前提
- 正確さよりわかりやすさに重点をおき、可能な限り情報をそぎ落としている。
- Linux を前提に書いているが、考え方は他のOSでもだいたい同じ。
- できるだけ、どの環境でも入っているコマンドを使用している。
注意
- SystemTap、DTrace など本番環境で使うには負荷の高いコマンドも記載しています。
- この記事に書いているコマンドは内容を理解した上で自己責任で使用してください。
関連
参考
[24時間365日] サーバ/インフラを支える技術 ?スケーラビリティ、ハイパフォーマンス、省力運用 (WEB+DB PRESS plusシリーズ)
- 作者: 安井真伸,横川和哉,ひろせまさあき,伊藤直也,田中慎司,勝見祐己
- 出版社/メーカー: 技術評論社
- 発売日: 2008/08/07
- メディア: 単行本(ソフトカバー)
- 購入: 133人 クリック: 2,270回
- この商品を含むブログ (288件) を見る
宣伝
絵で見てわかるITインフラの仕組み (DB SELECTION)
- 作者: 山崎泰史,三縄慶子,畔勝洋平,佐藤貴彦,小田圭二
- 出版社/メーカー: 翔泳社
- 発売日: 2012/09/19
- メディア: 単行本(ソフトカバー)
- 購入: 11人 クリック: 204回
- この商品を含むブログ (7件) を見る
*1:top でも確認できる
*2:実行可能状態(TASK_RUNNING)のプロセスの数。LinuxではCPU使用中でもCPU待ちでもプロセスの状態は実行可能状態(TASK_RUNNING)になる。
*3:スリープしているがシグナルによる待機状態解除不可(TASK_UNINTERRUPTIBLE)
*4:またはスレッド
*5:I/O待ちはCPUを使っていないので厳密にはちょっと違うが、まずはざっくり行列の長さを見る。あと、LinuxではCPUを使用中のプロセスもランキューにカウントされるが、SolarisではカウントされないなどOSの実装によって異なる。
*7:-eで終了時刻を指定できる。このあたりのオプションは問題が発生した時間帯を把握していて特定の範囲を指定したい場合などに使うと見やすい。
*8:OSによっては割込みも %system にカウントされる。Linux では割込みは %system ではなく、%irq(ハードウェア割込み) と %soft(ソフトウェア割込み) にカウントされる
*9:ループと言ったほうが分かりやすいかもしれない。例えば perl -e 'while(1){}' という Perl ワンライナーを実行すると1コアが100%になる。これはI/Oなどを発行せずにただCPU命令を実行しているとCPU使用率は100%になることを意味している。
*10:ハイパースレッディングのようなものを使っている場合はスレッド
*11:ただし、他のプロセスがCPUを使うと%iowaitにはカウントされなくなる。つまり、I/Oがボトルネックかどうかは %iowait だけでは判断できない。そこは vmstat の b 列で判断できるはず。後は sar とか
*12:プログラム名で表示されている状態で「c」を押すとコマンドラインになり、さらに「c」を押すとプログラム名になる。このようにある同じ操作を繰り返すことで、機能や状態のON/OFFを切り替える仕組みを「トグル」と言う
*13:「O(大文字のオー)」を押したときに画面が切り替わり、どのキーを押すとどの列でソートされるかが表示されるのでそれに従う。ちなみに「o(小文字のオー)」を押すと表示する列を選択することができる
*14:同期I/OではI/O要求を発行するとブロックされる、つまり待つが非同期は待たないので非同期I/Oではb列には表れないので、iostat などでブロックレイヤーでのIOPS、キューの長さなどを確認する必要がある
*15:メモリが枯渇していなくても使われていないとページアウトされた気がする
*16:読み込み
*17:書き込み