1. 程式人生 > >mod_php和mod_fastcgi和php-fpm的介紹,對比,和性能數據

mod_php和mod_fastcgi和php-fpm的介紹,對比,和性能數據

編譯安裝php bin 技術分享 原則 sha 什麽 err mode php

1、php中fastcgi和php-fpm是什麽東西

最近在研究和學習php的性能方面的知識,看到了factcgi以及php-fpm,發現我對他們是少之又少的理解,可以說幾乎是一無所知,想想還是蠻可怕的。決定仔細的學習一下關於這方面的知識。

參考和學習了以下文章:
1. mod_php和mod_fastcgi和php-fpm的介紹,對比,和性能數據
2. 實戰Nginx_取代

為了如何一步步的引出fastcgi和php-fpm,我先一點一點的說說關於php的周邊。哎。突然覺得人活著好累!

先說說web服務器

php是為web而生的一門後端語言,我們php狗當然是最清楚的啦。所以php僅僅是一門後端語言,那麽它就必須借助於web服務器,才能提供web功能。當然其他的後端語言如果做web應用,也必須借助於web服務器。好,由php引出了web服務器,不錯!

那麽常見的web服務器有哪些呢?php狗用的最多的就是Apache了,還有其他的:

  • apache
  • nginx
  • IIS
  • lighttpd
  • tomcat

基本上就是上面幾種,與php相關聯起來用的最多的就是Apache和Nginx了。

我們先舉例用apache當作web服務器,來說明一次完整的php訪問的情況:
技術分享圖片
圖片中就很好的解釋了php與Apache結合mysql數據庫的一次完成的web訪問流程圖

mod_php模式

上面講清楚了php必須借助於web服務器才能提供web的功能服務,現在看下他倆是怎麽成為基友的。

我們用到的最多的就是Apache了。那麽回憶一下,如何使apache是怎麽能夠識別php代碼的?是不是apache的配置文件httpd.conf中加上或者修改這樣幾句:

  1. //加入以下2句
  2. LoadModule php5_module D:/php/php5apache2_2.dll
  3. AddType application/x-httpd-php .php
  4. //將下面的
  5. <IfModule dir_module>
  6. DirectoryIndex index.html
  7. </IfModule>
  8. //將其修改為:
  9. <IfModule dir_module>
  10. DirectoryIndex index.html index.htm index.php index.phtml
  11. </IfModule>

上面的windows下安裝php和apache環境後的手動配置,在linux下源碼安裝大致是這樣配置的:

  1. ./configure --with-mysql=/usr/local --with-apache=/usr/local/apache --enable-track-vars

所以,這種方式,他們的共同本質都是用LoadModule來加載php5_module,就是把php作為apache的一個子模塊來運行。當通過web訪問php文件時,apache就會調用php5_module來解析php代碼。

那麽php5_module是怎麽來將數據傳給php解析器來解析php代碼的呢?

答案是通過sapi

我們再來看一張圖,詳細的說說apache 與 php 與 sapi的關系:

技術分享圖片

從上面圖中,我們看出了sapi就是這樣的一個中間過程,SAPI提供了一個和外部通信的接口,有點類似於socket,使得PHP可以和其他應用進行交互數據(apache,nginx,cli等)。php默認提供了很多種SAPI,常見的給apache和nginx的php5_module,CGI,給IIS的ISAPI,還有Shell的CLI。

所以,以上的apache調用php執行的過程如下:

apache -> httpd -> php5_module -> sapi -> php

好了。apache與php通過php5_module的方式就搞清楚了吧!

我們把這種運行方式叫做mod_php模式

mod_fastcgi模式

上面我們仔細說了php與apache通過php5_module,php5_module通過sapi的方式訪問php,來達到php web的整個流程。

上面也說到了sapi,sapi是php提供的統一接口,它提供給了php5_module和cgi等方式供web服務器來鏈接和解析php代碼。上面講到的php5_module加載模式,我們稱之為mod_php模式。

那麽!當當當當!馬上就要說出fastcgi模式了。哈哈哈哈哈,太不容了。

那麽php的sapi的另一種方式就是提供cgi模式,由於cgi比較老所以就出現了fastcgi來取代它。

所以,哎。沒辦法,又要說什麽是CGI了?

CGI(Common Gateway Interface)。CGI是外部應用程序(CGI程序)與Web服務器之間的接口標準,是在CGI程序和Web服務器之間傳遞信息的規程。CGI規範允許Web服務器執行外部程序,並將它們的輸出發送給Web瀏覽器,CGI將Web的一組簡單的靜態超媒體文檔變成一個完整的新的交互式媒體。

看官方的解釋就蛋疼,簡單的說,就是:cgi就是專門用來和web 服務器打交道的。web服務器收到用戶請求,就會把請求提交給cgi程序(php的fastcgi),cgi程序根據請求提交的參數作應處理(解析php),然後輸出標準的html語句返回給web服服務器,再返回給客戶端,這就是普通cgi的工作原理。

cgi的好處就是完全獨立於任何服務器,僅僅是做為中間分子。提供接口給apache和php。他們通過cgi搭線來完成搞基動作。這樣做的好處了盡量減少2個的關聯,使他們2變得更獨立。

但是cgi有個蛋疼的地方,就是每一次web請求都會有啟動和退出過程,也就是最為人詬病的fork-and-execute模式,這樣一在大規模並發下,就死翹翹了。

所以。這個時候fastcgi運用而生了。它事先就早早的啟動好了,而且可以啟動多個cgi模塊,在那裏一直運行著等著,等著web發過來的請求,然後再給php解析運算完成生成html給web後,也不會退出,而且繼續等著下一個web請求。而且這些cgi的模塊啟動是可控的,可監測的。這種技術還允許把web server和php運行在不同的主機上,以大規模擴展和改進安全性而不損失生產效率。

所以現在一般操作系統都是fastcgi模式。cig模式也慢慢退出了歷史舞臺!我們文章中說cgi一般也就指fastcgi。

所以把這種運行方式叫做mod_fastcgi模式

我會在接下來的段落講如何使用fastcgi模式來連接php和apache(或者nginx)

總結一下:php 與 apache 或者 ngix 結合, 會用sapi 提供2種連接方法:mod_php和mod_fastcgimod_php 模式會將php模塊安裝到apache下面來運行,2者結合度較大。mod_fastcgi模式則是作為一個中間過程,apache介紹用戶請求後,就發送給fastcgi, 再連接php來完成訪問。

圖形表示一下這2種模式

mod_php 模式

mod_php 模式是將php模塊安裝到apache中,所以每一次apache結束的請求呢,都會產生一條進程,這個進程就完整的包括php的各種運算計算等操作。

技術分享圖片
從圖中我們很清晰的可以看到,apache每接收一個請求,都會產生一個進程來連接php通過sapi來完成請求,可想而知,如果一旦用戶過多,並發數過多,服務器就會承受不住了。

而且,把mod_php編進apache時,出問題時很難定位是php的問題還是apache的問題。

mod_fastcgi 模式

mod_fastcgi模式則剛剛相反,fastcgi是一個獨立與apache和php的獨立個體,它隨著apache一起啟動,生成多個cig模塊,等著apache的請求:

技術分享圖片

圖中fastcgi早早的啟動好了,靜靜的在哪裏等著,已有apache發來的httpd請求就立馬接收過來,通過調用sapi給php,完成運算。而且不會退出。這樣就能應對大規模的並發請求,因為web server的要做的事情少了,所以就更快的去處理下一個請求,這樣並發大大的。

由於apache 與 php 獨立了。出問題,很好定位到底是哪裏出問題了。這點也是這種模式受歡迎的原因之一。

php-fpm

我了個大操,終於要說到php-fpm了。^....^

先開門見山說php-fpm是幹嘛好的了。它就是專門來輔助mode_fastcgi模式的。

嗯。很好,先知道它是幹嘛的後,我們再回到mode_fastcgi模式。通過前面的瞎雞巴一大堆的說明,我已經搞清楚了這種模式是怎麽樣子的一種狀態了。

fastcgi 是一個與平臺無關,與語言無關,任何語言只要按照它的接口來實現,就能實現自己語言的fastcgi能力和web server 通訊。

PHP-CGI就是PHP實現的自帶的FastCGI管理器。

雖然是php官方出品,自帶的,但是這丫的卻一點也不給力,性能太差,而且也很麻煩不人性化,主要體現在:

  1. php-cgi變更php.ini配置後需重啟php-cgi才能讓新的php-ini生效,不可以平滑重啟。
  2. 直接殺死php-cgi進程,php就不能運行了。

上面2個問題,一直讓很多人病垢了很久,所以很多人一直還是在用mode_php方式。

直到 2004年(確定是這麽早嗎?)一個叫 Andrei Nigmatulin的屌絲發明了PHP-FPM ,這神器的出現就徹底打破了這種局面,這是一個PHP專用的fastcgi管理器,它很爽的克服了上面2個問題,而且,還表現在其他方面更表現強勁. 請戳官網

我擦,這一篇貌似又瞎比比的說超時了啊。好吧。那windows和linux下安裝配置php-fpm就下一節來說吧。反正我已經已經把php-fpm和fastcgi給講清楚了。

=====================================================================================================

一些重要的設置

php-fpm進程分配

在之前的文章中就說過了。在fasgcgi模式下,php會啟動多個php-fpm進程,來接收nginx發來的請求,那是不是進程越多,速度就越快呢?這可不一定!得根據我們的機器配置和業務量來決定。

我們先來看下,設定進程的配置在哪裏?

pm = static | dynamic | ondemand

pm可以設置成這樣3種,我們用的最多的就上前面2種。

pm = static 模式

pm = static 表示我們創建的php-fpm子進程數量是固定的,那麽就只有pm.max_children = 50這個參數生效。你啟動php-fpm的時候就會一起全部啟動51(1個主+50個子)個進程,頗為壯觀。

pm = dynamic 模式

pm = dynamic模式,表示啟動進程是動態分配的,隨著請求量動態變化的。他由 pm.max_childrenpm.start_serverspm.min_spare_serverspm.max_spare_servers 這幾個參數共同決定。

上面已經講過,這裏再重申一下吧:

pm.max_children = 50 是最大可創建的子進程的數量。必須設置。這裏表示最多只能50個子進程。

pm.start_servers = 20 隨著php-fpm一起啟動時創建的子進程數目。默認值:min_spare_servers + (max_spare_servers - min_spare_servers) / 2。這裏表示,一起啟動會有20個子進程。

pm.min_spare_servers = 10
設置服務器空閑時最小php-fpm進程數量。必須設置。如果空閑的時候,會檢查如果少於10個,就會啟動幾個來補上。

pm.max_spare_servers = 30
設置服務器空閑時最大php-fpm進程數量。必須設置。如果空閑時,會檢查進程數,多於30個了,就會關閉幾個,達到30個的狀態。

到底選擇static還數dynamic?

很多人恐懼癥來襲,不知道選什麽好?

一般原則是:動態適合小內存機器,靈活分配進程,省內存。靜態適用於大內存機器,動態創建回收進程對服務器資源也是一種消耗。

如果你的內存很大,有8-20G,按照一個php-fpm進程20M算,100個就2G內存了,那就可以開啟static模式。如果你的內存很小,比如才256M,那就要小心設置了,因為你的機器裏面的其他的進程也算需要占用內存的,所以設置成dynamic是最好的,比如:pm.max_chindren = 8, 占用內存160M左右,而且可以隨時變化,對於一半訪問量的網站足夠了。

慢日誌查詢

我們有時候會經常飽受500,502問題困擾。當nginx收到如上錯誤碼時,可以確定後端php-fpm解析php出了某種問題,比如,執行錯誤,執行超時。

這個時候,我們是可以開啟慢日誌功能的。

  1. slowlog = /usr/local/var/log/php-fpm.log.slow
  2. request_slowlog_timeout = 15s

當一個請求該設置的超時時間15秒後,就會將對應的PHP調用堆棧信息完整寫入到慢日誌中。

php-fpm慢日誌會記錄下進程號,腳本名稱,具體哪個文件哪行代碼的哪個函數執行時間過長:

  1. [21-Nov-2013 14:30:38] [pool www] pid 11877
  2. script_filename = /usr/local/lnmp/nginx/html/www.quancha.cn/www/fyzb.php
  3. [0xb70fb88c] file_get_contents() /usr/local/lnmp/nginx/html/www.quancha.cn/www/fyzb.php:2

通過日誌,我們就可以知道第2行的file_get_contents 函數有點問題,這樣我們就能追蹤問題了。

編譯安裝php 的時候, 執行make報錯誤

錯誤:make: *** [ext/mysqli/mysqli.lo] Error 1

[root@localhost php-5.4.9]# mkdir /usr/local/webserver/mysql/include/mysql

[root@localhost php-5.4.9]# ln -s /usr/local/webserver/mysql/include/* /usr/local/webserver/mysql/include/mysql
[root@localhost php-5.4.9]# make ZEND_EXTRA_LIBS=‘-liconv‘

拋錯:

Generating phar.phar
/usr/local/src/php-5.4.9/sapi/cli/php: error while loading shared libraries: libiconv.so.2: cannot open shared object file: No such file or directory
make: *** [ext/phar/phar.php] Error 127

解決的方法如下:

#vi /etc/ld.so.conf

在裏面加上一行
/usr/local/lib

2.然後運行/sbin/ldconfig

#/sbin/ldconfig

編譯make

#make ZEND_EXTRA_LIBS=‘-liconv‘

拋錯:

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‘.
此處可以忽略 不過解決辦法如下

#cd ext/phar/
#cp ./phar.php ./phar.phar

然後到php5.4文件夾

#make ZEND_EXTRA_LIBS=‘-liconv‘

#make test

#make install

mod_php和mod_fastcgi和php-fpm的介紹,對比,和性能數據