【oom-killer】メモリが原因でサーバが落ちた時にやった対応

カーネルパニック

サーバの監視アラートが発報されサーバが落ちていることが発覚し調査した。SSHでの接続は不可能だったので、さくらVPSのコントロールパネルから状態を確認。画面には「kernel panic」の文字。操作できなかったのでコンパネ上から再起動しサーバは復帰した。

原因究明

messagesログを確認すると「httpd invoked oom-killer: ~」というログを発見。どうやらメモリが枯渇しサーバが落ちた模様。以下が障害の流れ。

メモリ枯渇→oom-killer→カーネルパニック

oom-killerとは

物理メモリ、スワップメモリが枯渇したとき、システム全体に最も影響の与えてるプロセス(メモリを一番使っている)を選択しkillするプログラムのこと。init プロセスやカーネルスレッドなどは OOM Killer 発動対象外。

スワップメモリ追加

メモリは物理が4G、スワップが2G。スワップメモリがかなり少なかったので応急処置としてスワップメモリを6Gに増やした。

# dd if=/dev/zero of=作成ファイル bs=ブロックサイズ count=ブロック数
dd if=/dev/zero of=/var/swpfile4G bs=1M count=4096

ddコマンドで4Gの空ファイルを作成する。

mkswap /var/swpfile4G

mkswapでフォーマットしスワップとして使用できるようにする。

chmod 600 /var/swpfile4G

このままでは権限のエラーがでるのでパーミッション変更。

swapon /var/swpfile4G

スワップ領域を割り当てる

free

freeコマンドで確認。

vi /etc/fstab
#最終行に以下を追加
/var/swpfile4G          swap                    swap    defaults        0 0

OS再起動時に追加したSwap領域がマウントするようにfstabファイルを編集。

プロセスチェック

以下のコマンドを利用してメモリを使っているプロセスを割り出した。調査すると落ちたサーバがWEBサーバとして利用していることもあり「httpd」が一番怪しかった。Apacheの設定を確認すると「MaxClients」の値が256あり、1プロセス当たりのメモリ使用量が50Mの場合、12Gのメモリを使用することになり完全に枯渇することがわかった。

#ランキング
ps -eo comm,rss | sort -rn -k 2 | head -n 50

#指定プロセスの物理メモリ(RSS)合計
ps -eo rss,comm | awk 'BEGIN {SUM=0} {if ($2 == "[プロセス名]"){ SUM+=$1 }} END {printf("%dMB\n", SUM/1024)}'

#指定プロセス数
ps -eo rss,comm | awk 'BEGIN {COUNT=0} {if ($2 == "[プロセス名]"){ COUNT+=1 }} END {print COUNT}'

#指定プロセスの物理メモリ(RSS)平均
ps -eo rss,comm | awk 'BEGIN {SUM=0;COUNT=0} {if ($2 == "[プロセス名]d"){ SUM+=$1;COUNT+=1 }} END {printf("%dKB\n", SUM/COUNT)}'

#指定プロセスの物理メモリ(RSS)最大
ps -eo rss,comm | awk 'BEGIN {MAX=0} {if ($2 == "[プロセス名]"){ if (MAX < $1) { MAX=$1 }}} END {print MAX}'

#指定プロセスのCPU使用率
ps -eo %cpu,comm | awk 'BEGIN {SUM=0} {if ($2 == "[プロセス名]"){ SUM+=$1 }} END {print SUM}'

ちなみに主要プロセスのメモリ使用量は以下になった。
Postfixメモリ使用量:約33MB
PHPメモリ使用量 :0MB
MySQLメモリ使用量 :75.51 MB
httpdメモリ使用量 :443.44 MB
clamメモリ使用量 :806.4 MB

clamがメモリの使用量が大きかったので一旦停止した。

Apacheのチューニング

プロセスチェックの結果からApacheの設定に問題があることがわかりチューニングした。
以下チューニングに関係するディレクティブ。

・StartServers
Apache起動時の子プロセス数

・MinSpareServers
待機時の最小子プロセス数

