nginx-php調優

1、一些常見的狀態碼爲:php

  • 200 – 服務器成功返回網頁html

  • 404(未找到) 服務器找不到請求的網頁。例如,對於服務器上不存在的網頁常常會返回此代碼。
  • 500(服務器內部錯誤) 服務器遇到錯誤,沒法完成請求。並且通常程序上是ASP錯誤爲多的,多是你的用戶權限的問題致使,或者是數據庫鏈接出現了錯誤
  • 502(錯誤網關) 服務器做爲網關或代理,從上游服務器收到無效響應。
  • 504(網關超時) 服務器做爲網關或代理,可是沒有及時從上游服務器收到請求。單個php-fpm進程阻塞超過nginx的時間閾值返回504 gateway timeout

2、分析
(1)502 Bad Gateway緣由分析
將請求提交給網關如php-fpm執行,可是因爲某些緣由沒有執行完畢致使php-fpm進程終止執行。說到此,這個問題就很明瞭了,與網關服務如php-fpm的配置有關了。
php-fpm.conf配置文件中有兩個參數就須要你考慮到,分別是max_children和request_terminate_timeout。
max_children最大子進程數,在高併發請求下,達到php-fpm最大響應數,後續的請求就會出現502錯誤的。能夠經過netstat命令來查看當前鏈接數。
設置max_children也須要根據服務器的性能進行設定,通常來講一臺服務器正常狀況下每個php-cgi所耗費的內存在20M左右。因此在峯值的時候,全部php-cgi所耗內存爲20 max_children數。
request_terminate_timeout設置單個請求的超時終止時間。還應該注意到php.ini中的max_execution_time參數。當請求終止時,也會出現502錯誤的。
當積累了大量的php請求,你重啓php-fpm釋放資源,但一兩分鐘不到,502又再次呈現,這是什麼緣由致使的呢? 這時還應該考慮到數據庫,查看下數據庫進程是否有大量的locked進程,數據庫死鎖致使超時,前端終止了繼續請求,可是SQL語句還在等待釋放鎖,這時就要重啓數據庫服務了或kill掉死鎖SQL進程了。
I、Nginx錯誤訪問日誌:
2013/09/19 01:09:00 [error] 27600#0:
78887 recv() failed (104: Connection reset by peer) while reading response header from upstream
client: 192.168.1.101, server: test.com, request: "POST /index.php HTTP/1.1", upstream: "fastcgi://unix:/dev/shm/php-fcgi.sock:",
host: "test.com", referrer: "http://test.com/index.php"前端

II、PHP-FPM報錯日誌:
WARNING: child 25708 exited on signal 15 (SIGTERM) after 21008.883410 seconds from startnginx

(2) 504 Gateway Time-out緣由分析
504錯誤通常是與nginx.conf配置有關了。主要與如下幾個參數有關:fastcgi_connect_timeout、fastcgi_send_timeout、fastcgi_read_timeout、fastcgi_buffer_size、fastcgi_buffers、fastcgi_busy_buffers_size、fastcgi_temp_file_write_size、fastcgi_intercept_errors。特別是前三個超時時間。若是fastcgi緩衝區過小會致使fastcgi進程被掛起從而演變爲504錯誤。web

3、nginx與php進程間通訊
(1)FastCGI原理
FastCGI是一個運用於Http Server和動態腳本語言間通訊的接口,多數流行的Http Server都支持FastCGI,包括Apache、Nginx和lighttpd等。同時,FastCGI也被許多腳本語言支持,其中就有PHP。
FastCGI接口方式採用C/S結構,能夠將HttP服務器和腳本解析服務器分開,同時在腳本解析服務器上啓動一個或者多個腳本解析守護進程。當HttP服務器每次遇到動態程序時,能夠將其直接交付給FastCGI進程來執行,而後將獲得的結果返回給客戶端。這種方式可讓HttP服務器專注地處理靜態請求或者將動態腳本服務器的結果返回給客戶端,這在很大程度上提升了整個應用系統的性能。
(2)Nginx+php-fpm實現原理
Nginx自己不會對PHP進行解析,終端對PHP頁面的請求將會被Nginx交給FastCGI進程監聽的IP地址及端口,由php-fpm做爲動態解析服務器處理,最後將處理結果再返回給nginx。其實,Nginx就是一個反向代理服務器。Nginx經過反向代理功能將動態請求轉向後端php-fpm,從而實現對PHP的解析支持,這就是Nginx實現PHP動態解析的原理。sql

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 簡單配置

