seemebaby 发表于 2017-12-23 09:39:38

关于php-fpm与nginx进程重载的坑

背景
  今天下午发布了一个统计功能,发现线上机器没有mongo模块,于是使用phpize编译了mongo模块,再用kill -HUP 进程号重启进程
  于是乎,以前都没有问题的操作,导致了php-fpm进程全部挂掉了。

现象
  1、执行操作
  

ps -ef|grep php-fpm  
root   
20749   10 Jun15 ?      00:06:04 php-fpm: master process (/usr/local/php/etc/php-fpm.conf)  
nobody   
24144 207490 Nov16 ?      00:00:16 php-fpm: pool www     

  执行重启操作
  

kill -HUP 20749  

  这里没有输出任何东西, 再查看,发现进程挂了
  于是试着重启
  

# /usr/local/php/sbin/php-fpm  
[
18-Nov-2016 21:39:26] ERROR: unable to bind listening socket for address '127.0.0.1:9000': Address already in use (98)  
[
18-Nov-2016 21:39:26] ERROR: FPM initialization failed  

  发现端口已经被使用,但是明明 fast-cgi没有运行了啊。
  于是netstat -nalt|grep 9000,得出一个OA进程占有,这个就很奇怪了。
  暂时不明。
  2、解决
  把OA进程kill掉后,重启发现报错
  

# /etc/init.d/php-fpm restart  
Gracefully shutting down php
-fpm /etc/init.d/php-fpm: line 82: kill: (20749) - No such process  
.........
  

  查看php-fpm的pid文件,还存在。 这个是异常关闭进程导致的,需要手动删除,再重启 -> OK了.
  3、再次出现问题
  环境一样,我再次使用kill -HUP 进程号 再次出现php-fpm master进程挂掉,但是子进程都还存在
  没办法,只好pkill php-fpm再使用/usr/local/php/sbin/php-fpm重启, 好, 又正常了。

研究
  参考线上朋友的说明:
  用HUP信号使Nginx加载新的配置文件 当Nginx接收到HUP信号的时候,它会尝试着去解析并应用这个配置文件,如果没有问题,那么它会创建新的worker进程,并发送信号给旧的 worker进程,让其优雅的退出。 接收到信号的旧的worker进程会关闭监听socket,但是还会处理当前的请求,处理完请求之后,旧的 worker进程退出。
  查看使用yum安装的php-fpm的reload控制脚本
  

reload () {echo -n $"Reloading $prog: "  if ! /usr/sbin/php-fpm --test ; then
  RETVAL=6

  echo $"not>
  failure $"not>  else
  killproc -p ${pidfile} php-fpm -USR2
  ## 或者 kill -USR2 `cat $php_fpm_PID`
  RETVAL=$?
  fi
  echo
  
}
  

  发现官方是使用-USR2 平滑reload的
  网上这位朋友说明如下:
  当你想升级Nginx到一个新的版本,增加或减少module的时候 发送USR2信号给master进程。master进程会把自己的.pid文件重命名为.oldbin(例 如,/usr/local/nginx/logs/nginx.pid.oldbin),然后执行新的二进制文件,从而启动一个新的master进程和新的worker进程.
  为了验证-HUP与-USR2的区别,做实验(回狗窝后自己机器):
  1、php.ini添加上mongo.so, 使用-HUP重启,发现master进程真挂了
  

# /usr/local/php/sbin/php-fpm -t  
[
18-Nov-2016 23:02:01] NOTICE: configuration file /usr/local/php/etc/php-fpm.conf test is successful  
[iyunv@gameyeah_my mongo
-php-driver-legacy]# ps -ef|grep php  
root   
10411 296940 22:53 pts/2    00:00:00 vim php_nginx_reload.md  
root   
10415 297170 22:56 pts/3    00:00:00 grep --colour=always php  
root   
29860   10 21:56 ?      00:00:00 php-fpm: master process (/usr/local/php/etc/php-fpm.conf)  
nobody   
29861 298600 21:56 ?      00:00:01 php-fpm: pool www  
nobody   
29862 298600 21:56 ?      00:00:02 php-fpm: pool www  
nobody   
29908 298600 22:03 ?      00:00:01 php-fpm: pool www  
[iyunv@gameyeah_my mongo
-php-driver-legacy]# kill -HUP 29860  
[iyunv@gameyeah_my mongo
-php-driver-legacy]# ps -ef|grep php  
root   
10411 296940 22:53 pts/2    00:00:00 vim php_nginx_reload.md  
root   
10417 297170 22:56 pts/3    00:00:00 grep --colour=always php  
nobody   
29861   10 21:56 ?      00:00:01 php-fpm: pool www  
nobody   
29862   10 21:56 ?      00:00:02 php-fpm: pool www  
nobody   
29908   10 22:03 ?      00:00:01 php-fpm: pool www   

  只好重启
  

