监控进程

赞助

如果你觉得我写得还行,并且愿意付费,那么我会更有动力写下去。

有时候,进程突然终止服务,可能是没有资源了,也可能是意外,比如说:因为 OOM 被杀;或者由于 BUG 导致崩溃;亦或者误操作等等,此时,我们需要重新启动进程。

实际上,Linux 本身的初始化系统能实现简单的功能,无论是老牌的 SysVinit,还是新潮的 Upstart 或者 Systemd 均可,但它们并不适合处理一些复杂的情况,比如说:CPU 占用超过多少就重启;或者同时管理 100 个 PHP 实现的 Worker 进程等等,如果你有类似的需求,那么可以考虑试试 MonitSupervisor,相信会有不一样的感受。

让我们看看 Monit 的用法,假设我们要监控 Nginx 进程,一旦其 CPU 使用率连续 5 次轮询周期里均超过 50% 的话,就重启进程,此时就可以按照如下方式设置:

check process nginx with pidfile /var/run/nginx.pid
    start program = "/etc/init.d/nginx start"
    stop program  = "/etc/init.d/nginx stop"
    if cpu is greater than 50% for 5 cycles then restart

Monit 根据 pidfile 轮询对应的进程是否健在,满足条件就执行 start/stop 等操作。如果进程本身不存在 pidfile,那么也可以使用 matching 语法来匹配进程。

再让我们看看 Supervisor 的用法,假设我们要监控 100 个 PHP 实现的 Worker 进程,用来提供 Gearman 之类的服务,由于 PHP 本身运行模式的缘故,为了避免严重的内存泄漏问题,我们设定 PHP 进程服务一定次数或一段时间后就自动退出,这时候我们需要启动新的 Worker 进程,以便总数维持不变,此时就可以按照如下方式设置:

[program:worker]
command=/usr/bin/php /path/to/worker.php
process_name=%(program_name)s_%(process_num)02d
numprocs=100
autostart=true
autorestart=true

如果说 Supervisor 有什么缺点的话,那么首当其冲的是对使用者而言它不够透明:很多进程都是后台运行的,但 Supervisor 却要求必须改成前台运行。好在多数服务都提供了对应的配置选项,如果没有的话,我们也可以使用一些变通的方法:

不管用什么来监控进程,如果监控者本身挂了,那么被监控者无疑就失控了。此时需要考虑如何监控监控者本身,这似乎是一个递归问题,不过文章开头我们说过,Linux 本身的初始化系统就能实现简单的监控功能,以 SysVinit 为例,编辑 /etc/inittab 文件:

SU:2345:respawn:/usr/bin/supervisord -c /etc/supervisord.conf

改好后运行「init q」命令让其生效,然后 kill 掉 supervisor 进程看看会不会发生奇迹。

注意:记得事先我们要配置 Supervisor 为 nodaemon=true 噢。

监控进程》上有7条评论

  1. 「一旦其 CPU 使用率连续 5 次超过 50%」,这里的超过 50% 的次数怎么理解呢?每个整秒时刻的前一秒平均值?从「cpu is greater than 50% for 5 cycles」来看,这个条件是一旦进程连续使用超过4个CPU cycle 就为真?

    systemd 也有些资源控制的,基于 cgroup,不过好像 CPU 部分不能指定重启服务。管理 PHP 进程不是 php-fpm 的职责么?有个 pm.max_requests 设置。

    • Monit 是轮询的,周期可配,缺省一分钟。具体可以参考 Monit 文档 http://mmonit.com/monit/documentation/monit.html ,里面有解释:

      The following is an example to check that the CPU usage of a service is not going beyond 50% during five poll cycles. If it does, Monit will restart the service:

      我文章中说的 PHP Worker 不是 PHP-FPM,是指用 PHP 实现的一些 Worker 进程,比如 Gearman 之类的 Worker。

  2. > 很多进程都是后台运行的,但 Supervisor 却要求必须改成前台运行

    必须前台跟 supervisor 的实现机制有关,因为 supervisor 是通过父子进程的方式监控子进程的信号的,对应的程序必须作为 supervisor 的子进程启动。

    个人认为 supervisor 的设计初衷就不是拿来监控那些通过 Linux 包管理器安装的、本身已经 daemonize 的服务。(这种情况恐怕 monit 更适合)

    supervisor 比较适合监控业务应用。12-factor app [建议](http://12factor.net/concurrency):“Twelve-factor app processes should never daemonize or write PID files”。这样的业务应用可能直接是 java -jar xxx.jar 运行的,或者 python script.py 运行,跟 supervisor 配合就恰到好处。

    对这样的业务应用来说,supervisor 是“透明”的,因为业务应用完全不知道自己正在被何种进程管理工具管理。这里的进程管理工具可以是 supervisor 也可以是 docker ,业务应用不需要任何修改就可以运行在这两种管理工具里。

  3. Pingback引用通告: supervisor启动监控daemon进程 | 星期八的博客 web & game

  4. 如果Supervisor挂掉了,它管理的进程就归init进程管理了。这时重启Supervisor, 配置的program很多是没办法启动的。因为端口什么的都已经被之前给init管理的进程占用了。这个要怎么解决呢?

    • 最近在调研一些进程管理工具 ,
      我也很好奇这个问题, 请问有找到合适的解决方式了吗

  5. 现在已经解决了。正常来说,Supervisor挂掉,它管理的进程也是会挂掉的。当使用kill -9杀死Supervisor时,它管理的进程才会归init进程管理。建议不要使用kill -9杀死进程,http://www.vaikan.com/no-no-no-dont-use-kill-9/。另外一个问题是,在正常情况下, Supervisor挂掉,它管理的进程也会挂掉,进程的子进程不会跟着一起挂,这些子进程会归init管理,占用资源。此时只要在Supervisor的配置文件里添加stopasgroup=true即可,具体意义查看文档http://supervisord.org/configuration.html#program-x-section-settings。至于管理Supervisor,目前有Upstart和Systemd, 这些比SysVinit更好。

发表评论

电子邮件地址不会被公开。 必填项已用*标注