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,然后注意到 worker 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 worker 操作发生得如此之快,monit 并没有意识到 worker 的 pid 已经改变并一直在等待(全新的)worker 死亡。然后它超时,然后它意识到pid实际上已经改变并且它正常运行。

我发现的肮脏解决方案:

为了证明这个假设,我试图减慢提到的kill-respawn worker 操作。所以我编辑了 unicorn 配置文件,让新工作人员在/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

而且效果非常好:晴天鸟语花香,网络界面现在显示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的重启过程循环,因为我们不希望start programmonit执行任何操作,而是让独角兽主进程处理它(如这里解释:http: //www.stopdropandrew.com/ 2010/06/01/where-unicorns-go-to-die-watching-unicorn-workers-with-monit.html )

4

1 回答 1

0

在我们的环境中,monit 监控 unicorn master,unicorn master 监控它的孩子。我们使用一个简单的 cron 来监控 unicorn worker,如果超过内存阈值就将其杀死:

    #!/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 回答