# pkill php-fpm ; /usr/local/php/sbin/php-fpm  

  2、php.ini添加上mongo.so, 使用-USR2重启, 发现一切正常进程号更新; 使用phpinfo()查看mongo模块正常使用.
  

# ps -ef|grep php  
root   
10411 296940 22:53 pts/2    00:00:00 vim php_nginx_reload.md  
root   
10476   10 23:03 ?      00:00:00 php-fpm: master process (/usr/local/php/etc/php-fpm.conf)  
nobody   
10477 104760 23:03 ?      00:00:00 php-fpm: pool www  
nobody   
10478 104760 23:03 ?      00:00:00 php-fpm: pool www  
root   
10480 297170 23:03 pts/3    00:00:00 grep --colour=always php  
[iyunv@gameyeah_my mongo
-php-driver-legacy]# kill -USR2 10476  
[iyunv@gameyeah_my mongo
-php-driver-legacy]# ps -ef|grep php  
root   
10411 296940 22:53 pts/2    00:00:00 vim php_nginx_reload.md  
root   
10481   10 23:05 ?      00:00:00 php-fpm: master process (/usr/local/php/etc/php-fpm.conf)  
nobody   
10482 104810 23:05 ?      00:00:00 php-fpm: pool www  
nobody   
10483 104810 23:05 ?      00:00:00 php-fpm: pool www  
root   
10485 297170 23:05 pts/3    00:00:00 grep --colour=always php  

  3、修改php.ini, 不添加mongo.so,使用 -HUP重启 --- master进程一样关闭了,只留下子进程
  4、重置,不添加mongo.so,使用 -USR2重启 --- 一切正常
  5、我重新以不修改php.ini的方式分别以-HUP/-USR2尝试重启,现象与上面一样
  1) 使用kill -HUP pid ,master进程关闭,没有成功启动新的master进程
  2) 使用kill -USR2 pid, 旧master进程关闭,新的master进程成功启动
  6、是不是php-fpm的特有性质呢??于是改试nginx进程
  1) 使用-HUP重启, 发现修改的配置生效了,但是进程号未修改
  

# cat /usr/local/nginx/logs/nginx.pid  

26220  
[iyunv@gameyeah_my mongo
-php-driver-legacy]# kill -HUP `cat /usr/local/nginx/logs/nginx.pid`  
[iyunv@gameyeah_my mongo
-php-driver-legacy]# ps -ef|grep nginx  
nobody   
5852 193720 Apr10 ?      00:00:48 nginx: worker process  
nobody   
5853 193720 Apr10 ?      00:00:30 nginx: cache manager process  
root   
10411 296940 22:53 pts/2    00:00:00 vim php_nginx_reload.md  
www      
10543 262200 23:22 ?      00:00:00 nginx: worker process  
www      
10544 262200 23:22 ?      00:00:00 nginx: worker process  
www      
10545 262200 23:22 ?      00:00:00 nginx: worker process  
www      
10546 262200 23:22 ?      00:00:00 nginx: worker process  
root   
10548 297170 23:22 pts/3    00:00:00 grep --colour=always nginx  
root   
19372   10 Apr08 ?      00:00:00 nginx: master process /usr/local/nginx-rtmp/sbin/nginx -c /usr/local/nginx-rtmp/conf/nginx.conf  
root   
26220   10 Apr15 ?      00:00:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf  
[iyunv@gameyeah_my mongo
-php-driver-legacy]# cat /usr/local/nginx/logs/nginx.pid  

