1) 目前各种服务器HTTP Server对PHP的支持一共有三种:
a.通过HTTPServer内置的模块来实现,
例如Apache的mod_php5,类似的Apache内置的mod_perl可以对perl支持;
b.通过CGI来实现,这个就好比之前perl的CGI,该种方式的缺点是性能差,因为每次服务器遇到这些脚本都需要重新启动脚本解析器来执行脚本然后将结果返回给服务器;另一方面就是不太安全;该方面几乎很少使用了。
c.最新出现一种叫做FastCGI。所谓FastCGI就是对CGI的改进。它一般采用C/S结构,一般脚本处理器会启动一个或者多个daemon进程,每次HTTPServer遇到脚本的时候,直接交付给FastCGI的进程来执行,然后将得到的结果(通常为html)返回给浏览器。
>该种方法的问题存在一个小问题是当遇到大流量的频繁请求的话,脚本处理器的daemon进程可能会超负荷从而变得很慢,甚至发生内存泄漏;
>但是比较起Apache的内置模块的方式的优点是由于Server和脚本解析器完全分开各负其责,因此服务器不再臃肿,可以专心地进行静态文件响应或者将动态脚本解析器的结果返回给用户客户端。所以比较起Apache的内置模块方式,有时候性能要提高很多。有人测试可能会达到Apache+mod_php的5~10倍。
2) 使用FastCGI方式现在常见的有两种stack:ligthttpd+spawn-fcgi; 另外一种是nginx+PHP-FPM(也可以用spawn-fcgi) 。
a.如上面所说该两种结构都采用FastCGI对PHP支持,因此HTTPServer完全解放出来,可以更好地进行响应和并发处理。因此lighttpd和nginx都有small, but powerful和efficient的美誉。
b. 该两者还可以分出一个好坏来,spawn-fcgi由于是lighttpd的一部分,因此安装了lighttpd一般就会使用spawn-fcgi对php支持,但是目前有用户说ligttpd的spwan-fcgi在高并发访问的时候,会出现上面说的内存泄漏甚至自动重启fastcgi。即:PHP脚本处理器当机,这个时候如果用户访问的话,可能就会出现白页(即PHP不能被解析或者出错)。
另一个:首先nginx不像lighttpd本身含带了fastcgi(spawn-fcgi),因此它完全是轻量级的,必须借助第三方的FastCGI处理器才可以对PHP进行解析,因此其实这样看来nginx是非常灵活的,它可以和任何第三方提供解析的处理器实现连接从而实现对PHP的解析(在nginx.conf中很容易设置)。
nginx可以使用spwan-fcgi(需要一同安装lighttpd,但是需要为nginx避开端口,一些较早的blog有这方面安装的教程),但是由于spawn-fcgi具有上面所述的用户逐渐发现的缺陷,现在慢慢减少使用nginx+spawn-fcgi组合了。
c. 由于spawn-fcgi的缺陷,现在出现了新的第三方(目前还是,听说正在努力不久将来加入到PHP core中)的PHP的FastCGI处理器,叫做PHP-FPM(具体可以google)。它和spawn-fcgi比较起来有如下优点:
由于它是作为PHP的patch补丁来开发的,安装的时候需要和php源码一起编译,也就是说编译到php core中了,因此在性能方面要优秀一些;
同时它在处理高并发方面也优于spawn-fcgi,至少不会自动重启fastcgi处理器。具体采用的算法和设计可以google了解。
因此,如上所说由于nginx的轻量和灵活性,因此目前性能优越,越来越多人逐渐使用这个组合:nginx+PHP/PHP-FPM 。
3) 因此总结:
目前在HTTPServer这块基本可以看到有三种stack比较流行:
>Apache+mod_php5
>lighttp+spawn-fcgi
>nginx+PHP-FPM
三者后两者性能可能稍优,但是Apache由于有丰富的模块和功能,目前来说仍旧是老大。有人测试nginx+PHP-FPM在高并发情况下可能会达到Apache+mod_php5的5~10倍,现在nginx+PHP-FPM使用的人越来越多。
下面着重介绍stack:
Apache+mod_php5和nginx+PHP-FPM的安装和配置。对于lighttpd+spawn-fcgi,由于我个人没有怎么用过,所以如下不准备介绍,感兴趣可以查阅资料。
1.Apache+mod_php模式:
我们很久一段时间使用经典的Apache+mod_php:
Apache对PHP的支持是通过Apache的模块来支持的。如果曾源代码编译安装php的话,如果希望Apache支持PHP的话,在./configure步骤需要指定--with-apxs2=/usr/local/apache2/bin/apxs 表示告诉编译器通过Apache的mod_php5/apxs来提供对PHP5的解析;
而且在最后一步make install的时候我们会看到将动态链接库libphp5.so(Apache模块)拷贝到apache2的安装目录的modules目录下,并且还需要在httpd.conf配置文件中添加LoadModule语句来动态将libphp5.so 模块加载进来,从而实现Apache对php的支持。
1)由于该模式实在太经典了,因此这里关于安装部分不准备详述了,相对来说比较简单。
2)这里之所以仍旧列出来Apache+mod_php5来讨论,是因为:
看过上一篇文章的话,我们知道nginx一般包括两个用途HTTPServer和Reverse Proxy Server(反向代理服务器)。
我们介绍了如何在前端部署nginx作为reverse proxy server,后端布置多个Apache来实现机群系统server cluster架构的。
因此,实际生产中,我们仍旧能够保留Apache+mod_php5的经典App Server,而仅仅使用nginx来当做前端的reverse proxy server来实现代理和负载均衡。因此,建议nginx(1个或者多个)+多个apache的架构继续使用下去。
2. nginx+PHP-FPM:
1)通过上面的分析,尽管我们可以仍旧保留Apache+mod_php来处理PHP,所有的静态文件和负载均衡由顶在前端的nginx来完成,但是由于nginx和PHP-FPM各自的优越性,使得nginx+PHP-FPM的组合的性能已经很超越Apache+mod_php。
因此很多人渐渐放弃了Apache+mod_php的组合了,而完全使用nginx+PHP-FPM来实现对PHP的处理。
因此现在出现了新的名词叫做LEMP(Linux+EngineX(nginx)+MySQL+PHP),慢慢要代替经典很多年的LAMP 。
2)甚至出现一种新的server cluster:
其中看不到Apache的影子了,全部由nginx来搞定。nginx轻量型,高性能,高灵活性使得它完全能够应付过来。
由于PHP-FPM是C/S结构,因此我们前端保留nginx来做负载均衡;对于之前后端的各个Apache服务器,我们不需要安装Apache了,对PHP重新编译安装使其以PHP-FPM方式支持FastCGI;
然后在nginx中配置将客户端的php请求分别pass到后台的多个运行的PHP-FPM,后者进行处理然后返回给nginx,然后显示给用户。整个过程可以完全不要Apache。
3) 下面我们具体来介绍如何来安装和简单配置
nginx+PHP+PHP-FPM+MySQL.
3. 安装和配置nginx+PHP+PHP-FPM+MySQL:
1) 安装MySQL:
这里之所以首先要安装MySQL,是因为之后编译安装PHP的时候,可以直接指定对MySQL的支持。
我们知道PHP对MySQL的支持是通过PHP扩展实现的。
可以源代码安装,不过我使用的Ubuntu,直接使用了其发布的二进制包安装了:
$sudo apt-get install mysql-server
安装的时候需要提示设置root密码;
之后使用
$netstat -tap |grep mysql
看看是否正常运行;
2) 安装PHP和PHP-FPM:
我们之前介绍了PHP-FPM是对PHP的补丁,因此需要和PHP一起编译安装。我这里使用的PHP 5.2.10 。
a. 下载安装包:
从php.net 下载:php-5.2.10.tar.gz
从PHP-FPM官网下载:php-5.2.10-fpm-0.5.13.diff.gz
注意两个版本尽量相同(不相同可能出错,我自己没试过)。
b. 解压缩打补丁
$tar xzvf php-5.2.10.tar.gz
$gzip -cd php-5.2.10-fpm-0.5.13.diff.gz | patch -d php-5.2.10 -p1
倘若中间需要哪个命令shell不认识,可以使用apt-get安装,或者google找答案。
c. 配置编译环境:
在安装之前可能需要安装几个依赖包:
sudo apt-get install libxml2-dev
sudo apt-get install libmysqlclient15-dev
不安装也可以,之后./configure失败的话,根据出错信息,再慢慢搜索安装依赖包也可以,重要的是记下关键步骤,因为每个人的系统装没装啥都不一定。
$cd php-5.2.10
$./configure --prefix=/usr/local/php --enable-fastcgi --enable-fpm --with-mysql --with-mysqli --with-openssl
这里我们配置php安装到/usr/local/php,如果不配置默认安装到/usr/local下,这样我觉得不太好,这样make install各个文件就会被拷贝得分散开来(分散在local的各个目录下),如果我们之后想卸载干净而且无法使用make uninstall的话,还不方便。安装到/usr/local/php下,如果我们想删除php,直接删除该目录即可。
--enable-fastcgi和--enable-fpm分别设置支持fastcgi和PHP-FPM的选项;
--with-mysql和--with-mysqli相当于编译php的MySQL扩展到php内核中,这样我们可以在php中使用mysql和mysqli库的函数访问mysql;
注意:这里需要注意的一个问题是,不要设置--with-apxs2=/usr/local/apache2/bin/apxs,我们知道它是告诉PHP编译成模块方式让Apache来支持。如果设置了该选项的话,编译安装之后,Apache会无法启动,报错信息:
/usr/lib/apache2/modules/libphp5.so: undefined symbol: -fpm-event-base-free
因此这里也就意味着,我们编译PHP以PHP-FPM的方式来支持FastCGI的话,基本上就不能和Apache一起使用了,也就是说我们决定使用nginx+PHP+PHP-FPM的话,这里的PHP就没法和Apache一起使用了。
如果非还想要使用,那可以另外编译安装一个PHP,编译的时候在./configure的时候设置--with-apxs2=/usr/local/apache2/bin/apxs,而且不要打PHP-FPM的补丁。
另外,如果该步骤出现错误,通常是缺乏依赖包,请按照错误信息安装依赖包即可。
d. 编译:
$make all
注意这里尽量使用make all,而不要仅仅是make
e. 安装:
$make install
f. 拷贝php.ini文件:
$sudo cp php.ini-dist /usr/local/php/lib/php.ini
将php.ini文件拷贝到如上位置;
如果安装都成功的话,我们的以PHP-FPM方式支持FastCGI的PHP就被安装到了/usr/local/php目录下了。
3) 配置PHP和PHP-FPM:
首先可用到/usr/local/php/bin目录下执行一下php -v,看PHP是否work。
a. 配置php.ini:
位于/usr/local/php/lib下
这里一般没有严格需要配置什么,可以按照自己要求进行配置。
b. 配置PHP-FPM这个PHP解析器:
我们上面说过PHP-FPM解析器是C/S结构,它的配置文件位于/usr/local/php/etc/php-fpm.conf。
$cd /usr/local/php/etc
$sudo vi php-fpm.conf
该文件是一个xml文件,只需要修改:
Unix user of processes
<value name="user">www-data</value>
Unix group of processes
<value name="group">www-data</value>
注意去掉两边的注释<!--和-->,否则之后php-fpm启动不了;
c. 配置完之后,就可以启动PHP-FPM:
$/usr/local/php/sbin/php-fpm start
我们上面介绍了FastCGI模式区别于CGI模式,它需要一个daemon进程一直运行在后台对php请求做出解析,这里的PHP-FPM就是这个daemon进程,在配置文件php-fpm.conf中可以设置它侦听的IP和端口,默认为127.0.0.1:9000。也就是它侦听9000端口的数据请求,然后会将其进行解析然后返回给请求端。
这个和我们之前介绍的FastCGI的思想相吻合。HTTPServer服务器和FastCGI模式的PHP解析器相分离(这里就是PHP-FPM),HTTPServer遇到PHP请求的时候,就会传递给PHP-FPM,后者解析并返回。实现HTTPServer和PHP解析器完全分离,缓解了Server的负担,Server有更多资源来处理并发请求。其实这也是nginx优于apache的一个原因。
d. 检查php-fpm是否运行正常:
$ps ax|grep fpm
4)安装和配置nginx:
之前文章我们介绍了nginx的安装和使用nginx作为reverser server的进行负载均衡配置了,感兴趣的可以参看。
a. nginx的安装很简单:
从官网下载安装包:nginx-0.7.61.tar.gz
$tar xzvf nginx-0.7.61.tar.gz
$cd nginx-0.7.61
$./configure
默认安装路径为/usr/local/nginx,如果不放心自己可以使用--prefix=/usr/local/nginx配置一下
$make
$sudo make install
b. 思想:
我们之前的文章介绍了nginx的使用非常灵活,有人比喻其为server领域的瑞士军刀,其实确实是:性能好,而且使用方法多。
各种使用方法都是通过配置文件来实现,因此掌握nginx的使用,除了掌握各种架构的思想之外,还要掌握如何对nginx.conf进行相应的配置。
我们这里着重对nginx.conf配置,实现通过php-fpm的fastcgi对php的处理。其实nginx本身并不会对PHP进行解析,这个要区别于Apache (Apache通过内置模块实现了对PHP的解析),nginx其实是将对php页面的请求交给了后台在127.0.0.1:9000 侦听的php-fpm,后者具有解析php的功能。
因此如果把php-fpm看做一个app server的话,其实nginx这里的作用还是一个反向代理服务器。和我们之前介绍的使用location配置将php请求proxypass给后台侦听的Apache服务器,在思想上几乎一样。
c. 配置位于/usr/local/nginx/conf目录下的nginx.conf和fastcgi.params
>nginx.conf配置:
$cd /usr/local/nginx/conf
$sudo vi nginx.conf
从上往下对默认的配置文件进行修改:
1. user www-data; 这里需要和php-fpm中定义的用户一致;
2. worker_processes 2; 可以设置更多,这个选项和之后的worker_connections 1024;
一起来定义每个进程并发相应的最大连接数,因此这里可以达到2*1024的并发请求;
3. 在server {
listen 8080;
如果自己已经安装了Apache并且占用了80端口,这里修改为别的8080,负责启动不了;
4. 如上面所述,我们其实设置nginx将PHP请求转发给后台的php-fpm server即可,后者有解析php功能。
其实还是充当反向代理的作用;
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
root html;
fastcgi_pass 127.0.0.1:9000 ;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME html/$fastcgi_script_name;
include fastcgi_params;
}
注意fastcgi_param SCRIPT_FILENAME html/$fastcgi_script_name;
之后需要设置为放置php脚本的位置,这里我们举例在/usr/local/nginx/html目录下创建一个phpinfo.php文件
包含代码<?php phpinfo(); ?>
$sudo vi fastcgi.params
配置fastcgi参数文件,具体可以参考http://wiki.nginx.org/NginxFcgiExample
基本上可以使用默认的该文件,不需要修改。
5) 运行nginx:
$sudo /usr/local/nginx/sbin/nginx
然后在浏览器中查看http://localhost
> 默认会显示/usr/local/nginx/html目录下的index.html页面: Welcome to Nginx!
>然后查看http://localhost/phpinfo.php ,相当于访问html目录下的phpinfo.php页面,
如果正常,会显示phpinfo的页面。其中可以看到Server API一项包含:CGI/FastCGI,表示FastCGI方式运行。
如果以上步骤出现错误,通常都是因为nginx.conf配置不正确,可以google寻找解决方法,一般都可以找得到(英文)。然后重新修改nginx.conf文件。
之后需要重启nginx,可以执行:
$sudo kill `cat /usr/local/nginx/logs/nginx.pid` 表示关闭nginx
$sudo /usr/local/nginx/sbin/nginx 再次启动nginx
6)设置开机自启动:
在Ubuntu下,如果希望添加到/etc/init.d实现开机重启的话,可以Google寻找nginx和php-fpm的init script(php-fpm本身就是init script不需要寻找了),然后拷贝到/etc/init.d目录下。
简单的方法,设置rc.local:
$sudo vi /etc/rc.local
在exit 0之前添加:
/usr/local/php/sbin/php-fpm start
/usr/local/nginx/sbin/nginx
这样开机自动启动nginx和php-fpm。
7) 使用nginx和php-fpm实现server cluster:
和nginx对多台app server代理实现负载均衡类似,我们可以实现nginx对多台php-fpm实现负载均衡:
T o configure Nginx to load balance multiple FastCgi servers use this type of configuration:
upstream fastcgiServers {
server 127.0.0.1:9000 ;
server 127.0.0.1:9001 ;
server 198.192.0.1:9000 ;
server 198.192.0.2:9000 ;
server 198.192.0.3:9000 ;
}
location ~ \.php$ {
fastcgi_pass fastcgiServers;
fastcgi_index stream.app;
fastcgi_param SCRIPT_FILENAME /var/www/htdocs$fastcgi_script_name;
include /etc/nginx/fastcgi.conf;
}
4. 总结:
三种常用模式:
Apache+mod_php5;
lightppd+spawn-fcgi;
nginx+PHP-FPM
我们可以使用到生产环境中的:
0) 如果不是server cluster的话:
可以使用以上任一种,不过有各种测试表明nginx+PHP-FPM性能优越,但是Apache+mod_php5很经典模块多,比如对.htaccess等的支持。
如果构建server cluster的话:
1) nginx作为反向代理服务器,后台多台Apache+mod_php5。
nginx处理静态文件,及对php并发请求对后台多台app server的负载均衡;
2) nginx作为反向代理器,后台多台PHP-FPM
nginx处理静态文件及将php并发请求发送到后台php-fpm来解析;
另外:关于如何更好使用nginx这个轻量级高性能的瑞士军刀,主要是如何配置nginx.conf,更多参看:
http://wiki.nginx.org/Main
另外,关于PHP支持的各种缓存等这里没有安装,感兴趣可以另行安装。
更多参考资料:
http://www.php.net/manual/en/install.unix.apache2.php
http://www.softwareprojects.com/resources/programming/t-installing-nginx-web-server-w-php-and-ssl-1474.html
http://php-fpm.org/Main_Page
http://www.softwareprojects.com/resources/programming/t-how-to-install-php-fpm-spawn-fcgi-replacement-1602.html
http://wiki.nginx.org/NginxFcgiExample
有可能以后会将PHP-FPM直接添加到PHP内核中一起进行发布
Will there be a PHP-FPM is included in the official PHP?
http://php-fpm.org/FAQ
http://bookmarks.honewatson.com/2008/04/24/multiple-fastcgi-php-servers-nginx-load-balancing/
http://www.wikivs.com/wiki/Lighttpd_vs_nginx
http://en.wikipedia.org/wiki/Reverse_proxy
http://sameerparwani.com/posts/nginx-as-a-front-end-to-apache/
http://blog.kovyrin.net/2006/04/17/typical-nginx-configurations/
http://www.yawn.it/2008/04/30/nginx-php-php-fpm-on-debian-etch-40/
http://howtoforge.org/installing-nginx-with-php5-and-mysql-support-on-ubuntu-8.10