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