2

私は monit でユニコーン ワーカーを監視しようとしているので、特定のメモリしきい値に達すると、ユニコーン ワーカーを適切に強制終了します。

問題:

ワーカーを再起動するように monit に指示すると、まず/etc/init.d/unicorn kill_worker 0スクリプト コマンドを実行してワーカーを停止しようとします。

# my /etc/monit/config.d/unicorn file
check process orly_unicorn_worker_0 with pidfile /tmp/unicorn.orly.0.pid
  start program = "/bin/true"
  stop program = "/etc/init.d/unicorn_orly kill_worker 0"

コマンドを介してプロセスを監視しているtopと、ワーカーがどのように強制終了され、マスターが別の pid を使用して新しいワーカーを生成するかがわかります。

ただし、Monit はしばらく待機し、ログに「停止に失敗しました」というエラーをスローします。実際には 30 秒待機してタイムアウトしています。

タイムアウトになると、monit は を認識しrestart action is done、ワーカー PID が変更されたことに気づき、期待どおりにプロセスを監視し続けます。

その結果、すべてが機能し、monit は必要に応じてワーカーを再起動し、監視を続けることができますが、ログにはエラーがいっぱいで、Web インターフェイスexecution failedにはワーカーに関する厄介な (そして紛らわしい) エラー ステータスが表示されます。設定されている場合、誤った電子メール アラートを送信します。

これは、Web インターフェイスを介してワーカーを再起動しようとしたときのログの関連部分です (ワーカーの親 PID と混同されることに注意してください)。

[UTC Mar  5 13:29:17] info     : 'orly_unicorn_worker_0' trying to restart
[UTC Mar  5 13:29:17] info     : 'orly_unicorn_worker_0' stop: /etc/init.d/unicorn_orly
[UTC Mar  5 13:29:47] error    : 'orly_unicorn_worker_0' failed to stop
[UTC Mar  5 13:29:47] info     : 'orly_unicorn_worker_0' restart action done
[UTC Mar  5 13:29:47] error    : 'orly_unicorn_worker_0' process PID changed to 13699
[UTC Mar  5 13:29:49] error    : 'orly_unicorn_worker_0' process PPID changed to 0
[UTC Mar  5 13:30:19] info     : 'orly_unicorn_worker_0' process PID has not changed since last cycle
[UTC Mar  5 13:30:19] error    : 'orly_unicorn_worker_0' process PPID changed to 13660
[UTC Mar  5 13:30:49] info     : 'orly_unicorn_worker_0' process PPID has not changed since last cycle

これを理解するのに長い時間がかかりましたが、ここで起こっていることは、ワーカーが殺され、その後すぐにリスポーンされるため、monit が変更に気付かないことです。

私の推測では、停止アクションを実行するときに、monit が を読み取って/tmp/unicorn.orly.0.pidプロセスの pid を取得し、そのプロセスが存在するかどうかを確認します。

ただし、ワーカーの kill-respawn 操作は非常に高速に行われるため、monit はワーカーの pid が変更されたことを認識せず、(新しい) ワーカーが終了するのを待ち続けます。その後、タイムアウトになり、pidが実際に変更されたことに気づき、通常どおりになります。

私が見つけた汚い解決策:

この仮説を証明するために、前述のkill-respawn ワーカー操作を遅くしようとしました。そこで、ユニコーンの設定ファイルを編集して、新しい pid を書き留める直前に、新しいワーカーを数秒間スリープさせました/tmp/unicorn.orly.0.pid

私はこのようにしました:

after_fork do |server, worker|
  sleep 3

  # write down the new worker PID so monit can monitor it
  child_pid = server.config[:pid].sub(".pid", ".#{worker.nr}.pid")
  system("echo #{Process.pid} > #{child_pid}")
end

そして、見事に機能しました。晴れた日には鳥や花が歌い、Web インターフェースは良好なprocess runningステータスを表示し、ログはすべてが順調に進んでいることを示しています。

[UTC Mar  5 13:30:44] info     : 'orly_unicorn_worker_0' trying to restart
[UTC Mar  5 13:30:44] info     : 'orly_unicorn_worker_0' stop: /etc/init.d/unicorn_orly
[UTC Mar  5 13:30:45] info     : 'orly_unicorn_worker_0' stopped
[UTC Mar  5 13:30:45] info     : 'orly_unicorn_worker_0' start: /bin/true
[UTC Mar  5 13:30:46] info     : 'orly_unicorn_worker_0' restart action done

質問:

これを達成する方法はありますか?ワーカーを 3 秒間スリープ状態にすることは、良い解決策とは思えません。何か案は?

これはmonitの通常の状況ではないことを理解しています。monit にアクションを実行させたくないので、monitの再起動プロセス サイクルを壊しましたstart programが、代わりにユニコーン マスター プロセスに処理させます (ここで説明されているように: http://www.stopdropandrew.com/ 2010/06/01/where-unicorns-go-to-die-watching-unicorn-workers-with-monit.html )

4

1 に答える 1

0

この環境では、monit がユニコーン マスターを監視し、ユニコーン マスターがその子を監視します。シンプルな cron を使用してユニコーン ワーカーを監視し、メモリのしきい値を超えた場合はそれらを強制終了します。

    #!/usr/bin/env ruby
    #       

    def get_mem(pid)
      pid = pid.to_i
      mem = 0 
      if File.exist?("/proc/#{pid}/status")
        File.read("/proc/#{pid}/status").each_line do |status|
          next unless status =~ /^VmRSS:\s+(\d+) kb/i
          mem = $1.to_i / 1024
        end     
      end     
      mem     
    end     

    %x{pgrep -f 'unicorn worker'}.each_line do |pid|
      Process.kill('QUIT', pid.to_i) if (get_mem pid) >= 300
    end

ユニコーン マスターは、子供が殺されたことに気づき、自動的に新しい子供を復活させます。ユニコーンワーカーは、現在のリクエストが完了した後にシャットダウンする QUIT シグナルを尊重していると確信しています。

于 2013-03-07T00:26:24.073 に答える