理想未来ってなんやねん

娘可愛い。お父さん頑張る。

サーバーに負荷を与えないよう、コマンドをゆっくり実行する方法

サーバーを管理しているとメインで行っている処理の邪魔にならないようにコマンドをゆっくり実行させたいことがあります。


そのような場合、niceおよびioniceを使用することでプライオリティを低くした状態でコマンドを実行することができます。
しかし、それでも優先度が下がるだけでサーバー全体としての負荷は下がることはありません。


プライオリティを下げて実行しても重い時がありますし、又、ロードアベレージが一定以上となった時にアラートを飛ばすようにしているとアラートが飛んできてしまうことがあるので、さらに負荷を下げて実行したい時があります。


具体的に負荷を下げるアイデアとして、プロセスを一時停止する方法があります。


プロセスはSIGSTOPシグナルを送ることで一時的に停止することができます。
また、一時停止したプロセスはSIGCONTシグナルを送ることで再び実行することができます。


プロセスが終了するまで間にSLEEPを入れながらSIGSTOPシグナルとSIGCONTシグナルを交互に送ることで実行時間を調整することができますが、注意しなければならないのはプロセスが子プロセス、さらに子プロセスが孫プロセスを生成している場合で、すべての子孫プロセスに対して処理を行う必要があります。


上記を踏まえて、子孫のプロセスも含めて一時停止させるbashスクリプトを書きましたので、参考として記載いたします。

#!/bin/bash

# 子孫のPIDを再帰的に調べる関数
function get_descendant_pid()
{
	local PID=${1}
	local CHILD_PID_LIST=$(pgrep -P $PID)
	local GCHILD_PID_LIST=()

	if [ -n "${CHILD_PID_LIST}" ]; then
		for CHILD_PID in ${CHILD_PID_LIST}
		do
			GCHILD_PID_LIST=(${GCHILD_PID_LIST[@]} $(get_descendant_pid $CHILD_PID))
		done
	fi
	echo ${CHILD_PID_LIST[@]} ${GCHILD_PID_LIST[@]}
}

#ゆっくり実行したいコマンド
COMMAND="tar czf /var/backup/www-$(date +'%Y%m%d').tar.gz /var/www"

#低いプライオリティ且つバックグラウンドで実行
"$(ionice -c3 nice -n 19 ${COMMAND})" &

# 直前に実行されたコマンドのpid
PID=$!

# プロセスが終了するまでSIGSTOPシグナルとSIGCONTシグナルを交互に送り
# プロセス実行時間を絞る
while kill -0 $PID >/dev/null 2>&1;
do
	# PIDを親に持つ子孫プロセスのPIDを調べる
	PIDLIST="$PID $(get_descendant_pid $PID)"
	
	# 1秒毎に一時停止、再開
	kill -s SIGSTOP $PIDLIST
	sleep 1
	kill -s SIGCONT $PIDLIST
	sleep 1
done


以上、スローライフなサーバー管理にお役立ていただけると幸いです。