Hatena::ブログ(Diary)

サラリーマンから起業するリアル このページをアンテナに追加 RSSフィード


cakePHPに関する記事はこれから下記のブログに書いていきます。
http://d.hatena.ne.jp/cakephper



2009-01-23

[][]一定期間CPU負荷が高かった場合の、負荷が高いプロセスを記録する

サーバ運用していて、たまにMRTGの結果からCPU負荷が高くなる時間や日があったりします。

最近では、SSHの総当たり辞書攻撃を中国などから受けてて高くなってました。/var/log/secureファイルのサイズが大きくなってて、中を見たらsshの認証が失敗しているログが大量にたまってた。うちのSSHサーバは証書認証なので別に問題ないけど、負荷が上がって嫌な感じだったので、firewallでフィルタしました。

今回のようにログファイルなどで、負荷が高くなっている原因が分かればいいのですが、分からない場合は負荷が高いプロセスを記録しておいて、後からそれが分かるようにしておきたいと思い、簡単なスクリプトを書きました。linux CentOS4.4で動かしてます。いくつかのコマンドを利用しているのでlinuxしか動かない可能性が高いです。

今回は、SNMPとか入ってない環境でも動くように、負荷が高いというのをvmstatコマンドでCPUアイドルの数値をチェックし、負荷が高い状態が何回か続いた場合のみ、cpu, memoryの利用率が高い順にプロセスをソートして、上位n件をファイルに記録します。ついでにvmstatの結果も記録します。

vmstatは1秒間隔に3回実行し、3回目の実行結果の値を見ています(vmstatを1回のみ実行するだけだとうまくcpu負荷が取れなかったので)。


利用方法は、下記のスクリプトをサーバに置いて、実行権限を与えて実行するだけです。rootじゃなくてもかまいません。cronで5分間隔ぐらいで実行すれば良いと思います。

実行すると、そのディレクトリにvmstatのログと、負荷が高い状態のカウントファイルと、ログを出力するdataディレクトリを作成します。

下記のスクリプトのconfigの箇所を変えて好きな条件に設定可能です。ログファイルは、ログファイル出力毎にファイルが分かれており、ファイル名に日時分秒が入ります。


では、実際のスクリプトです。

#!/bin/sh

#This file Directory(この実行ファイルのパスを取得)
PROG_PATH=`dirname $0`



#----------------- config ---------------------------

#CPU Idole % Limit(CPUアイドルの%がこの値を下回ったら記録対象とする)
CPU_IDOLE_LIMIT=61

#Counter Limit(CPU負荷が高い状態が連続n回続いたらログを記録)
COUNTER_LIMIT=5

#number of process which is recorded(記録する負荷が高いプロセスの数)
CPU_PROC_NUM=7

#Counter file(カウントファイルの名前)
COUNTER_FILE=$PROG_PATH/count.txt

#Log directory path(ログデータ出力ディレクトリ)
LOG_DIR=$PROG_PATH/data

#vmstat temp log(vmstatの結果記録テンポラリファイル)
VMSTAT_LOG=$PROG_PATH/vmstat.log

#----------------- end config -----------------------

#vmstatを1秒間隔に3回実行し、それをファイルに記録
vmstat 1 3 > $VMSTAT_LOG


#vmstatの結果ファイルから、最後の行を抽出して、そこからcpuアイドルの値を抽出
Idole=`tail -1 $VMSTAT_LOG | gawk '{print $15;}'`


#記録するプロセスの数を1つ増やす(ヘッダ行が入るため)
CPU_PROC_NUM=`expr $CPU_PROC_NUM + 1`

#カウンタファイルがなければ作成する
if [ ! -e $COUNTER_FILE ] ; then
	
	echo "1" > $COUNTER_FILE
fi


#現在のカウントを取得(負荷が高い状態が続いた数)
COUNTER=`cat $COUNTER_FILE`


#CPUアイドルの値が規定値を下回れば記録対象とする
if [ $Idole -lt $CPU_IDOLE_LIMIT ] ; then

    #CPU負荷が高い状態が規定値回数以上続いたらログに記録する
	if [ $COUNTER -gt $COUNTER_LIMIT ] ; then

                #ログ出力ディレクトリがなければ作成
		if [ ! -d $LOG_DIR ] ; then
			mkdir $LOG_DIR
		fi

                #ログファイル名を作成 cpu_20081224123456.logというような名前
		LOG_FILE=$LOG_DIR/cpu_`date +%Y%m%d%H%M%S`.log

		#ログファイル出力 psコマンドの結果から、cpu負荷、メモリ使用率が高い順にソートし、上位n件をログに記録
		ps aux | sort -r -b +2 | head -$CPU_PROC_NUM > $LOG_FILE 

                #改行を2個入れて、ついでにvmstatの結果もログに記録
		echo "" >> $LOG_FILE 
		echo "" >> $LOG_FILE 
		cat $VMSTAT_LOG >> $LOG_FILE 
		
		
	
		#カウンタの値を初期化
		echo "1" > $COUNTER_FILE
		
	else
	
         	#カウンタの値を1つ上げる
		COUNTER=`expr $COUNTER + 1`
		echo $COUNTER > $COUNTER_FILE
	
	fi

