以最典型的apache httpd和php为例,对于httpd来说,web server和php-cgi有3种交互模式。
cgi模式
:httpd接收到一个动态请求就fork一个cgi进程,cgi进程返回结果给httpd进程后自我销毁。动态模块模式
:将php-cgi的模块(例如php5_module)编译进httpd。在httpd启动时会加载模块,加载时也将对应的模块激活,php-cgi也就启动了。(注:纠正一个小小错误,很多人以为动态编译的模块是可以在需要的时候随时加载调用,不需要的时候它们就停止了,实际上不是这样的。和静态编译的模块一样,动态加载的模块在被加载时就被加入到激活链表中,无论是否使用它,它都已经运行在apache httpd的内部。可参考LoadModule指令的官方手册)php-fpm模式
:使用php-fpm管理php-cgi,此时httpd不再控制php-cgi进程的启动。可以将php-fpm独立运行在非web服务器上,实现所谓的动静分离。
实际上,借助模块mod_fastcgi还可以实现fastcgi模式。同cgi一样,管理模式的先天缺陷决定了这并不是一种好方法。
3.1 CGI模式
使用CGI模式时,当动态请求到达,httpd临时启动一个cgi解释器,并通过cgi协议转发要运行的内容。当cgi脚本运行结束后,将结果返回给httpd,然后cgi解释器进程自我销毁。当多个动态请求到达时,将先后启动多个cgi解释器。因此,这种方法效率极低。
在注释掉php5_module的LoadModule相关行后,使用action指令指定要使用cgi运行的类型。但注意,action指令是mod_action提供的,所以必须已经加载该模块。
例如:指定MIME类型为image/gif的请求使用images.cgi运行。显然,images.cgi脚本你必须先写好。
Action image/gif /cgi-bin/images.cgi
还可以通过添加handler来复合文件类型,再使用某个cgi脚本去运行这个handler中的任意类型。
AddHandler my-file-type .xyz
Action my-file-type "/cgi-bin/program.cgi"
对于php来说,则可以使用安装php时bin目录下提供的php-cgi程序作为cgi程序。
[root@xuexi php]# ls /usr/local/php/bin/
pear peardev pecl phar phar.phar php php-cgi php-config phpize
# 复制到apache默认的cgi-bin目录下,方便管理
[root@xuexi php]# cp /usr/local/php/bin/php-cgi /usr/local/apache/cgi-bin/
# 在httpd.conf中添加以下行
Action application/x-httpd-php /usr/local/php/bin/cgi-bin/php-cgi
3.2 模块方式
在编译php时,将php5_module模块编译到apache中,例如在编译php时在./configure配置中加上"--with-apxs2=/usr/local/apache/bin/apxs"。
这种交互模式下,httpd在启动时加载并激活php_module。也就是说,php-cgi常驻在httpd进程内部。当动态请求到达时,httpd不用再生成cgi解释器,而是直接将动态请求转发给它内部php-cgi。
配置实用这种交互模式非常简单,只需使用LoadModule加载php_module,再添加对应的MIME处理器即可。
LoadModule php5_module modules/libphp5.so
# 在mime模块中添加对应的类型
<IfModule mime_module>
AddType application/x-httpd-php .php
AddType applicaiton/x-httpd-php-source .phps
</IfModule>
3.3 php-fpm方式
前面说了,php-fpm是php-cgi的进程管理器。这种交互方式实际上是让php-cgi以独立于httpd的方式存在,目前基本使用php-fpm的方式管理php-cgi进程。也就是说,这种模式下,php-cgi和httpd已经分离了,它们的分离意味着请求的动静分离变为可能:httpd和php-fpm分别运行在不同服务器上。动静分离后,压力也分散到各自的服务器上。
要让php-fpm以这种方式运行,需要在编译的./configure配置选项中添加"--enable-fpm"选项。当然,还得启动php-fpm服务。例如:
service php-fpm start
这样php-cgi进程就开放着端口(默认9000)等待httpd转发动态请求。要让httpd能够转发请求到php-cgi上,需要在httpd.conf中关闭正向代理,并设置fastcgi协议代理参数。例如,转发到192.168.100.54主机上的php-fpm。
# 加载代理模块
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
# 添加MIME类型
AddType application/x-httpd-php .php
AddType application/x-httpd-php-source .phps
# 在需要转发的虚拟主机中配置转发代理
ProxyRequests off
ProxyPassMatch ^/(.*\.php)$ fcgi://192.168.100.54:9000/usr/local/apache/htdocs/$1