サーバが重いときのボトルネックの見つけ方と対応方法について紹介します。
ボトルネックの種類
ボトルネックには以下の種類があります。
- CPU使用率
- ディスクI/O
- メモリ使用量
- TCPコネクション
- 外的要因
外的要因とは重くなっているサーバ自身ではなくリモートホストやDNSなどに問題があるケースです。
サーバの状態とボトルネックの対応
サーバが重い時のサーバの状態と、ボトルネックの対応をまとめると以下のようになります。
- ロードアベレージが高い
- ユーザーモードのCPU使用率が高い
- アプリケーション起因のCPU使用率がボトルネック
- システムモードのCPU使用率が高い
- アプリケーション以外の要因で生じるCPU使用率がボトルネック
- I/O待ちが長い
- スワップが発生している
- メモリ不足がボトルネック
- スワップが発生していない
- ディスクI/Oがボトルネック
- スワップが発生している
- ユーザーモードのCPU使用率が高い
- ロードアベレージが低い
- TCPコネクション数が多い
- TCPコネクションがボトルネック
- TCPコネクション数は多くない
- 外的要因がボトルネック
- TCPコネクション数が多い
ボトルネックを発見するための具体的な手順
ボトルネックを見つけるには以下の手順でサーバを調査するとよいです。
- ロードアベレージの確認
- ロードアベレージが高い場合はCPU使用率とI/O待ちを確認
- I/O待ちが長い場合はスワップの有無を確認
- ロードアベレージが低い場合はTCPコネクション数を確認
以下では各手順について解説をします。
ロードアベレージの確認
ロードアベレージが高い場合は『CPU使用率』『ディスクI/O』『メモリ使用量』のいずれかが、低い場合は『TCPコネクション』もしくは『外的要因』がボトルネックです。
ロードアベレージはtop
のload average
などで確認できます。
top - 14:27:01 up 0 min, 1 user, load average: 1.65, 0.50, 0.17
Tasks: 119 total, 1 running, 118 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 1.0 sy, 0.7 ni, 98.0 id, 0.3 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 499816 total, 63044 free, 223308 used, 213464 buff/cache
KiB Swap: 2097148 total, 2047708 free, 49440 used. 243264 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1483 netdata 39 19 95136 29752 2004 S 1.0 6.0 0:00.96 netdata
1635 root 39 19 5692 1732 172 S 0.7 0.3 0:00.39 apps.plugin
1623 netdata 39 19 1736 780 484 S 0.3 0.2 0:00.03 bash
目安として、ロードアベレージはCPU1コアあたり3~5程度あると高いといえます。
もしCPUのコア数が2の場合は6~10程度だと高ロードアベレージということになります。
CPUのコア数はgrep cpu.cores /proc/cpuinfo | sort -u
で確認ができます。
$ grep cpu.cores /proc/cpuinfo | sort -u
cpu cores : 1
ロードアベレージが高い場合はCPU使用率とI/O待ちを確認
I/O待ちが長い場合は『ディスクI/O』もしくは『メモリ使用量』が、CPU使用率が高い場合は『CPU使用率』がボトルネックです。
『CPU使用率』はさらにユーザーモードとシステムモードに細分化されます。
ユーザーモードのCPUとはアプリケーションの実行に関するCPU、システムモードのCPUとはカーネルの実行に関するCPUのことをいいます。
つまり、ユーザーモードのCPU使用率が高い場合はアプリケーション起因、システムモードのCPU使用率が高い場合はアプリケーション以外の要因で生じるCPUがボトルネックです。
システムモードのCPU使用率が高い場合はI/Oも高い可能性があるので、あわせて確認をしておくとよいでしょう。
CPU使用率とI/O待ちはsar -u [時間刻み幅]
やdstat -a
などで確認できます。
たとえばsar -u
であれば%user
、%system
、%iowait
の項目を確認します。
$ sar -u 2
Linux 4.4.0-210-generic (160-251-11-228) 06/20/2021 _x86_64_ (1 CPU)
02:29:00 PM CPU %user %nice %system %iowait %steal %idle
02:29:02 PM all 0.00 0.50 1.50 0.00 0.00 98.00
02:29:04 PM all 0.00 0.51 1.01 0.00 0.00 98.48
02:29:06 PM all 0.00 1.01 0.51 0.00 0.00 98.48
I/O待ちが長い場合はスワップの有無を確認
スワップが発生している場合は『メモリ使用量』が、発生していない場合は『ディスクI/O』がボトルネックです。
スワップ発生の有無はsar -W [時間刻み幅]
、vmstat [時間刻み幅]
、dstat --swap
などで確認できます。
たとえばsar -W
であればpswpin/s
とpswpout/s
の項目を確認します。
$ sar -W 2
Linux 4.4.0-210-generic (160-251-11-228) 06/20/2021 _x86_64_ (1 CPU)
02:30:08 PM pswpin/s pswpout/s
02:30:10 PM 0.00 0.00
02:30:12 PM 0.00 0.00
02:30:14 PM 0.00 0.00
ロードアベレージが低い場合はTCPコネクション数を確認
TCPコネクション数が多い場合は『TCPコネクション』、少ない場合は『外的要因』がボトルネックです。
TCPコネクション数はnetstat
やss
などで確認できます。
たとえばnetstat
であればnetstat -an | wc -l
の数を確認します。
$ netstat -an | wc -l
111
目安として、値が数万の場合はTCPコネクション数が多いといえます。
ボトルネックの解消方法
ボトルネックを解消するための具体的な方法について紹介します。
アプリケーション起因のCPU使用率がボトルネックの場合
アプリケーションの実装に問題があるためCPU使用率が高くなっている状態です。
top
などでCPU使用率の高いプロセスを特定し、当該プロセスの実装に問題がないかプログラムのロジックを再確認します。
たとえばNew RelicやDatadogをはじめとしたアプリケーションモニタリングツール(APM)を利用することでボトルネックとなっているロジックの特定ができます。
アプリケーション以外の要因で生じるCPU使用率がボトルネックの場合
プロセスやスレッドの動作、もしくはI/O待ちが原因でCPU使用率が高くなっている状態です。
アプリケーション以外の要因でCPU使用率が高い場合、I/O待ちも長いケースが多いです。
ですので、I/O待ちもあわせて確認をし、ディスクI/Oがボトルネックの場合はそちらの対応をします。
I/O待ちに問題がない場合はtop
などを利用して高頻度でforkされているプロセスがないか確認をし、存在する場合はプロセスの改善をします。
メモリ不足がボトルネックの場合
メモリが足りないためメモリ上にデータがのり切らずスワップが発生してしまい、その結果I/O待ちが長くなっている状態です。
まずはtop
などでメモリ消費量が多いプロセスを特定し、当該プロセスでのメモリの使い方を改善できないか・使い方は適切であるのか確認します。
たとえば大容量のデータを一度にメモリへのせる実装をしているのであれば改善の余地があります。
メモリの使い方に問題がないのであれば単にメモリが足りていないのが原因であるためメモリ増強を検討します。
ディスクI/Oがボトルネックの場合
読み書きの頻度が高いためスワップこそ発生していないもののディスクの処理が追いついていない状態です。
ディスクI/Oの使用状況はsar -b [時間刻み幅]
などで確認ができます。
pidstat -d
などで読み書きの頻度が高いプロセスを特定し、キャッシュを導入したりプログラムを修正したりすることで読み書きの頻度を減らすようにします。
TCPコネクションがボトルネックの場合
許容量以上のコネクションが作成されている状態です。
コネクションを分散するなどしてコネクション数を減らす対策をします。
さいごに
Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!