location ~ .php$ {
root /home/admin/web/nginx/html/;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /home/admin/web/nginx/html/$fastcgi_script_name;
include fastcgi_params;
}數據庫

當nginx接收到一個http請求時,經過配置文件找到對應的server。而後匹配server中的全部location,找到最匹配的。而在location中的命令會啓動不一樣的模塊去完成工做,好比rewrite模塊、index模塊。所以在nginx中模塊能夠看做真正的勞動工做者。nginx的模塊是被編譯到nginx中的,屬於靜態方式。啓動nginx時,模塊被自動加載。不像apache,把模塊單獨編譯成so文件,在配置文件中指定是否加載。因此,單比模塊加載方面,nginx也比apache速度上有提高。
location ~ .php$ {
root /webpath;
fastcgi_pass 127.0.0.1:9000;

...
}apache

這個location指令把以php爲文件後綴的請求,交給127.0.0.1:9000處理。我想你看到這個應該猜到了,這是一個C/S架構東西。 而這裏的IP地址和端口(127.0.0.1:9000)就是fastcgi進程監聽的IP地址和端口。fastcgi的配置IP和端口從何而來呢?在php-fpm.conf中能夠看到。
listen = 127.0.0.1:9000 #這個表示php的fastcgi進程監聽的ip地址以及端口
pm.start_servers = 2vim

php-fpm做爲fastcgi的進程管理器,能夠有效控制內存和進程,而且平滑重載php配置。php5.3之後,php-fpm被集成到php的core中,默認安裝,無須配置。後端

fastcgi進程管理器php-fpm自身初始化,啓動主進程php-fpm和啓動start_servers個fastcgi子進程。主進程php-fpm主要是管理fastcgi子進程,監聽9000端口,fastcgi子進程等待請求。當客戶端請求到達nginx時,nginx經過location指令,將全部以php爲後綴的文件都交給 127.0.0.1:9000 來處理。php-fpm選擇並鏈接到一個fastcgi子進程,並將環境變量和標準輸入發送到fastcgi子進程。fastcgi子進程完成處理後將標準輸出和錯誤信息返回。當fastcgi子進程關閉鏈接時,請求便告處理完成,等待下次處理。
(3)fastcgi與cgi
I、cgi在2000年或更早的時候用得比較多, 之前web服務器通常只處理靜態的請求,若是碰到一個動態請求怎麼辦呢?web服務器會根據此次請求的內容,而後會fork一個新進程來運行外部c程序(或perl腳本...), 這個進程會把處理完的數據返回給web服務器,最後web服務器把內容發送給用戶,剛纔fork的進程也隨之退出。 若是下次用戶還請求改動態腳本,那麼web服務器又再次fork一個新進程,周而復始的進行。

後來出現了一種更高級的方式是, web服務器能夠內置perl解釋器或php解釋器。 也就是說這些解釋器作成模塊的方式,web服務器會在啓動的時候就啓動這些解釋器。 當有新的動態請求進來時,web服務器就是本身解析這些perl或php腳本,免得從新fork一個進程,效率提升了。

II、fastcgi的方式是,web服務器收到一個請求時,他不會從新fork一個進程(由於這個進程在web服務器啓動時就開啓了,並且不會退出),web服務器直接把內容傳遞給這個進程(進程間通訊,但fastcgi使用了別的方式,tcp方式通訊),這個進程收到請求後進行處理,把結果返回給web服務器,最後本身接着等待下一個請求的到來,而不是退出。

III、舉個例子: 服務端如今有個10萬個字單詞, 客戶每次會發來一個字符串,問以這個字符串爲前綴的單詞有多少個。 那麼能夠寫一個程序,這個程序會建一棵trie樹,而後每次用戶請求過來時能夠直接到這個trie去查找。 可是若是以cgi的方式的話,此次請求結束後這課trie也就沒了,等下次再啓動該進程時,又要新建一棵trie樹,這樣的效率就過低下了。 而用fastcgi的方式的話,這課trie樹在進程啓動時創建,之後就能夠直接在trie樹上查詢指定的前綴了。

