寻觅生命中的那一片浅草......

文章带标签 PHP

PHP的master与worker进程关系的一点纠结

纠结的起点

同事发了一篇文档,里面提及

  1. FPM 的 master 进程接收到请求
  2. master 进程根据配置指派特定的 worker 进程进行请求处理,如果没有可用进程,返回错误,这也是我们配合 Nginx 遇到502错误比较多的原因。

全文请参考: Nginx 与 FPM 的工作机制

我曾经认为Nginx也是由master负责派发请求给worker,但同事那边马上发了篇文档出来打脸,文章提到master只负责管理worker,如重启,重新加载配置文件,并不会派发请求。祥见:nginx平台初探

纠结过程

为什么我会纠结呢?

  1. 上面提到的Nginx
  2. fpm一开始其实是一个第三方管理软件,类似spawn-cgi,说白了就是负责启动php-cgi进程的,那PHP官方把它整合进来作为官方的php-cgi管理工具后,会委以「派发请求」这样的重任吗?

早上和同事一起纠结了一下,纠结过程如下:

  1. strace对比master和worker的行为,同事把Nginx和fpm都设置成了1个worker进程观察,得出结论是不会经过fpm的master进程
strace -e network -p fpm_master_pid
strace -e network -p fpm_worker_pid
  1. 放狗,发现另外一种说法,见:关于fastcgi和php-fpm的疑惑,引用如下

master进程并不接收和分发请求,而是worker进程直接accpet请求后poll处理.

master进程不断调用epoll_wait和getsockopt是用来异步处理信号事件和定时器事件.

这里提一下,Nginx也类似,master进程并不处理请求,而是worker进程直接处理, 不过区别在于Nginx的worker进程是epoll异步处理请求,而PHP-FPM仍然是poll.

  1. 把master干掉,看请求是否可以正常处理,经实际测试,master干掉后,worker依然在,请求也可以正常处理。
kill -HUP fpm_master_pid

其他

  1. worker进程数量不够的时候,显然是manager启动了更多进程,这个时候是manager怎么知道的

答:PHP源码分析 – PHP-FPM运行模式详解,看起来就是满足下面的条件就会执行 fpm_children_make

1. idle < pm_min_spare_servers
2. running_children < pm_max_children
3. MIN(MIN(idle_spawn_rate, pm_min_spare_servers - idle), pm_max_children - running_children) > 0
  1. nginx中配置的fastcgi_pass默认是fastcgi的监听端口,这个配置的意义是什么?

答:浅谈多进程程序的进程控制和管理方式,主要看「多进程下的套接字」,这段文字解释了为什么多进程不需要派发,因为它socket是多进程共享的

纠结论

fpm的master并不承担派发请求的角色。

特别鸣谢纠结侠:郑导(C好厉害)

其他资料

php-fpm的status和ping

php-fpm提供了状态输出,可以通过它来做些监控

修改php-fpm.conf

vi php-fpm.conf

# status
pm.status_path = /php_status

# ping
ping.path = /php_ping

修改fastcgi_params,解决访问php-fpm的status,显示空白页面的问题

vi nginx/conf/fastcgi_params
# 添加
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_script_name;

添加Nginx虚拟主机

server
{
    listen       80;
    server_name  localhost;
    location ~ ^/(php_status|php_ping)$ 
    {
        access_log off; 
        allow 127.0.0.1;
        deny all;
        include fastcgi_params;
        fastcgi_pass 127.0.0.1:10080;
    }
}

这样就可以了,测试

curl http://localhost/php_status
curl http://localhost/php_ping

用gdb分析段错误(Segmentation fault)

开始前,先看下这篇文章,(猛击此处) Redhat Linux下如何生成core dump文件

看完后,开工
vi /root/.bash_profile
加入ulimit -S -c unlimited > /dev/null 2>&1
保存退出,重新加载配置
source /root/.bash_profile

经研究发现,只要把
/usr/local/php/bin/php-cgi –fpm –fpm-config /usr/local/php/etc/php-fpm.conf
放到脚本里都会报
Segmentation fault

vi /root/test.sh
添加
/usr/local/php/bin/php-cgi –fpm –fpm-config /usr/local/php/etc/php-fpm.conf

cd /root
sh test.sh
这是它会报Segmentation fault,并在/root下产生一个core.28522文件,这个文件名后面的数字是随机的
现在我们来看下core.28522里面到底是什么内容,需要用到gdb这个工具

yum -y install gdb

gdb使用的方法是
gdb 产生core时执行的命令 core文件

gdb /usr/local/php/bin/php-cgi core.28522

我们在最后会看到
Core was generated by `/usr/local/php/bin/php-cgi –fpm –fpm-config /usr/local/php/etc/php-fpm.conf’.
Program terminated with signal 11, Segmentation fault.
#0 0x00007f895e2df0b8 in eaccelerator_clean_shutdown ()
from /usr/local/php/lib/php/extensions/no-debug-zts-20060613/eaccelerator.so

由此,我们定位到是EA导致整个段错误的

64位CentOS6系统上编译PHP

CentOS 6 64位版本,默认是不会安装32位软件的,这样就导致我们在安装PHP前安装的库,只会有64位版本

例如
yum -y install libjpeg libjpeg-devel libpng libpng-devel libxml2 libxml2-devel zlib zlib-devel glibc glibc-devel glib2 glib2-devel mhash freetype freetype-devel

这样安装,系统默认只会安装64位版本,假设我们用以下命令去安装PHP

CHOST=”x86_64-pc-linux-gnu” CFLAGS=”-march=nocona -O2 -pipe” CXXFLAGS=”-march=nocona -O2 -pipe” \
./configure –prefix=/usr/local/php \
–with-config-file-path=/etc \
–with-mysql=/usr/loca/mysql –with-pdo-mysql=/usr/local/mysql/bin/mysql_config \
–with-mysqli=/usr/local/mysql/bin/mysql_config \
–with-iconv-dir=/usr/local \
–with-freetype-dir –with-jpeg-dir \
–with-png-dir –with-ttf \
–enable-zip –with-zlib \
–with-gd \
–disable-rpath –enable-discard-path \
–enable-safe-mode –enable-bcmath \
–enable-shmop –enable-sysvsem \
–with-curl –with-curlwrappers \
–enable-fastcgi –enable-force-cgi-redirect \
–enable-mbstring –with-mcrypt \
–disable-ipv6 \
–enable-static \
–enable-maintainer-zts \
–enable-zend-multibyte \
–enable-sockets \
–enable-soap \
–with-openssl \
–without-sqlite –without-pdo-sqlite

则会提示
configure: error: libjpeg.(a|so) not found.

通过rpm -qa |grep libjpeg是有安装的

解决办法是在configure里加入

–with-libdir=lib64

修改后是这样

CHOST=”x86_64-pc-linux-gnu” CFLAGS=”-march=nocona -O2 -pipe” CXXFLAGS=”-march=nocona -O2 -pipe” \
./configure –prefix=/usr/local/php \
–with-libdir=lib64 \
–with-config-file-path=/etc \
–with-mysql=/usr/loca/mysql –with-pdo-mysql=/usr/local/mysql/bin/mysql_config \
–with-mysqli=/usr/local/mysql/bin/mysql_config \
–with-iconv-dir=/usr/local \
–with-freetype-dir –with-jpeg-dir \
–with-png-dir –with-ttf \
–enable-zip –with-zlib \
–with-gd \
–disable-rpath –enable-discard-path \
–enable-safe-mode –enable-bcmath \
–enable-shmop –enable-sysvsem \
–with-curl –with-curlwrappers \
–enable-fastcgi –enable-force-cgi-redirect \
–enable-mbstring –with-mcrypt \
–disable-ipv6 \
–enable-static \
–enable-maintainer-zts \
–enable-zend-multibyte \
–enable-sockets \
–enable-soap \
–with-openssl \
–without-sqlite –without-pdo-sqlite

不过,由于我们MySQL不是用rpm包装的,是自编译安装在/usr/local/mysql
如果使用以上configure参数,则会提示

configure: error: Cannot find libmysqlclient_r under /usr/local/mysql/.
Note that the MySQL client library is not bundled anymore!

此时做个修改

ln -s /usr/local/mysql/lib /usr/local/mysql/lib64

这样就可以configure通过了,然后就make && make install吧

题外话,如果要在CentOS6 64位上yum安装32位的软件
echo ‘multilib_policy=all’ >> /etc/yum.conf
就可以了

2024年十月
« 5月    
 123456
78910111213
14151617181920
21222324252627
28293031