nginx中配置php-FPM教程
nginx 可以直接調用FPM來驅動php,從此就可以放棄apache了。什麼原因不多說了。
先下載php5.4的安裝包。
照別人的說法
代碼如下 |
複製代碼 |
./configure --enable-fastcgi --prefix=/data1/server/php-cgi --with-gd --with-jpeg-dir --with-png-dir --with-freetype-dir --enable-mbstring --with-mysql --with-mysqli --with-pdo-mysql --enable-sockets --with-curl --with-ttf --with-libxml-dir --with-config-file-path=/data1/server/php-cgi/etc --with-zlib --enable-exif --enable-ftp --with-xmlrpc --enable-zip --with-iconv-dir --with-libxml-dir --with-mcrypt --with-tidy --with-tidy --enable-fpm --enable-force-cgi-redirect
|
提示無法安裝enable-force-cgi-redirect 等等一堆玩意兒
好的,去掉一些東西來安裝
代碼如下 |
複製代碼 |
./configure --prefix=/data1/server/php-cgi --with-gd --with-jpeg-dir --with-png-dir --with-freetype-dir --enable-mbstring --with-mysql --with-mysqli --with-pdo-mysql --enable-sockets --with-curl --with-libxml-dir --with-config-file-path=/data1/server/php-cgi/etc --with-zlib --enable-exif --enable-ftp --with-xmlrpc --enable-zip --with-iconv-dir --with-libxml-dir --with-mcrypt --with-tidy --with-tidy --enable-fpm
|
出現錯誤
configure: error: xml2-config not found. Please check your libxml2 installation.
代碼如下 |
複製代碼 |
1.安裝他 #apt-get install libxml2-dev 錯誤 configure: error: Please reinstall the libcurl distribution - easy.h should be in <curl-dir>/include/curl/ 2.安裝他 apt-get install libcurl4-gnutls-dev 錯誤 configure: error: jpeglib.h not found. 3.安裝他 apt-get install libjpeg-dev 錯誤 If configure fails try –with-vpx-dir=<DIR> configure: error: png.h not found. 4.安裝他 apt-get install libpng12-dev 錯誤 If configure fails try –with-xpm-dir=<DIR> configure: error: freetype.h not found. 5.安裝他 apt-get install libfreetype6-dev 錯誤 configure: error: mcrypt.h not found. Please reinstall libmcrypt. 6.安裝他 apt-get install libmcrypt-dev 錯誤 configure: error: Cannot find libtidy 7.安裝他 apt-get install libtidy-dev 我一個一個測試的。大家安裝的時候,可以先安裝這些錯誤需要安裝的東西,然後再執行./configure…… make make test make install |
啟動php-fpm
/data1/server/php-cgi/sbin/php-fpm
錯誤
[28-Mar-2012 11:15:01] ERROR: failed to open configuration file ‘/data1/server/php-cgi/etc/php-fpm.conf’: No such file or directory (2)
[28-Mar-2012 11:15:01] ERROR: failed to load configuration file ‘/data1/server/php-cgi/etc/php-fpm.conf’
[28-Mar-2012 11:15:01] ERROR: FPM initialization failed
cd /data1/server/php-cgi/etc
再次啟動
/data1/server/php-cgi/sbin/php-fpm
ERROR: [pool www] cannot get gid for group ‘nobody’
好吧,我們加一個組叫nobody
#groupadd nobody
再次啟動
/data1/server/php-cgi/sbin/php-fpm
成功了。
關閉php-fpm
killall php-fpm
目前還不知道有沒有直接的命令來關閉它。
cannot get gid for group ‘nobody’ 其他解決方案。
————————————————————————————
or can change it in your php-fpm.conf
; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user’s group
; will be used.
user = www-data
group = nobody
————————————————————————————-
整合nginx
最後的配置
代碼如下 |
複製代碼 |
# cd /etc/nginx/conf.d #vi default.conf location ~ \.php$ { root /usr/share/nginx/html; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; include fastcgi.conf; # vi /etc/nginx/fastcgi.conf fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; # PHP only, required if PHP was built with –enable-force-cgi-redirect fastcgi_param REDIRECT_STATUS 200; /etc/init.d/nginx stop /etc/init.d/nginx start |
成功啦。
給php一個設定檔,從安裝目錄拷貝一個
cp php.ini-development /data1/server/php-cgi/etc/php.ini
補充:php-fpm 輸出php錯誤記錄檔
nginx是一個web伺服器,因此nginx的access日誌只有對訪問頁面的記錄,不會有php 的 error log資訊。
nginx把對php的請求發給php-fpm fastcgi進程來處理,預設的php-fpm只會輸出php-fpm的錯誤資訊,在php-fpm的errors log裡也看不到php的errorlog
原因是php-fpm的設定檔php-fpm.conf中預設是關閉worker進程的錯誤輸出,直接把他們重新導向到/dev/null,所以我們在nginx的error log 和php-fpm的errorlog都看不到php的錯誤記錄檔。
調試起來就很痛苦了。解決nginx下php-fpm不記錄php錯誤記錄檔的辦法:
1.修改php-fpm.conf中配置 沒有則增加
catch_workers_output = yes
error_log = log/error_log
2.修改php.ini中配置,沒有則增加
log_errors = On
error_log = "/usr/local/lnmp/php/var/log/error_log"
error_reporting=E_ALL&~E_NOTICE
3.重啟php-fpm,
當PHP執行錯誤時就能看到錯誤記錄檔在"/usr/local/lnmp/php/var/log/error_log"中了
請注意:
1. php-fpm.conf 中的php_admin_value[error_log] 參數 會覆蓋php.ini中的 error_log 參數
所以確保你在phpinfo()中看到的最終error_log檔案具有可寫入權限並且沒有設定php_admin_value[error_log] 參數,否則錯誤記錄檔會輸出到php-fpm的錯誤記錄檔裡。
2.找不到php.ini位置,使用php的phpinfo()結果查看
3.如何修改PHP錯誤記錄檔不輸出到頁面或螢幕上
修改php.ini
display_errors = off //不顯示錯誤資訊(不輸出到頁面或螢幕上)
log_errors = on //記錄錯誤資訊(儲存到記錄檔中)
error_reporting = E_ALL //捕獲所有錯誤資訊
error_log = //設定記錄檔名
程式中修改以上配置
ini_set("display_errors",0)
ini_set("error_reporting",E_ALL); //這個值好像是個PHP的常量
ini_set("error_log","<記錄檔名>")
ini_set("log_errors",1);
4.如何將php的錯誤記錄檔輸出到nginx的錯誤記錄檔裡
在PHP 5.3.8及之前的版本中,通過FastCGI啟動並執行PHP,在使用者訪問時出現錯誤,會首先寫入到PHP的errorlog中
如果PHP的errorlog無法寫入,則會將錯誤內容返回給FastCGI介面,然後nginx在收到FastCGI的錯誤返回後記錄到了nginx的errorlog中
在PHP 5.3.9及之後的版本中,出現錯誤後PHP只嘗試寫入PHP的errorlog中,如果失敗則不會再返回到FastCGI了,錯誤記錄檔會輸出到php-fpm的錯誤記錄檔裡。
所以如果想把php錯誤記錄檔輸出到nginx錯誤記錄檔,需要使用php5.3.8之前的版本,並且設定檔中php的error_log對於php worker進程不可寫
php-fpm記憶體配置問題
nginx php-fpm配置過程中最大問題是內泄漏出問題:伺服器的負載不大,但是記憶體佔用迅速增加,很快吃掉記憶體接著開始吃交換分區,系統很快掛掉!
google了一天,終於發現些有用的東西,其實根據官方的介紹,php-cgi不存在記憶體流失,每個請求完成後php-cgi會回收記憶體,但是不會釋放給作業系統,這樣就會導致大量記憶體被php-cgi佔用。
官方的解決辦法是降低PHP_FCGI_MAX_REQUESTS的值,我用的是php-fpm,對應的php-fpm.conf中的就是max_requests,該值的意思是發送多少個請求後會重啟該線程,我們需要適當降低這個值,用以讓php-fpm自動的釋放記憶體,不是大部分網上說的51200等等,實際上還有另一個跟它有關聯的值max_children,這個是每次php-fpm會建立多少個進程,這樣實際上的記憶體消耗是max_children*max_requests*每個請求使用記憶體,根據這個我們可以預估一下記憶體的使用方式,就不用再寫指令碼去kill了。
下面其實是重啟指令碼的過程,並不是什麼很嚴重的事情,但是我們要小心,不是說一直重啟就是好的,因為重啟會導致cpu的使用率飆升,系統負載巨大,所以還是平衡上面的資料比較重要。
Mar 08 16:13:33.113138 [NOTICE] fpm_got_signal(), line 48: received SIGCHLD
Mar 08 16:13:33.113202 [WARNING] fpm_children_bury(), line 215: child 23051 (pool default) exited on signal 11 SIGSEGV after 747.428492 seconds from start
Mar 08 16:13:33.113622 [NOTICE] fpm_children_make(), line 352: child 24511 (pool default) started
配置指南通訊指南
TCP配置方式
TCP通訊配置起來很簡單,三步即可搞定
第一步,編輯 /etc/nginx/conf.d/你的網站設定檔(如果使用的預設設定檔,修改/etc/nginx/sites-available/default)
將fastcgi_pass參數修改為127.0.0.1:9000,像這樣:
代碼如下 |
複製代碼 |
location ~ \.php$ { index index.php index.html index.htm; include /etc/nginx/fastcgi_params; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; include fastcgi_params; }
|
第二步,編輯php-fpm設定檔 /etc/php5/fpm/pool.d/www.conf
將listen參數修改為127.0.0.1:9000,像這樣:
listen = 127.0.0.1:9000
第三步,重啟php-fpm,重啟nginx
unix socket配置方式
unix socket其實嚴格意義上應該叫unix domain socket,它是*nix系統處理序間通訊(IPC)的一種被廣泛採用方式,以檔案(一般是.sock)作為socket的唯一標識(描述符),需要通訊的兩個進程引用同一個socket描述符檔案就可以建立通道進行通訊了。
配置需要五步
第一步,決定你的socket描述符檔案的儲存位置。
可以放在系統的任意位置,如果想要更快的通訊速度,可以放在/dev/shm下面,這個目錄是所謂的tmpfs,是RAM可以直接使用的地區,所以,讀寫速度都會很快。
決定了檔案位置,就要修改檔案的許可權了,要讓nginx和php-fpm對它都有讀寫的許可權,可以這樣:
代碼如下 |
複製代碼 |
sudo touch /dev/shm/fpm-cgi.sock sudo chown www-data:www-data /dev/shm/fpm-cgi.sock sudo chmod 666 /dev/shm/fpm-cgi.sock
|
第二步,修改php-fpm設定檔/etc/php5/fpm/pool.d/www.conf
將listen參數修改為/dev/shm/fpm-cgi.sock,像這樣:
listen = /dev/shm/fpm-cgi.sock
將listen.backlog參數改為-1,記憶體壓無限大,預設是128,並發高了之後就會報錯
; Set listen(2) backlog. A value of '-1' means unlimited.
; Default Value: 128 (-1 on FreeBSD and OpenBSD)
listen.backlog = -1
第三步,修改nginx網站設定檔
將fastcgi_pass參數修改為unix:/dev/shm/fpm-cgi.sock,像這樣:
代碼如下 |
複製代碼 |
location ~ \.php$ { index index.php index.html index.htm; include /etc/nginx/fastcgi_params; fastcgi_pass unix:/dev/shm/fpm-cgi.sock; fastcgi_index index.php; include fastcgi_params; }
|
第四步,修改/etc/sysctl.conf 檔案,提高核心層級的並發串連數(這個系統級的設定檔我也不是特別熟悉,參考的是這篇部落格:《Php-fpm TcpSocket vs UnixSocket》)
sudo echo 'net.core.somaxconn = 2048' >> /etc/sysctl.conf
sudo sysctl -p
第五步, 重啟nginx和php-fpm服務(最好先重啟php-fpm再重啟nginx)
兩種通訊方式的分析和總結
從原理上來說,unix socket方式肯定要比tcp的方式快而且消耗資源少,因為socket之間在nginx和php-fpm的進程之間通訊,而tcp需要經過本地迴環驅動,還要申請臨時連接埠和tcp相關資源。
當然還是從原理上來說,unix socket會顯得不是那麼穩定,當並發串連數爆發時,會產生大量的長時緩衝,在沒有連線導向協議支撐的情況下,大資料包很有可能就直接出錯並不會返回異常。而TCP這樣的連線導向的協議,多少可以保證通訊的正確性和完整性。
當然以上主要是半懂不懂的理論分析加主觀臆測,具體的差別還是要通過測試資料來說話,以後有空,會進行這方面的測試。從網上別人部落格的測試資料,我的理論分析差不多是對的。至於你選擇哪種方式,我只能說“魚和熊掌不可兼得也”,通過高超的營運和配置技巧,在效能和穩定性上做一個平衡吧。