1. 程式人生 > >what's FastCGi for php

what's FastCGi for php

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了,啟動命令如下:

  [[email protected] ~]# php-fpm        啟動php-fpm

如果有像這樣的報錯:

 [[email protected] 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

[[email protected] ~]# 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一份來修改後即可用,命令如下:

[[email protected] ~]# cd /etc/nginx/conf.d/
[[email protected] conf.d]# ls
default.conf
[[email protected] conf.d]# cp default.conf web1.conf
[[email protected] conf.d]# mv default.conf default.cf    # 避免預設配置影響nginx執行
[[email protected] 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;

寫完以上引數後,儲存退出重啟服務。