4、用戶對動態php網頁的訪問過程
(1)用戶瀏覽器發起對網頁的訪問:http://www.66rpg.com/index.php
(2)用戶和nginx服務器進行三次握手,進行tcp鏈接(忽略包括nginx訪問控制策略、防火牆等)
(3)第一步:用戶將http請求發送給nginx服務器
(4)第二步:nginx會根據用戶訪問的URL和後綴對請求進行判斷,例如用戶訪問的index.php則會根據配置文件中的location進行匹配。nginx根據用戶請求的資源匹配到具體的location後會執行location對應的動做。
fastcgi_params #表示nginx會調用fastcgi這個接口。
fastcgi_intercept_errors on; #表示開啓fastcgi的中斷和錯誤信息記錄。
fastcgi_pass 127.0.0.1::9000; #表示nginx經過fastcgi_pass將用戶請求的資源發給127.0.0.1:9000進行解析,這裏的nginx和php在同一臺服務器上,因此127.0.0.1:9000表示本地的php腳本解析服務器。
(5)第三步:經過第二步能夠看出,用戶請求的是動態內容,nginx會將請求交給fastcgi客戶端,經過fastcgi_pass將用戶的請求發送給php-fpm。若是用戶訪問的是靜態資源,nginx直接將用戶請求的靜態資源返回給用戶
(6)第四步:fastcgi_pass將動態資源交給php-fpm以後,php-fpm會將資源轉給php腳本解析服務器的wrapper
(7)第五步:wrapper收到php-fpm轉過了的請求後,wrapper會生成一個新的線程調用php動態程序解析服務器。若是用戶請求的是須要讀取Mysql數據庫等,會出發讀庫操做;若是用戶請求的是圖片,附件等,php會觸發一次查詢後端存儲服務器的操做。
(8)第六步:php將查詢到的結果返回給nginx
(9)第七步:nginx構造一個響應報文將結果返回給用戶。

5、配置說明,調優
壓測:
合理的併發,且保證qps在必定範圍沒有明顯降低。
I、# vim /usr/local/php/etc/php-fpm.conf
pm.max_children = 800
pm.start_servers = 400
pm.min_spare_servers = 200
pm.max_spare_servers = 500
pm.max_requests = 2048

(1)php-fpm有一個參數 max_requests,該參數指明瞭,每一個children最多處理多少個請求後便會被關閉,默認的設置是500。由於php是把請求輪詢給每一個children,在大流量下,每一個childre到達max_requests所用的時間都差很少,這樣就形成全部的children基本上在同一時間被關閉,這樣會致使此時nginx發給php的請求沒法獲得相應,會出現短期的502.解決方法:php-fpm有一個參數 max_requests,該參數指明瞭,每一個children最多處理多少個請求後便會被關閉,默認的設置是500。

(2)php-fpm 進程池優化方法
php-fpm進程池開啓進程有兩種方式,一種是static,直接開啓指定數量的php-fpm進程,再也不增長或者減小;
另外一種則是dynamic,開始時開啓必定數量的php-fpm進程,當請求量變大時,動態的增長php-fpm進程數到上限,當空閒時自動釋放空閒的進程數到一個下限。
這兩種不一樣的執行方式,能夠根據服務器的實際需求來進行調整。
要用到的一些參數,分別是pm、pm.max_children、pm.start_servers、pm.min_spare_servers和pm.max_spare_servers。
pm表示使用那種方式,有兩個值能夠選擇,就是static(靜態)或者dynamic(動態)。
下面4個參數的意思分別爲:

pm.max_children:靜態方式下開啓的php-fpm進程數量,在動態方式下他限定php-fpm的最大進程數(這裏要注意pm.max_spare_servers的值只能小於等於pm.max_children)
pm.start_servers:動態方式下的起始php-fpm進程數量。
pm.min_spare_servers:動態方式空閒狀態下的最小php-fpm進程數量。
pm.max_spare_servers:動態方式空閒狀態下的最大php-fpm進程數量。

若是dm設置爲static,那麼其實只有pm.max_children這個參數生效。系統會開啓參數設置數量的php-fpm進程。
若是dm設置爲dynamic,4個參數都生效。系統會在php-fpm運行開始時啓動pm.start_servers個php-fpm進程,而後根據系統的需求動態在pm.min_spare_servers和pm.max_spare_servers之間調整php-fpm進程數。

PS.pm.min_spare_servers、pm.max_spare_servers這2個參數一開始我覺得是指空閒進程,可是後來服務器給我報了一個錯誤:pm.start_servers(70) must not be less than pm.min_spare_servers(15) and not greater than pm.max_spare_servers(60)要求pm.start_servers的值在pm.min_spare_servers和pm.max_spare_servers之間,通過測試,得出上述結論。

相關文章
相關標籤/搜索