26220  

  2) 使用-USR2重启,发现新的master进程起来了,旧的master进程还存在;再使用-QUIT关闭旧进程(-WINCH一样没有见关闭),过一段时间发现旧进程真没了.
  

# kill -USR2 `cat /usr/local/nginx/logs/nginx.pid`  
[iyunv@gameyeah_my mongo
-php-driver-legacy]# ps -ef|grep nginx  
nobody   
5852 193720 Apr10 ?      00:00:48 nginx: worker process  
nobody   
5853 193720 Apr10 ?      00:00:30 nginx: cache manager process  
root   
10411 296940 22:53 pts/2    00:00:00 vim php_nginx_reload.md  
www      
10543 262200 23:22 ?      00:00:00 nginx: worker process  
www      
10544 262200 23:22 ?      00:00:00 nginx: worker process  
www      
10545 262200 23:22 ?      00:00:00 nginx: worker process  
www      
10546 262200 23:22 ?      00:00:00 nginx: worker process  
root   
10551 262200 23:23 ?      00:00:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf  
www      
10552 105510 23:23 ?      00:00:00 nginx: worker process  
www      
10553 105510 23:23 ?      00:00:00 nginx: worker process  
www      
10554 105510 23:23 ?      00:00:00 nginx: worker process  
www      
10555 105510 23:23 ?      00:00:00 nginx: worker process  
root   
10557 297170 23:23 pts/3    00:00:00 grep --colour=always nginx  
root   
19372   10 Apr08 ?      00:00:00 nginx: master process /usr/local/nginx-rtmp/sbin/nginx -c /usr/local/nginx-rtmp/conf/nginx.conf  
root   
26220   10 Apr15 ?      00:00:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf  

  真心查看nginx官方提供的reload方法是使用-HUP
  

reload() {echo -n $"Reloading $prog: "  killproc
-p ${pidfile} ${prog} -HUP  RETVAL
=$?  echo
  
}
  

  结论
  php-fpm与nginx的使用-USR2/-HUP意义不一样!
  Master进程能够接收并处理如下的信号:
  TERM, INT(快速退出,当前的请求不执行完成就退出)
  QUIT (优雅退出,执行完当前的请求后退出)
  HUP (重新加载配置文件,用新的配置文件启动新worker进程,并优雅的关闭旧的worker进程, 用于nginx的加载新配置,不能用于php-fpm加载新配置)
  USR1 (重新打开日志文件)
  USR2 (平滑的升级nginx二进制文件/平滑加载php-fpm新配置)
  WINCH (优雅的关闭worker进程)
  于是 可以自己写php-fpm控制脚本
  关闭
  

kill -QUIT `cat $php_fpm_PID`  

  平滑重载配置
  

kill -USR2 `cat $php_fpm_PID`  

  强制关闭
  

kill -TERM `cat $php_fpm_PID`  

  可以自己写nginx控制脚本
  关闭
  

kill -QUIT `cat /usr/local/nginx/logs/nginx.pid`  

  平滑重载配置
  

kill -HUP `cat /usr/local/nginx/logs/nginx.pid`  

  平滑升级nginx,即升级新编译的nginx
  

OldPid=`cat /usr/local/nginx/logs/nginx.pid`  

kill -USR2 $OldPid  

kill -QUIT $OldPid  

--------------------------------------------  
upgrade() {
  
oldbinpidfile
=${pidfile}.oldbin  
configtest
-q || return  

echo -n $"Starting new master $prog: "  
killproc
-p ${pidfile} ${prog} -USR2  

echo  

  
for i in `/usr/bin/seq $UPGRADEWAITLOOPS`; do
  /bin/usleep $SLEEPMSEC
  if [ -f ${oldbinpidfile} -a -f ${pidfile} ]; then
  echo -n $"Graceful shutdown of old $prog: "
  killproc -p ${oldbinpidfile} ${prog} -QUIT
  RETVAL=$?
  echo
  return
  fi
  
done
  

  
echo $"Upgrade failed!"
  
RETVAL=1
  
}
  

  转载自:http://gameyeah.net/blog/php_nginx_reload.html 《php-fpm与nginx进程重载》
页: [1]
查看完整版本: 关于php-fpm与nginx进程重载的坑