サーバのモニタリンクと異常通知用PHPスクリプトを作った

※記事内に商品プロモーションを含む場合があります

今まで、サーバの監視と言う事をやってませんでした。
サーバのデータを記録しておく事で、何で落ちたかが
分かりやすくなります。

また、異常が発生した時に通知が来る用にすれば
サーバが反応しない時間を少しでも短く出来ると思い
サーバモニタリンク・通知用スクリプトをPHPでつくりました。

この前はZabbixと言うソフトを使っていました。

モニタリンクと異常通知用PHPスクリプト

動作・ロギング

cronを使って10秒に1回スクリプトを実行。
通常cronは最低でも1分に1回ですが、1分に1回にして
for i in `seq 0 10 59`;do (sleep ${i};php スクリプト) & done; >/dev/null 2>/dev/null
の用にcronに設定すれば10秒に1回実行されます。

取得するデータは以下の通り

  • ロードアベレージ1分
  • ロードアベレージ5分
  • ロードアベレージ15分
  • メモリ使用率
  • スワップ使用率
  • httpdプロセス数

Apacheのhttpdプロセス数はzabbixでは取れなかったデータ。
プロセス数とメモリの状況を見る事でApacheの状況をより把握出来ます。

メモリとスワップを使用率にしたのは
バイト単位だと、最大と使用の2項目必要になりますが
使用率なら1項目で済みます。

1番は項目を減らす事での容量削減です。

このデータと時間をcsv形式にして保存します。
保存は最新のデータが上になる様にしました。

こうする事で表示用スクリプトで開く時に先頭を読むだけで
現在のステータスを確認出来ます。

ログは日付.logに保存されます。
スクリプトには明日のデータを消去する機能もあるので
簡易的なログローテーション機能となっています。

明日の日付のログを消す事で先月のログと今月のログが
混在してしまうのを防いでいます。

動作・通知

サーバのロードアベレージ1分が3を超えたらau携帯(iPhone)に
メールを送信する用に設定しました。

ロードアベレージが3以上を維持してると10秒に1回iPhoneに通知が
送信されるので、さすがにそれはやり過ぎ。

対策としてメールを送信したらロックファイルを作って
ロックファイルがある時はメール送信をしない様にしました。

そのままだと、いざという時にメールが送信されないので
ロードアベレージ1分が0.5を下回ったらロックファイルを削除します。

マルチコアでのロードアベレージ

シングルコアの場合、ロードアベレージが1以上の場合
実行待ちが発生している状態と言われます。

マルチコアの場合イロイロと説はありますが
1×コア数で良いと思います。

このVPSは3コアなのでロードアベレージ1分が3になったら
通知する様に設定しました。

多少低い気はしますが、
3ぐらいであればサーバがまだ反応するのですぐ気付いた場合は
すぐ対処出来るのでまぁ良いかなと思っています。

メール通知に分厚いauの壁

テスト環境は自宅サーバーなのでOP25Bが効いて
メール送信は出来ません。

メール送信はVPSで試しましたが一向にメールが届きません。

試しにG-Mailにしたら一発で届きました。

返送先のメールアドレスを指定してもダメ。
spfレコードを設定してもダメ。

2~3時間ぐらい悩みましたが
結局は、自分のiPhoneでauの迷惑メールフィルターに
アクセスしホワイトリストに送信元のメールアドレスを設定しました。

設定後試したら、すぐに届きました。

au・iPhoneに届いたサーバ異常通知

コード

<?php
/*
サーバモニタリンク&ロギンクスクリプトby @eaxjp
eax’s monitering bot
システムステータスのロギングとロードアベレージが3以上になった場合通知するスクリプトです。
(C)eax Version .1.5- 20150816 https://b.eax.jp/
*/

//日時取得
$now = getdate();

//HTTPプロセス数取得
$http_p = exec(‘ps aux|grep httpd|wc -l’);
$http_p = $http_p – 1;

//ロードアベレージ取得
$la = sys_getloadavg();
$la1 = $la[0];
$la5 = $la[1];
$la15 = $la[2];

//メモリ使用率
$memory_result = explode(“\n”, `free -m`);
$memory_pattern = “#^-/\+ buffers/cache: +([0-9]+) +([0-9]+)$#”;
preg_match($memory_pattern, $memory_result[2], $memory_info);
$mem_r = round(( $memory_info[1] / intval($memory_info[1] + $memory_info[2]) ) * 100,1);

//スワップ使用率
$memory_result = explode(“\n”, `free -m`);
$memory_pattern = “#^Swap: +([0-9]+) +([0-9]+) +([0-9]+)$#”;
preg_match($memory_pattern, $memory_result[3], $memory_info);
$swap_r = round(( $memory_info[2] / $memory_info[1] ) * 100,1);

//通知 ロードアベレージ
//ロードアベレージ1分が3を超えたらメール送信、ロックファイル作成
//0.5以下になればロックファイルを削除。これにより連続でメール送信されるのを防ぐ
if($la1 >= 3 and file_exists(dirname(__FILE__).”/mail_send.lock”) == false){
mb_language(“Japanese”);
mb_internal_encoding(“UTF-8”);

$body = <<< EOD
ロードアベレージ(1分)が3以上に上昇しています。

* * 現在の状況 * *
現在の時刻:{$now[‘hours’]}時{$now[‘minutes’]}分{$now[‘seconds’]}秒
Apacheのプロセス数:{$http_p}
ロードアベレージ 1min:{$la1}
ロードアベレージ 5min:{$la5}
ロードアベレージ 15min:{$la15}
メモリ使用率:{$mem_r}
スワップ使用率:{$swap_r}
EOD;

mb_send_mail(“送り先”, “サーバ異常通知”, $body ,”From: 送り元”, “-f 送り元”);
$fp = fopen(dirname(__FILE__).”/mail_send.lock”, “w”);
fwrite($fp, ‘1’);
fclose($fp);
}

if($la1< 0.5){
if (file_exists(dirname(__FILE__).”/mail_send.lock”)) {
unlink(dirname(__FILE__).”/mail_send.lock”);
}
}

//ログ保存 CSV形式にて保存、日付.logで/log/に格納される
$sd = array($now[‘hours’], $now[‘minutes’],$now[‘seconds’],$la1,$la5,$la15,$http_p,$mem_r,$swap_r);
//時間・分・秒・LA1・LA5・LA15・httpdプロセス数・メモリ使用率・スワップ使用率

//ログデータの作成 out=$csv_line
$fp = fopen(‘php://memory’, ‘r+’);
fputcsv($fp, $sd);
rewind($fp);
$csv_line = stream_get_contents($fp);
fclose($fp);

$fn = dirname(__FILE__).”/log/”.$now[‘mday’].”.log”;
//ファイルが存在しない場合はエラーを防ぐ為、空ファイルを作る
if (file_exists($fn) == false) {
$fp = fopen($fn, “w+”);
fclose($fp);
}

//ログファイルを読み込んで、最新データが先頭になる様に保存
$content=file_get_contents($fn);
$content= $csv_line.$content;
file_put_contents($fn,$content);

//明日のログ削除 先月と今月のログが混在するのを防ぐ
$asu = date(“j”, strtotime(“+1 day”));
$fn = dirname(__FILE__).”/log/”.$asu.”.log”;
if (file_exists($fn)) {
unlink($fn);
}

あとがき

コードのご利用は自己責任でお願いします。

ロギングしたデータを表示するスクリプトも作ったので
こちらは別記事で書きます。