DTIサーバのディスク容量監視にyadaemon.rbを使ったRubyスクリプトを走らせています。
ディスク容量を把握するのは、ちょっと面倒なので内部では手を抜いてopen("|df")
を実行しています。
しばらく走らせてみたらdefunctプロセス(いわゆるゾンビプロセス)が大量発生したので、その原因を考えてみました。
問題のあったコード
"df"プロセスが終了していなかったのは次の部分です。
module YaWatchDisks
def yield_df_perms
open("|df ").each_line do |line|
# "Filesystem" "1K-blocks" "Used" "Available" "Use%" "Mounted on"
# perms: ["/dev/md0", "484041584", "453132936", "6514352", "99%", "/"]
perms = line.split(/\s+/)
yield perms if perms.length == 6 and perms[1].to_i > 0 and perms[2].to_i > 0 and perms[3].to_i > 0
end
end
...
考えてみれば、each_lineメソッドを実行する主体はeach_lineメソッドのブロックを終了してからcloseメソッドを呼び出すなんていう責任はないわけです。
内部ではopen("|df")
の部分がGCの対象になるまで常に滞留していたはずです。
でも実際にはGCの対象にもならず、元プロセスは常駐していますから、プロセスが大量に残っていたという事になります。
問題の修正
変に省略せずに、ブロックをつけて呼び出してあげれば、何の問題もなくcloseされるようになります。
module YaWatchDisks
def yield_df_perms
open("|df ") do |f|
f.each_line do |line|
# "Filesystem" "1K-blocks" "Used" "Available" "Use%" "Mounted on"
# perms: ["/dev/md0", "484041584", "453132936", "6514352", "99%", "/"]
perms = line.split(/\s+/)
yield perms if perms.length == 6 and perms[1].to_i > 0 and perms[2].to_i > 0 and perms[3].to_i > 0
end
end
end
...
しばらくしてからmuninで確認すると、プロセス数が純増していたグラフからzombie分が消えていて解決したことが確認できました。
ruby-forum.comで見つけた理由らしきもの
Googleでドキュメントを検索していたらhttp://www.ruby-forum.com/topic/62435で、外部プログラムの結果を得るなら「バッククォートや%x{}構文を使ったら?」という記述がありました。
これを、試してみると古いコードでも確かにゾンビプロセスは発生しなくなり、問題なく動くようになりました。
0 件のコメント:
コメントを投稿