fi

負荷が高かった日時が分かれば、それからログファイルのファイル名を見て該当ログファイルを見つけて、負荷が高いプロセスが発見できるかと思います。

ログファイルが出力されていれば、メールを送信するシェルと組み合わせれば、アラートメールみたいになりますね。


上記のプログラムは解説のために日本語コメントをいれていますが、それが原因で動かないこともあるので、日本語を含めていないプログラムを下記に記載します(うちではこっちを実行して動かしてます)。

#!/bin/sh

#This file Directory
PROG_PATH=`dirname $0`



#----------------- config ---------------------------

#CPU Idole % Limit
CPU_IDOLE_LIMIT=61

#Counter Limit
COUNTER_LIMIT=5

#number of process which is recorded
CPU_PROC_NUM=7

#Counter file
COUNTER_FILE=$PROG_PATH/count.txt

#Log directory path
LOG_DIR=$PROG_PATH/data

#vmstat temp log
VMSTAT_LOG=$PROG_PATH/vmstat.log

#----------------- end config -----------------------


vmstat 1 3 > $VMSTAT_LOG


#get CPU Idole %
Idole=`tail -1 $VMSTAT_LOG | gawk '{print $15;}'`



CPU_PROC_NUM=`expr $CPU_PROC_NUM + 1`


if [ ! -e $COUNTER_FILE ] ; then
	
	echo "1" > $COUNTER_FILE
fi


COUNTER=`cat $COUNTER_FILE`



if [ $Idole -lt $CPU_IDOLE_LIMIT ] ; then

	if [ $COUNTER -gt $COUNTER_LIMIT ] ; then

		if [ ! -d $LOG_DIR ] ; then
			mkdir $LOG_DIR
		fi

		LOG_FILE=$LOG_DIR/cpu_`date +%Y%m%d%H%M%S`.log

		#output Process info to log text.
		ps aux | sort -r -b +2 | head -$CPU_PROC_NUM > $LOG_FILE 
		echo "" >> $LOG_FILE 
		echo "" >> $LOG_FILE 
		cat $VMSTAT_LOG >> $LOG_FILE 
		
		
	
		#clear counter	
		echo "1" > $COUNTER_FILE
	else
		COUNTER=`expr $COUNTER + 1`
		echo $COUNTER > $COUNTER_FILE
	fi

fi

NOIKENOIKE 2009/02/07 23:46 はじめまして.
PROG_PATH のところを自分好みに書き換えて,ありがたく使わせていただいています.
こちらの環境は CentOS 5.x ですが,UTF8 エンコード,LF 改行で保存して,「日本語コメントつき版」が無事に動きました.
いま,cron.hourly にほおりこんで,1時間に 1 回くらいのペースで動かしています.

実用的なスクリプトの公開をありがとうございました.

ichikawayichikaway 2009/02/08 08:28 >NOIKEさん

コメントありがとうございます。
利用してもらえて嬉しいです。
使っていて変な箇所があればまたご連絡下さい。

今後とも宜しくお願いします。

NOIKENOIKE 2009/02/08 16:24 ちょうどいま,負荷が高くなってログファイルが生成されたところなのですが,ps aux の結果が記録されていませんでした.
よくわからないのですが,sort コマンドの +2 という引数が私のところでは使えないようで,
sort: open failed: +2: No such file or directory
となってしまうので,ひとまず +2 を削ったところ,ps aux の結果も記録されるようになりました.

対処方法として正しいのかどうかわかりませんが,一応,ご報告いたします.

ichikawayichikaway 2009/02/11 00:39 >NOKIEさん

ご連絡ありがとうございます。
sortコマンドのオプションで+2は何個目のフィールドでソートするかという指定なのですが、これは最近では-kオプションに置き換えられてるので、
sort -r -b -k 2としたら動くかもしれません。

sort -r -b -k 2の意味は、0から数えて2つめのフィールド以降の順で降順ソートで表示という意味です。つまり+2もしくは-k 2がないとCPU負荷が高い順でソートされない可能性があります。

NOIKENOIKE 2009/02/12 00:22 > つまり+2もしくは-k 2がないとCPU負荷が高い順でソートされない可能性があります。

なるほど... 確かに思ったようにログが取れていませんでした(^^;).ありがとうございます.
やっぱりよく理解できていないままの付け焼刃の対処ではだめですね... .

-k 2 でも思ったようにソートされたログが取れなかったので,今度は,man sort をじっくり読んで設定しました.
私のところでは,k の値は 1 から始まるようです.
-k 3 としたところ,CPU負荷の値でソートされました!
いまは,念のために -n (numeric sort)もつけてあります.

ありがとうございました!

ichikawayichikaway 2009/02/12 22:20 >NOIKEさん

お返事ありがとうございます。
-kは1からカウントでしたか。
確かに-nオプションはあったほうが良いかもしれないですね。
色々と勉強になりました。ありがとうございました!

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/ichikaway/20090123/1232708883