Godで初めてのプロセス監視

Ruby 製のプロセス監視ツール、God を試してみた。(書いてる時点より5ヶ月前…。)

モダンに監視したい

なぜなら TIG が落ちるから(笑)

実は Un*x 系の OS なら素朴な監視は割と簡単にできる。

  • ps
  • grep
  • /etc/rc.d/* とか /etc/init.d/* とか
  • sendmail

辺りで事足りる。要するに

定期的に ps を叩いて、この文字列のパターンがない場合はこのプロセスが落ちてるから mail 投げて起動スクリプトを呼ぼう

ってだけ1。これだけでプロセスが落ちてたらまた起動し直すということが可能なので、知らん間にサーバ落ちててオレ涙目っていう状態を減らすことはできる。少なくともすでに上の道具が使えているなら新しいことを覚える手間はないので、どうしてもすぐ監視を始めたい場合にはこれだけでも十分有効だと思う。

でも効率が良くない。ちょっと複雑なことを考え始めると fork の嵐になって2地球に優しくないし、cron で回すのもタイミングによっては大きな負荷になる。(朝方とか。)

それに sh スクリプトは処理の部品化も一苦労。できれば凝ったものはあまり書きたくない。

なんで daemontools や runit, monit じゃないの?

  • どれも知らない
  • どれも独自の文法で設定を書かなきゃいけない
  • djbware はメンドウというもっぱらの噂

だったらどれ使っても一緒。でも

ツールに入っていない機能(通知方法とか)を使いたいと思うときがきっときて、そのときの拡張しやすさは Ruby 製の God の方が上だと思う

というか

Ruby が好き

だから。使ってみての比較ではないのでそういう意味では参考にならない。

参考

なぜ daemontools を使うのか - kazuhoのメモ置き場

こんな意見もある。これと比べると

  • ログのローテート機能はない

んだけど、それは logrotate や rotatelogs を使えばいいんじゃないかという気がしている。特に困ったことがないのはヌルい使い方しかしてないからかもしれないので鵜呑みにはしないでね。

Ruby でやって、重くないの?

kqueue や netlink_handler を使っているので監視部分のコストは高くないっぽい。Ruby 本体とスクリプト分メモリを食うのはしょうがない。

Windows には対応していないので悪しからず。

サイト

インストール

拡張ライブラリがあるので ruby-devel や ruby-dev とかのパッケージも入れておこう3

$ sudo gem install god

で ok.

使ってみる

god の gem にも example はあるんだけど、もうちょっと試しやすいように

を git clone するか Download Source のリンクから丸ごと取得する。

どれでもいいんだけど、leaky.god を試してみる。leaky.god の中身はこんな感じになっている。

God.watch do |w|
  w.name            = "leaky"
  w.interval        = 5.second
  w.start           = 'ruby ' + File.dirname(__FILE__) + '/scripts/leaky.rb'

  w.start_if do |start|
    start.condition(:process_running) do |c|
      c.running = false
    end
  end

  w.restart_if do |restart|
    restart.condition(:memory_usage) do |c|
      c.above = 2.megabytes
    end
  end

end

細かい説明はしないけど、

  • leaky.rb が起動していなかったら起動する
  • 消費メモリが2MBに達したら再起動する

という動作をする。

god -c leaky.god

と打って god を起動し、Activity Monitor や後述の topless, watch などを使って Ruby プロセスの様子を確認してみると、God 自身が使っているプロセスと、どんどんメモリが増えていって 2MB に達したら再起動するプロセスを確認することができる。

試しに再起動をくり返しているプロセスを手動で強制終了してもやはり帰ってくる。

設定を変える

手動で強制終了と言っても2MBにはあっという間に達してしまうので、あっという間に再起動が掛かって強制終了できない、と思うかもしれない。そこで God が監視する interval を延ばしてみよう。先ほどの leaky.god の

  w.interval        = 5.second

ここを書き換える。15.second くらいあれば十分だろう。書き換えたら leaky.god を保存して

god load leaky.god

すると今の変更が反映される。これで手動で強制終了しやすくなった。

当然監視の間隔が延びたので、設定容量である 2MB を越えてしまったり、強制終了後の再起動までに掛かる時間も延びてしまうが、そこは仕方がない。あくまで実験なので。

終了する

さてこれで leaky.rb は普通の方法では終了することができなくなった。じゃあどうやって終了するのかというと、

god stop leaky

と打つ。この leaky は watch のところで定義してある name を反映している。god ファイルの名前じゃないので注意。God そのものを終了したければ

god quit

ただし監視しているプロセスのことは気にせず終了してしまうので、

god terminate

を使うようにしておいた方がいいと思う。詳しくは

god --help

と打てば確認できる。

Growl への通知を追加してみる

God は標準でも mail だけでなく twitter や各種 webhook への通知が可能になっているが、試しに Growl への通知を追加してみた。動いたときの Twitter への POST がこれ。

Twitter / wtnabe: できたできた。http://bit.ly/bD38Z …

まずは

gem install ruby-growl

RubyForge: ruby-growl: Project Info

をインストール。そして

god_extension/
|-- god_growl.rb   <-- 追加
god_examples/
|-- README.textile
|-- leaky.god
|-- lib/
|-- pids/
|-- rails/
|-- scripts/
|   |-- crashy.rb
|   |-- leaky.rb
|   `-- stable.rb
|-- simple.god
`-- sinatra.god

ディレクトリの構造はこんな感じで、god_gworl.rb というファイルを以下の内容で作る。

simple.god を以下のように Growl を利用するように書き換えて、

Growl がネットワーク越しに通知を受け取れるようにして

god -c simple.god

で実行。

ここから実行される crashy.rb は次々 crash するんだけど、それが God に捕捉されるたびに Growl に通知が来る。なかなか面白い。

その他、気づいたこと

基本的に God 1プロセスで複数のプロセスを監視することになる。その場合、当然監視対象ごとに設定ファイルを分けた方が読みやすいので

God.load /path/to/GOD_CONFIG

で設定ファイルを読み込む処理を書いた設定ファイルを

god -c

で指定して立ち上げることになる。

もし監視する God そのものを増やす場合は God と通信するためのポートもその分必要になる。

監視対象プロセスの起動順に関する疑問

例えば TIG のあとに tiarra、といった具合に起動する順番が大切になっているものを希望通りに立ち上げるにはどうしたらいいんだろう。

  1. 順番に load を書いていく
  2. よくある感じで設定ファイルの名前を数字始まりにしてまとめて読む

やっぱ 2 なのかな。

  1. OP25B とかは考えてない 

  2. sh スクリプトだからしょうがない。 

  3. OSXで標準のRubyを使ってる人はどうなるのかは知らない 

More

Categories

Tool 日々 Web Biz Net Apple MS ことば News Unix howto Food PHP Movie Edu Community Book Security Text TV Perl Ruby Music Pdoc 生き方 RDoc ViewCVS CVS Rsync Disk Mail FreeBSD Cygwin PDF Photo Zebedee Debian OSX Comic Cron Sysadmin Font Analog iCal Sunbird DNS Linux Wiki Emacs Thunderbird Sitecopy Terminal Drawing tDiary AppleScript Life Money Omni PukiWiki Xen XREA Zsh Screen CASL Firefox Fink zsh haXe Ecmascript PATH_INFO SQLite PEAR Lighttpd FastCGI Subversion au prototype.js jsUnit Apache Trac Template Java Rhino Mochikit Feed Bloglines CSS del.icio.us SBS qwikWeb gettext Ajax JSDoc Rails HTML CHM EPWING NDTP EB IE CLI ck ThinkPad Toy WSH RFC readline rlwrap ImageMagick epeg Frenzy sysprep Ubuntu MeCab DTP ERD DBMS eclipse Eclipse Awk RD Diigo XAMPP RubyGems PHPDoc iCab DOM YAML Camino Geekmonkey w3m Scheme Gauche Lisp JSAN Google VMware DSL SLAX Safari Markdown Textile IRC Jabber Fastladder MacPorts LLSpirit CPAN Mozilla Twitter OpenFL Rswatch ITS NTP GUI Pragger Yapra XML Mobile Git Study JSON VirtualBox Samba Pear Growl Mercurial Rack Capistrano Rake Win RSS Mechanize Sitemaps Android JavaScript Python RTM OOo iPod Yahoo Unicode Github iTunes God SBM friendfeed Friendfeed HokuUn Sinatra TDD Test Project Evernote iPad Geohash Location Map Search Simplenote Image WebKit RSpec Phone CSV WiMAX USB Chrome RubyKaigi RubyKaigi2011 Space CoffeeScript Nokogiri Hpricot Rubygems jQuery Node GTD CI UX Design VCS Kanazawa.rb Kindle Amazon Agile Vagrant Chef Windows Composer Dotenv PaaS Itamae SaaS Docker Swagger Grape WebAPI Microservices OmniAuth HTTP 分析基盤 CDN Terraform IaaS HCL Webpack Vue.js BigQuery Middleman CMS AWS PNG Laravel Selenium OAuth OpenAPI GitHub UML GCP TypeScript SQL Hanami Develop Document Jekyll