・StartServers
Apache起動時の子プロセス数

・MinSpareServers
待機時の最小子プロセス数

・MaxSpareServers
待機時の最大子プロセス数

・ServerLimit
設定可能なサーバプロセス数の上限

・MaxClients
最大の小プロセス数

・MaxRequestsPerChild
1子プロセスが処理するリクエスト数(上限を超えると新しいプロセスに入れ替わる)

実際設定したのは以下の設定。

サーバが落ちた時の設定内容(デフォルト値)
<IfModule prefork.c>
StartServers         8
MinSpareServers         5
MaxSpareServers     20
ServerLimit     256
MaxClients     256
MaxRequestsPerChild  4000
</IfModule>

<IfModule prefork.c>
StartServers         25
MinSpareServers         25
MaxSpareServers     40
ServerLimit     105
MaxClients     100
MaxRequestsPerChild  1000
MaxMemFree           2048
</IfModule>

「MaxSpareServers」はメモリが枯渇しないように設定。「MaxClients」は始め50ぐらいに設定していたが、すぐに上限に到達したので(apacheのエラーログでわかる)調整し100ぐらいに落ち着いた。

Zabbixでプロセスの監視

Zabbixでプロセスの監視をすることにした。今後これらの値を参考にさらなるチューニングなどに生かしていく。
テンプレートを作成しアイテムを追加する。

以下プロセスのメモリ容量を監視。

・postfixメモリ使用量
・phpメモリ使用量
・mysqldメモリ使用量
・httpdメモリ使用量
・clamメモリ使用量

あとはapacheのプロセス数、1プロセス当たりの平均メモリ使用量を監視。

プロセス名メモリ使用量

アイテム追加

名前:プロセス名メモリ使用量
タイプ:エージェント
キー:proc.mem[プロセス名,,sum,,rss]
データ型:数値(整数)
データ形式:10進数
単位:B

プロセス名はpostfix、php、mysqld、httpd、clamを入れる。

httpdの1プロセス当たりの平均メモリ使用量

アイテム追加

名前:httpdメモリ使用量平均
タイプ:エージェント
キー:proc.mem[httpd,,avg,,rss]
データ型:数値(整数)
データ形式:10進数
単位:B

httpdプロセス数

アイテム追加

名前:httpdプロセス数
タイプ:エージェント
キー:proc.num[httpd,,,]
データ型:数値(整数)
データ形式:10進数

Zabbixでログ監視

ログを監視し問題のあるものはアラートを飛ばす設定にした。
テンプレートを作成しアイテム追加、トリガーを追加する。

messages監視

以下の設定でmessagesログを監視し「oom-killer」が出たらアラートを飛ばすようにする。

アイテム追加

名前:messagesログ監視
タイプ:アクティブ
キー:log[/var/log/messages,,,,,]
データ型:ログ

トリガー

名前:OOM killer が発動されました。
条件式:
{Template linux logs:log[/var/log/messages,,,,,].regexp(oom-killer)}=1 and 
{Template linux logs:log[/var/log/messages,,,,,].nodata(10m)}=0

apacheのエラーログ

以下の設定でapacheのエラーログを監視し「MaxClients」が出たらアラートを飛ばすようにする。
このアラートは、apacheのプロセス数が「MaxClients」の値に到達したことを意味し再チューニングの参考にできる。

・アイテム

名前:apache error_log
タイプ:アクティブ
キー:log[/var/log/httpd/error_log,,,,,]
データ型:ログ

トリガー

名前:apacheのプロセスが上限に達しました。
条件式:
{Template linux logs:log[/var/log/httpd/error_log,,,,,].regexp(MaxClients)}=1 and 
{Template linux logs:log[/var/log/httpd/error_log,,,,,].nodata(10m)}=0
説明:
apacheのプロセスが上限に達しました。

今後

・MySQLなどの設定もデフォルト値のままなので見直す必要がある。
・サイト数が40サイトぐらいあるサーバなのでapacheのログを集計しどのサイトがアクセス数が多いかを把握し対応(サーバ移行など)する必要がある。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする