如何用supervisor守护php

最近有同事有个针对php-fpm进程的监护需求,也即:如果php-fpm的master进程意外退出(可能是crash,也可能是被误kill),那么希望master进程能被自动拉起,以免中断服务。

我们知道,supervisor是一个非常强大的进程监控(monitor & control)工具,它理论上可以实现php-fpm master进程的守护需求。因此,我帮同事试验了如何用supervisor完成他的需求,结果表明,supervisor确实是神器,只需一个合理的配置文件,它就能解决问题。

下面是我的调研过程及最终实现php-fpm主进程守护功能的配置文件,在此做个记录,也希望能帮助到别人。

1. 安装supervisor

supervisor本身是python实现的,而且是调研阶段,故先创建一个新的virtualenv环境,然后用pip安装好supervisor包。

至此,基本的调研环境搭建完毕。当然,php-fpm和PHP环境以及前端的Nginx是早就ready的。

2. 分析php-fpm.sh脚本

通常编译安装PHP后,php-fpm这个2进制的C程序也会被编译并安装好,典型路径在php_install_path/sbin/目录下。该目录下还有个名为php-fpm.sh的脚本用于控制php-fpm进程的start/stop/restart/reload等动作。

./sbin/php-fpm.sh脚本中,”start”操作启动了php-fpm主进程,其余的操作都是通过向php-fpm master进程发signal实现的。

” instart)–daemonize wait_;;

从上面是终端输入”./sbin/php-fpm.sh start”时,实际执行的代码,可以看到,php-fpm进程的启动参数是–daemonize $php_opts,而$php_opts的值为”–fpm-config $php_fpm_CONF –pid $php_fpm_PID”。

注意: php-fpm.sh启动php-fpm master进程时,传入了daemonize参数,,表明php-fpm master process以守护(daemon)方式启动,而根据supervisor文档的说明,当用supervisor监护进程时,被监护进程不能是守护进程,这是由于守护进程通常会在fork完子进程后就让父进程”结束生命”,也即由supervisor创建的父进程退出,此时,supervisor无法再监护已退出进程创建出来的子进程。关于daemon process的行为,可以参考Linux Daemon Writing HOWTO一文来理解。

根据上面的分析,我们知道,只要supervisor启动php-fpm进程时,不传入daemonize参数即可。

3. 实现php-fpm主进程守护功能的supervisor配置文件

上面的分析已经告诉我们应该怎么解决问题了,下面直接上验证可用的配置文件。文件位于php-fpm.conf同级目录下(典型路径为php_install_path/etc/)。

[inet_http_server]; inet (TCP) server disabled by :iface)[supervisord]logfile=./var/log/supervisord.log ; (main log file;default $CWD/supervisord.log)logfile_maxbytes=50MB; (max main logfile bytes b4 rotation;default 50MB)logfile_backups=2; (num of main logfile rotation backups;default 10)loglevel=info; (log level;default info; others: debug,warn,trace)pidfile=./var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)nodaemon=false; (start in foreground if true;default false)minfds=1024; (min. avail startup file descriptors;default 1024)minprocs=200; (min. avail process descriptors;default 200)identifier=sup.php-fpm; (supervisord identifier, ‘)[rpcinterface:supervisor]supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface[supervisorctl]serverurl=http://:9015 ; use an url to specify an inet socket[program:php-fpm]command=bash -c “sleep 1 && /home/slvher/tools/php/5.6.11/sbin/php-fpm –fpm-config /home/slvher/tools/php/5.6.11/etc/php-fpm.conf –pid /home/slvher/tools/php/5.6.11/var/run/php-fpm.pid” ; the program (relative uses PATH, can take args)process_name=%(program_name)s ; process_name expr (default %(program_name)s)autostart=true; start at supervisord start (default: true)autorestart=true; whether/when to restart (default: unexpected)startretries=5; max # of serial start failures (default 3)exitcodes=,2)stopsignal=QUIT; signal used to kill process (default TERM)stopwaitsecs=)

配置文件结构通过查看supervisor文档很容易就能掌握,有两个配置项需要特别注意:

1) command

它指定了supervisor要监控的进程的启动命令,可以看到,这里我们没有给php-fpm传入daemonize参数,其余参数只是展开了php-fpm.sh中的shell变量而已。

大家已经注意到,command也不是直接调起php-fpm,而是通过bash -c执行了两个命令,而第一个命令是sleep 1。这是由于php-fpm在stop后,其占用的端口通常不能立即释放,此时,supervisor以极快的速度试图重新拉起进程时,可能会由于报如下错误而导致几次retry均失败:

## var/log/php-fpm.error.log[18-Jul-2015 21:35:28] ERROR: unable to bind listening socket for address ‘127.0.0.1:9002’: Address already in use (98)[18-Jul-2015 21:35:28] ERROR: FPM initialization failed

而supervisor目前还不支持delay restart功能,因此,这里只能通过先sleep再启动的略显tricky的方法来解决问题,结果表明,疗效不错且无副作用。-_-

2) autorestart获得幸福的二法门是珍惜你所拥有的、遗忘你所没有的

如何用supervisor守护php

相关文章:

你感兴趣的文章:

标签云: