linux-PHP环境安装

什么是FastCGI

快速通用网关接口(Fast Common Gateway Interface/FastCGI)是一种让交互程序与Web服务器通信的协议。FastCGI是早期通用网关接口(CGI)的增强版本。
FastCGI致力于减少网页服务器与CGI程序之间互动的开销,从而使服务器可以同时处理更多的网页请求。

###FastCGI 的优点
FastCGI 的优点是把动态语言和HTTP Server分离开来,所以Nginx与PHP/PHP-FPM经常被部署在不同的服务器上,以分担前端Nginx服务器的压力,使Nginx专一处理静态请求和转发动态请求,而PHP/PHP-FPM服务器专一解析PHP动态请求。

nginx+FastCGI运行原理

Nginx不支持对外部程序的直接调用或者解析,所有的外部程序(包括PHP)必须通过FastCGI接口来调用。FastCGI接口在Linux下是socket(这个socket可以是文件socket,也可以是ip socket)。为了调用CGI程序,还需要一个FastCGI的wrapper(wrapper可以理解为用于启动另一个程序的程序),这个wrapper绑定在某个固定socket上,如端口或者文件socket。当Nginx将CGI请求发送给这个socket的时候,通过FastCGI接口,wrapper接收到请求,然后派生出一个新的线程,这个线程调用解释器或者外部程序处理脚本并读取返回数据;接着,wrapper再将返回的数据通过FastCGI接口,沿着固定的socket传递给Nginx;最后,Nginx将返回的数据发送给客户端。这就是Nginx+FastCGI的整个运作过程。

spawn-fcgi和PHP-FPM对比

  • ligttpd的spwan-fcgi在高并发访问的时候,会出现内存泄漏甚至自动重启FastCGI的问题。
  • PHP-FPM作为PHP的一个补丁,在安装的时候需要和PHP源码一起编译,也就是说PHP-FPM被编译到PHP内核中,因此在处理性能方面更加优秀。同时PHP-FPM在处理高并发方面也比spawn-fcgi引擎好很多,因此,推荐使用Nginx+PHP/PHP-FPM这个组合对PHP进行解析。

php安装

  • 尽量使用PHP和PHP-FPM版本一致,如果版本之间相差太大,可能会出现兼容问题。
  • 早期的时候fpm是PHP的一个补丁包,PHP在 5.3.3 之后已经将php-fpm写入php源码核心了。所以已经不需要另外下载了。

安装相关依赖及软件

centos 5 安装包组:Xsoftware Development
centos 6

1
yum install zlib libxml libjpeg freetype libpng gd  curl libiconv  zlib-devel libxml2-devel libjpeg-devel freetype-devel libpng-devel gd-devel curl-devel libxslt*  -y

iconv字符编码转换命令

1
2
3
4
5
6
7
tar zxf libiconv-1.14.tar.gz
cd libiconv-1.14
./configure --prefix=/usr/local/libiconv
make
make install
sleep 2
cd ../

mcrypt 是php里面重要的加密支持扩展库,这里注意的是mcrypt软件依赖libmcrypt和mhash两个库。

libmcrypt依赖库安装

默认路径:/usr/local/lib/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
wget http://downloads.sourceforge.net/mcrypt/libmcrypt-2.5.8.tar.gz
tar zxf libmcrypt-2.5.8.tar.gz
cd libmcrypt-2.5.8
./configure
make
make install
sleep 2
/sbin/ldconfig
cd libltdl/
./configure --enable-ltdl-install
make
make install
sleep 2
cd ../../

Mhash是基于离散数学原理的不可逆向的php加密方式扩展库,其在默认情况下不开启。mhash的可以用于创建校验数值,消息摘要,消息认证码,以及无需原文的关键信息保存(如密码)等。

默认路径:/usr/local/lib/

1
2
3
4
5
6
7
8
wget http://downloads.sourceforge.net/mhash/mhash-0.9.9.9.tar.gz
tar zxf mhash-0.9.9.9.tar.gz
cd mhash-0.9.9.9/
./configure
make
make install
sleep 2
cd ../

默认路径:/usr/local/bin/

1
2
3
4
5
6
7
8
9
wget http://downloads.sourceforge.net/mcrypt/mcrypt-2.6.8.tar.gz
tar zxf mcrypt-2.6.8.tar.gz
cd mcrypt-2.6.8/
/sbin/ldconfig
./configure LD_LIBRARY_PATH=/usr/local/lib
make
make install
sleep 2
cd ../

配置相关连接

1
2
3
4
5
6
7
8
9
10
11
12
rm -f /usr/lib64/libmcrypt.*
rm -f /usr/lib64/libmhash*
ln -s /usr/local/lib64/libmcrypt.la /usr/lib64/libmcrypt.la
ln -s /usr/local/lib64/libmcrypt.so /usr/lib64/libmcrypt.so
ln -s /usr/local/lib64/libmcrypt.so.4 /usr/lib64/libmcrypt.so.4
ln -s /usr/local/lib64/libmcrypt.so.4.4.8 /usr/lib64/libmcrypt.so.4.4.8
ln -s /usr/local/lib64/libmhash.a /usr/lib64/libmhash.a
ln -s /usr/local/lib64/libmhash.la /usr/lib64/libmhash.la
ln -s /usr/local/lib64/libmhash.so /usr/lib64/libmhash.so
ln -s /usr/local/lib64/libmhash.so.2 /usr/lib64/libmhash.so.2
ln -s /usr/local/lib64/libmhash.so.2.0.1 /usr/lib64/libmhash.so.2.0.1
ln -s /usr/local/bin/libmcrypt-config /usr/bin/libmcrypt-config
1
2
ln -s /application/mysql/lib/libmysqlclient.so.18  /usr/lib64/
mkdir -p ext/phar/phar.phar

PHP安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
./configure \
--prefix=/application/php5.3.27 \
--with-mysql=/application/mysql \
--with-iconv-dir=/usr/local/libiconv \
--with-freetype-dir \
--with-jpeg-dir \
--with-png-dir \
--with-zlib \
--with-libxml-dir=/usr \
--enable-xml \
--disable-rpath \
--enable-safe-mode \
--enable-bcmath \
--enable-shmop \
--enable-sysvsem \
--enable-inline-optimization \
--with-curl \
--with-curlwrappers \
--enable-mbregex \
--enable-fpm \
--enable-mbstring \
--with-mcrypt \
--with-gd \
--enable-gd-native-ttf \
--with-openssl \
--with-mhash \
--enable-pcntl \
--enable-sockets \
--with-xmlrpc \
--enable-zip \
--enable-soap \
--enable-short-tags \
--enable-zend-multibyte \
--enable-static \
--with-xsl \
--with-fpm-user=nginx \
--with-fpm-group=nginx \
--enable-ftp

结果:

1
2
3
4
5
6
7
8
9
10
+--------------------------------------------------------------------+
| License: |
| This software is subject to the PHP License, available in this |
| distribution in the file LICENSE. By continuing this installation |
| process, you are bound by the terms of this license agreement. |
| If you do not agree with the terms of this license, you must abort |
| the installation process at this point. |
+--------------------------------------------------------------------+

Thank you for using PHP.

编译和安装

1
make && make install

配置文件补充
--enable-fastcgi :启用对PHP的FastCGI支持。
--enable-fpm:激活对 FastCGI模式的fpm支持。

Linux 可以不装MySQL,如果连软件包都没有,这样情况可以使用:
1
2
3
4
5
—with-mysql=mysqlnd
其他需要MySQL相关包场景的PHP编译参数:
--enable-mysqlnd \
--with-pdo-mysql=mysqlnd \
--with-mysqli=mysqlnd \

配置PHP:

解压包中包含两个配置文件:

  • php.ini-development :测试环境使用配置文件,相关debug功能都开启了。
  • php.ini-production :生产环境使用配置文件,相关debug功能都关闭了。
1
# cp php.ini-production /application/php/lib/php.ini

PHP配置完毕。

配置PHP及FCGI进程管理

1
2
3
4
ln -s /application/php5.3.27/ /application/php
cp php.ini-production /application/php/lib/php.ini
cd /application/php/etc/
mv php-fpm.conf.5.3.27 php-fpm.conf

php-fpm.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
{pid = /app/logs/php-fpm.pid
error_log = /app/logs/php-fpm.log
log_level= error
rlimit_files=32768
listen.owner=nginx
listen.group=nginx
pm.max_children = 1024
pm.start_servers = 16
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.process_idle_timeout=15s;
pm.max_requests=2048
slowlog=/app/logs/$pool.log.slow}

mkdir -p /app/logs

启动:

1
2
3
4
/application/php/sbin/php-fpm -t
/application/php/sbin/php-fpm
netstat -lntup|grep php-fpm
ps -ef|grep php-fpm

添加开机自启动:

1
2
3
4
5
vim /etc/rc.local
/etc/init.d/nysqld start
/application/php/sbin/php-fpm
/application/nginx/sbin/nginx

PHP-FPM 配置文件详解

[global]配置

  • pid string: PID文件的位置。默认为空。
  • error_log string: 错误日志的位置。默认:安装路径 #INSTALL_PREFIX#/log/php-fpm.log。
  • log_level string: 错误级别。可用级别为:alert(必须立即处理),error(错误情况),warning(警告情况),notice(一般重要信息),debug(调试信息)。默认:notice。
  • emergency_restart_threshold int : 如果子进程在 emergency_restart_interval 设定的时间内收到该参数设定次数的 SIGSEGV 或者 SIGBUS退出信息号,则FPM会重新启动。0 表示“关闭该功能”。默认值:0(关闭)。
  • emergency_restart_interval mixed : emergency_restart_interval 用于设定平滑重启的间隔时间。这么做有助于解决加速器中共享内存的使用问题。可用单位:s(秒),m(分),h(小时)或者 d(天)。默认单位:s(秒)。默认值:0(关闭)。
  • process_control_timeout mixed: 设置子进程接受主进程复用信号的超时时间。可用单位:s(秒),m(分),h(小时)或者 d(天)。默认单位:s(秒)。默认值:0(关闭)。
  • daemonize boolean: 设置 FPM 在后台运行。设置“no”将 FPM 保持在前台运行用于调试。默认值:yes。

Pool Definitions 进程池设置

在FPM中,可以使用不同的设置来运行多个进程池。 这些设置可以针对每个进程池单独设置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[www]
user = nginx
group = nginx
listen = 127.0.0.1:9000
listen.owner = nginx
listen.group = nginx
pm = dynamic
pm.max_children = 1024
pm.start_servers = 16
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.max_requests = 2048
slowlog = /app/logs/$pool.log.slow
request_slowlog_timeout = 10
php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f 49000448@qq.com

重要的配置参数

  • listen string: 设置接受 FastCGI 请求的地址。
  • user string: FPM 进程运行的Unix用户。必须设置。
  • group string: FPM 进程运行的 Unix 用户组。如果没有设置,则默认用户的组被使用。
  • pm string: 设置进程管理器如何管理子进程。可用值:static,ondemand,dynamic。必须设置。
  • request_terminate_timeout mixed: 设置单个请求的超时中止时间。该选项可能会对 php.ini 设置中的 ‘max_execution_time’ 因为某些特殊原因没有中止运行的脚本有用。设置为 ‘0’ 表示 ‘Off’。可用单位:s(秒),m(分),h(小时)或者 d(天)。默认单位:s(秒)。默认值:0(关闭)。
  • rlimit_files int: 设置文件打开描述符的 rlimit 限制。默认值:系统定义值。
  • pm.max_requests int: 设置每个子进程重生之前服务的请求数。对于可能存在内存泄漏的第三方模块来说是非常有用的。如果设置为 ‘0’ 则一直接受请求,等同于 PHP_FCGI_MAX_REQUESTS 环境变量。默认值:0。
  • listen.allowed_clients string: 设置允许连接到 FastCGI 的服务器 IPV4 地址。等同于 PHP FastCGI (5.2.2+) 中的 FCGI_WEB_SERVER_ADDRS 环境变量。仅对 TCP 监听起作用。每个地址是用逗号分隔,如果没有设置或者为空,则允许任何服务器请求连接。默认值:any。

详细配置参数

  • listen string: 设置接受 FastCGI 请求的地址。可用格式为:’ip:port’,’port’,’/path/to/unix/socket’。每个进程池都需要设置。

  • listen.backlog int: 设置 listen(2) 的半连接队列长度。“-1”表示无限制。默认值:-1。

  • listen.allowed_clients string: 设置允许连接到 FastCGI 的服务器 IPV4 地址。等同于 PHP FastCGI (5.2.2+) 中的 FCGI_WEB_SERVER_ADDRS 环境变量。仅对 TCP 监听起作用。每个地址是用逗号分隔,如果没有设置或者为空,则允许任何服务器请求连接。默认值:any。

  • listen.owner string: 如果使用,表示设置 Unix 套接字的权限。在Linux中,读写权限必须设置,以便用于 WEB 服务器连接。在很多 BSD 派生的系统中可以忽略权限允许自由连接。默认值:运行所使用的用户和组,权限为 0666。

  • listen.group string: 参见 listen.owner。

  • listen.mode string: 参见 listen.owner。

  • user string: FPM 进程运行的Unix用户。必须设置。

  • group string: FPM 进程运行的 Unix 用户组。如果没有设置,则默认用户的组被使用。

  • pm string: 设置进程管理器如何管理子进程。可用值:static,ondemand,dynamic。必须设置。

  • static: 子进程的数量是固定的(pm.max_children)。
  • ondemand: 进程在有需求时才产生(当请求时,与 dynamic 相反,pm.start_servers 在服务启动时即启动。
  • dynamic: 子进程的数量在下面配置的基础上动态设置:pm.max_children,pm.start_servers,pm.min_spare_servers,pm.max_spare_servers。
  • pm.max_children int: pm 设置为 static 时表示创建的子进程的数量,pm 设置为 dynamic 时表示最大可创建的子进程的数量。必须设置。该选项设置可以同时提供服务的请求数限制。类似 Apache 的 mpm_prefork 中 MaxClients 的设置和 普通PHP FastCGI中的 PHP_FCGI_CHILDREN 环境变量。

  • pm.start_servers in: 设置启动时创建的子进程数目。仅在 pm 设置为 dynamic 时使用。默认值:min_spare_servers + (max_spare_servers - min_spare_servers) / 2。

  • pm.min_spare_servers int: 设置空闲服务进程的最低数目。仅在 pm 设置为 dynamic 时使用。必须设置。

  • pm.max_spare_servers int: 设置空闲服务进程的最大数目。仅在 pm 设置为 dynamic 时使用。必须设置。

  • pm.max_requests int: 设置每个子进程重生之前服务的请求数。对于可能存在内存泄漏的第三方模块来说是非常有用的。如果设置为 ‘0’ 则一直接受请求,等同于 PHP_FCGI_MAX_REQUESTS 环境变量。默认值:0。

  • pm.status_path string: FPM 状态页面的网址。如果没有设置,则无法访问状态页面,默认值:无。

  • ping.path string: FPM 监控页面的 ping 网址。如果没有设置,则无法访问 ping 页面。该页面用于外部检测 FPM 是否存活并且可以响应请求。请注意必须以斜线开头(/)。

  • ping.response string: 用于定义 ping 请求的返回响应。返回为 HTTP 200 的 text/plain 格式文本。默认值:pong。

  • request_terminate_timeout mixed: 设置单个请求的超时中止时间。该选项可能会对 php.ini 设置中的 ‘max_execution_time’ 因为某些特殊原因没有中止运行的脚本有用。设置为 ‘0’ 表示 ‘Off’。可用单位:s(秒),m(分),h(小时)或者 d(天)。默认单位:s(秒)。默认值:0(关闭)。

  • request_slowlog_timeout mixed: 当一个请求该设置的超时时间后,就会将对应的 PHP 调用堆栈信息完整写入到慢日志中。设置为 ‘0’ 表示 ‘Off’。可用单位:s(秒),m(分),h(小时)或者 d(天)。默认单位:s(秒)。默认值:0(关闭)。

  • slowlog string: 慢请求的记录日志。默认值:#INSTALL_PREFIX#/log/php-fpm.log.slow。

  • rlimit_files int: 设置文件打开描述符的 rlimit 限制。默认值:系统定义值。

  • rlimit_core int: 设置核心 rlimit 最大限制值。可用值:’unlimited’,0 或者正整数。默认值:系统定义值。

  • chroot string: 启动时的 Chroot 目录。所定义的目录需要是绝对路径。如果没有设置,则 chroot 不被使用。

  • chdir string: 设置启动目录,启动时会自动 Chdir 到该目录。所定义的目录需要是绝对路径。默认值:当前目录,或者根目录(chroot时)。

  • catch_workers_output boolean: 重定向运行过程中的 stdout 和 stderr 到主要的错误日志文件中。如果没有设置,stdout 和 stderr 将会根据 FastCGI 的规则被重定向到 /dev/null。默认值:无。

管理FastCGI 进程

启动FastCGI进程

方法一:

1
/data/app/php/bin/php-cgi --fpm

方法二:

1
/data/app/php/sbin/php-fpm start

推荐采用第二种方法启动FastCGI。
php-fpm logrotate 重新启用log文件。

使用信号重启php-fpm

  • INT, TERM 立刻终止
  • QUIT 平滑终止
  • USR1 重新打开日志文件
  • USR2 平滑重载所有worker进程并重新载入配置和二进制模块

示例:

php-fpm 关闭:

1
kill -INT `cat /data/app/php/var/run/php-fpm.pid`

php-fpm 重启:

1
kill -USR2 `cat /data/app/php/var/run/php-fpm.pid`

php与web中间件整合

php与nginx整合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
server {
listen 80;
server_name blog.biglittleant.cn;
root www/blog;
location / {
root www/blog;
index index.html index.htm;
}
location ~ .*\.(php|php5)?$
{
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
}

fastcgi的优化主要集中在nginx的fastcgi.conf配置文件中。
相关内容参考死磕nginx系列–配置文档解读

测试PHP程序是否正常

1
2
3
4
 cat test.php
<?php
phpinfo();
?>

测试MYSQL是否正常

1
2
3
4
5
6
7
8
9
10
<?php
//$link_id=mysql_connect('主机名','用户','密码');
$link_id=mysql_connect('localhost','root','oldboy123') or mysql_error();

if($link_id){
echo "mysql successful by oldboy !\n";
}else{
echo "mysql_error()";
}
?>

报错汇总:

报错一 编译报错

1
configure: error: Cannot find OpenSSL's <evp.h>

解决办法

1
yum yum install openssl openssl-devel

报错二 make 报错

1
2
3
Generating phar.php
/root/tools/php-5.3.27/sapi/cli/php: error while loading shared libraries: libmysqlclient.so.18: cannot open shared object file: No such file or directory
make: *** [ext/phar/phar.php] Error 127

解决方法:

1
ln -s /application/php5.3.27 /application/php

报错三 make 报错

1
2
3
4
5
6
Generating phar.phar
chmod: cannot access `ext/phar/phar.phar': No such file or directory
make: [ext/phar/phar.phar] Error 1 (ignored)

Build complete.
Don't forget to run 'make test’.

解决办法:

1
[root@test2 php-5.3.27]# mkdir  -p ext/phar/phar.phar

报错四 编译报错:

1
configure: error: Cannot find OpenSSL's <evp.h>

解决方法:

1
[root@nfs-client php-5.3.27]# yum install openssl-devel -y

报错五编译报错:

1
2
checking for XSL support... yes
configure: error: xslt-config not found. Please reinstall the libxslt >= 1.1.0 distribution

解决方法:

1
[root@nfs-client php-5.3.27]# yum install libxslt-devel -y

报错六 configure 报错:

1
2
3
4
checking if we should use cURL for url streams... no
checking for cURL in default path... not found
configure: error: Please reinstall the libcurl distribution -
easy.h should be in <curl-dir>/include/curl/

解决办法

1
2
ln -s /application/mysql/lib/libmysqlclient.so.18  /usr/lib64/
mkdir -p ext/phar/phar.phar

参考文档

官方FPM配置文件解读

搞不清FastCgi与PHP-fpm之间是个什么样的关系

搞不清FastCgi与PHP-fpm之间是个什么样的关系

刚开始对这个问题我也挺纠结的,看了《HTTP权威指南》后,感觉清晰了不少。

首先,CGI是干嘛的?CGI是为了保证web server传递过来的数据是标准格式的,方便CGI程序的编写者。

1
2
3
web server(比如说nginx)只是内容的分发者。比如,如果请求/index.html,那么web server会去文件系统中找到这个文件,发送给浏览器,这里分发的是静态数据。好了,如果现在请求的是/index.php,根据配置文件,nginx知道这个不是静态文件,需要去找PHP解析器来处理,那么他会把这个请求简单处理后交给PHP解析器。Nginx会传哪些数据给PHP解析器呢?url要有吧,查询字符串也得有吧,POST数据也要有,HTTP header不能少吧,好的,CGI就是规定要传哪些数据、以什么样的格式传递给后方处理这个请求的协议。仔细想想,你在PHP代码中使用的用户从哪里来的。

当web server收到/index.php这个请求后,会启动对应的CGI程序,这里就是PHP的解析器。接下来PHP解析器会解析php.ini文件,初始化执行环境,然后处理请求,再以规定CGI规定的格式返回处理后的结果,退出进程。web server再把结果返回给浏览器。

好了,CGI是个协议,跟进程什么的没关系。那fastcgi又是什么呢?Fastcgi是用来提高CGI程序性能的。

1
提高性能,那么CGI程序的性能问题在哪呢?"PHP解析器会解析php.ini文件,初始化执行环境",就是这里了。标准的CGI对每个请求都会执行这些步骤(不闲累啊!启动进程很累的说!),所以处理每个时间的时间会比较长。这明显不合理嘛!那么Fastcgi是怎么做的呢?首先,Fastcgi会先启一个master,解析配置文件,初始化执行环境,然后再启动多个worker。当请求过来时,master会传递给一个worker,然后立即可以接受下一个请求。这样就避免了重复的劳动,效率自然是高。而且当worker不够用时,master可以根据配置预先启动几个worker等着;当然空闲worker太多时,也会停掉一些,这样就提高了性能,也节约了资源。这就是fastcgi的对进程的管理。

那PHP-FPM又是什么呢?是一个实现了Fastcgi的程序,被PHP官方收了。

1
大家都知道,PHP的解释器是php-cgi。php-cgi只是个CGI程序,他自己本身只能解析请求,返回结果,不会进程管理(皇上,臣妾真的做不到啊!)所以就出现了一些能够调度php-cgi进程的程序,比如说由lighthttpd分离出来的spawn-fcgi。好了PHP-FPM也是这么个东东,在长时间的发展后,逐渐得到了大家的认可(要知道,前几年大家可是抱怨PHP-FPM稳定性太差的),也越来越流行。

好了,最后来回来你的问题。 网上有的说,fastcgi是一个协议,php-fpm实现了这个协议

1
对。

有的说,php-fpm是fastcgi进程的管理器,用来管理fastcgi进程的

1
2
3
对。php-fpm的管理对象是php-cgi。但不能说php-fpm是fastcgi进程的管理器,因为前面说了fastcgi是个协议,似乎没有这么个进程存在,就算存在php-fpm也管理不了他(至少目前是)。 有的说,php-fpm是php内核的一个补丁

以前是对的。因为最开始的时候php-fpm没有包含在PHP内核里面,要使用这个功能,需要找到与源码版本相同的php-fpm对内核打补丁,然后再编译。后来PHP内核集成了PHP-FPM之后就方便多了,使用--enalbe-fpm这个编译参数即可。

有的说,修改了php.ini配置文件后,没办法平滑重启,所以就诞生了php-fpm

1
是的,修改php.ini之后,php-cgi进程的确是没办法平滑重启的。php-fpm对此的处理机制是新的worker用新的配置,已经存在的worker处理完手上的活就可以歇着了,通过这种机制来平滑过度。

还有的说PHP-CGI是PHP自带的FastCGI管理器,那这样的话干吗又弄出个php-fpm

1
不对。php-cgi只是解释PHP脚本的程序而已。