preface
公司所有的大多數業務都泡在LNMP平台上,所以對PHP+Nginx有點了解,那么就做個小小的總結吧。
what's FastCGi
FastCGI是一個可伸縮,高速的在HTTP server和動態腳本語言間通信的接口。FastCGI支持多種腳本語言和HTTP server。
FCGI是由CGI發展改進而來的。傳統的CGI接口方式的性能很差。每次HTTP服務器遇到動態程序時都需要重新啟動腳本解釋器來執行解析,然后將結果返回給HTTP服務器,這在處理高並發訪問時幾乎是不可用的。另外傳統的CGI接口方式安全性也很差,現在很少使用了。
FCGI接口方式采用C/S結構,可以將HTTP服務器和腳本解釋器分開,同時在腳本解釋器上啟動一個或者多個腳本解釋器守護進程。當HTTP服務器遇到動態程序時,可以將其直接交付給FCGI進程來執行,然后將得到的結果返回給瀏覽器。這種方式可以讓HTTP服務器專一的處理靜態請求或者動態腳本的結果返回給客戶端,這就很大程度上提高了響應速度。
Nginx + FCGI運行原理
Nginx 不支持對外部程序的直接調用或者解析,所有的外部程序(包括PHP)必須通過FCGI接口來調用。FCGI接口在linux是socket(這個socket是文件socket,也可以是ip socket)。為了調用CGI程序,還需要一個FCGI的wrapper(wrapper可以理解為啟動另一個程序的程序)。這個wrapper綁定在某個固定的socket上,如端口或者文件的socket,當Nginx將cgi請求發送給這個socket的時候,通過FCGI接口,wrapper接收到請求,然后派生出一個新的線程,這個線程調用解釋器或者外部程序處理腳本並讀取數據,接着,wrapper將返回的數據通過FCGi接口,沿着固定的socket傳給Nginx,最終,NGinx將返回的數據發送給客戶端,這就是Nginx+FCGi的運行流程。如圖所示:
spawn-fcgi 和 php-fpm
FCGI接口方式在腳本解析服務器上啟動一個或者多個守護進程對動態腳本進行解析,這些進程就是FastCGI進程管理器,或者稱為fastCgi引擎,spawn-fcgi 和 PHP-FPM就是支持php的兩個Fcgi進程管理器。
span-fcgi是HTTP服務器lighttpd的一部分,目前是獨立的一個項目,一般與lighttpd配合使用來支持PHP,但是lighttpd的spwan-fcgi在高並發訪問的時候,會出現內存泄漏甚至自動重啟FastCGI的問題
Nginx是個輕量級的HTTPserver,必須借助第三方的FCGI處理器才可以對PHP進行解析。
PHP-FPM是一個第三方的FCGI進程管理器,它是PHP的一個補丁來開發的,在安裝的時候也需要和PHP源碼一起編譯,也就是說PHP-FPM被編譯到PHP內核中,因此處理性能方面更加優秀,同事PHP-FPM在處理高並發方面也比spawn-fcgi引擎好很多,所以推薦NGINX+PHP-FPM組合。
FCGI的主要優點是把動態語言和HTTP server分離開來,所以Nginx 與 php、php-fpm經常被部署在不同的服務器上,以分擔前端Nginx的服務器壓力,讓nginx 專一處理靜態請求和轉發動態請求。而PHP、PHP-fpm服務器專一解析PHP動態請求。
那么就部署它們吧
php下載地址: http://php.net
php-fpm下載地址:http://php-fpm.org/downloads/
我這里下載的php是php-5.5.38
安裝之前,把依賴包都安裝好,采用yum安裝 :
yum -y install gcc gcc++ libxml2 libxml2-devel autoconf libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel zlib zlib-devel glibc-devel glib2 glib2-devel
安裝好依賴包后,安裝php
./configure --prefix=/usr /local/php --enable-fpm --enable-fastcgi(可能會提示沒有這個選項)
make && make install
編譯沒有問題后,我們開始配置和優化php-fpm,php全局配置文件是php.ini,編譯后是在/etc/php.ini這下面。
重點介紹php-fpm引擎的配置文件
php-fpm配置文件也在/etc/php-fpm.conf下面,默認情況下會把/etc/php-fpm.d/www.conf 的配置文件include進去。
我們在www.conf里面看看以下幾項:
listen = 127.0.0.1:9000 #監聽了本地9k端口
user = nginx #運行用戶
group = nginx
pm.max_children = 50 # 設置fcgi的進程數,官方建議小於2G內存開啟64個,4G可以開200個
request_terminate_timeout = 0 # 用於設置FCGI執行腳本的時間,默認是0秒,也就是五險的執行下去,可以更加情況改
rlimit_files = 1024 #設置PHP-FPM 打開文件描述符的限制,這個值要和linux內核打開文件數關聯起來,例如,要將此值設置為65535,就必須在linux命令上執行ulimit -HSN 65536
pm.max_requests = 500 設置處理多少個請求后便會關閉,默認是500,
listen.allowed_clients = 127.0.0.1 # 設置允許訪問FCGI進程解析器的IP地址,如果不在IP地址,將無法接受Nginx轉發過來的php解析請求。
了解完上訴配置后,就可以啟動FastCGI了,啟動命令如下:
[root@salt ~]# php-fpm 啟動php-fpm
如果有像這樣的報錯:
[root@salt php]# php-cgi
PHP Warning: PHP Startup: Unable to load dynamic library '/usr/lib64/php/modules/redis.so' - /usr/lib64/php/modules/redis.so: undefined symbol: igbinary_unserialize in Unknown on line 0
那么在/etc/php.ini把這行注釋掉啟動就可以了:
; extension=/usr/lib64/php/modules/redis.so
Notice
如果是php7.0版本以上的,可以使用以下命令安裝redis
[root@salt ~]# pecl install redis
pecl/redis requires PHP (version >= 7.0.0, version <= 7.1.0, excluded versions: 6.0.0), installed version is 5.5.32
No valid packages found
install failed
配置nginx來支持php
我們切換到nginx配置文件目錄下,發現有個default.conf的模版文件,我們copy一份來修改后即可用,命令如下:
[root@salt ~]# cd /etc/nginx/conf.d/
[root@salt conf.d]# ls
default.conf
[root@salt conf.d]# cp default.conf web1.conf
[root@salt conf.d]# mv default.conf default.cf # 避免默認配置影響nginx運行
[root@salt conf.d]# vim web1.conf
# 寫入以下內容:
server {
listen 80;
server_name web1.test.com;
charset utf8;
location / {
root /var/www/html;
index index.html index.htm;
}
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
location ~ \.php$ {
root html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/html/$fastcgi_script_name;;
include fastcgi_params;
}
}
參數解釋
- location 正則匹配到以php結尾的到這里解析,
- root 指明了網站目錄
- fastcgi_pass 指明了用哪里的php-fpm來解析
- fastcgi_index 指明首頁
- fastcgi_param 指明的是php動態程序的主目錄,/scripts也就是$fastcgi_script_name前面指定的路徑,我們一般在這里寫網站根目錄的路徑,比如我們的路徑是 /var/www/html。
測試php+nginx是否正常工作
在網站根目錄下面創建Index.php文件,寫入一些內容,命令如下:
/var/www/html/index.html的內容:
<h1>
<span> hello, this is test page </span>
</h1>
/var/www/html/phpinfo.php內容:
<?php phpinfo(); ?>
我們訪問http://ip/如果出現自定義頁面,那么就成功了。
訪問http://ip/phpinfo.php 出現php安裝信息,那么也算成功了。
優化Nginx和FastCgi參數
我們在nginx配置文件里面的http段內添加一下內容,比如我們現在使用的web1.conf文件,那么我就在web1.conf里面添加以下內容:
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 128k;
fastcgi_cache_valid 200 302 1h;
fastcgi_cache_valid 301 1d;
fastcgi_cache_valid any 1m;
參數解釋
-
fastcgi_connect_timeout 300;` 值連接到后端FastCGI的超時時間
-
fastcgi_send_timeout 300; 指向Fastcgi 傳送請求的超時時間,這個值是已經完成了2次握手后向FastCGI應答的超時時間
-
fastcgi_read_timeout 300; 指向接收FastCGI應答的超時時間,這個是已經完成2次握手后接收FastCGI應答的超時時間
-
fastcgi_buffer_size 64k; 用於指定讀取FastCGI。 應答第一部分需要多大的緩沖區,這個值表示將使用1個64KB的緩沖區讀取應答的第一部分(應答頭),可以設置Fastcgi_buffers選項指定的緩沖區大小。
-
fastcgi_buffers 4 64k; 指定本地需要多少和多大的緩沖區緩沖FastCGI的應答請求。如果一個PHP腳本所產生的頁面大小為256KB,那么就會為其分配4個64KB的緩沖區來緩存,如果頁面大小大於256KB,那么大於256KB的部分會緩存到Fastcgi_temp指定的路徑中。但是這個不是好辦法。因為內存中的數據處理速度大於硬盤,一般這個值應該為站點中的php腳本所產生的頁面大小的中間值,如果站點大部分腳本所產生的頁面大小為256KB,那么可以把這個值設置為16 16K,或者4 64KB。。
-
fastcgi_busy_buffers_size 128k; 默認值是fastcgi_buffers的兩 倍
-
fastcgi_temp_file_write_size 128k; 表示寫入緩存文件時使用多大的數據塊,默認是fastcgi_buffers的兩倍。
-
開啟緩存后:
fastcgi_cache_valid 200 302 1h;將http狀態碼是200的和302的緩存一小時,301的緩存一天,其他的緩存一分鍾 -
fastcgi_cache_valid 301 1d;
-
fastcgi_cache_valid any 1m;
寫完以上參數后,保存退出重啟服務。