php-fpm详解
什么是 FastCGI
FastCGI 是一個可伸縮、高速的在web server和腳本語言間通迅的接口。關于FastCGI技術的更多信息可以在官方網 站和Wikipedia看到。
FastCGI 被許多腳本語言所支持,包括 php,如果用 --enable-fastcgi 選項編譯的話。
多數流行的web server都支持 FastCGI。包括Apache(mod_fastcgi和mod_fcgid),Zeus,nginx和lighttpd。
FastCGI 的主要優點是把動態語言和 web server 分離開來。這種技術允許 web server 和動態語言運行在不同的主機上。這可以改進可擴展性和安全性而沒有大的效率損失。
php-fpm 可以和任何支持外部 FastCGI 技術的 web server 一起使用。
php-fpm是做啥用的
很不幸,官方網站?php.net?上的 php 在將 FastCGI SAPI 用于生產環境方面有許多已知的問題。
下面是關于啟用 FastCGI SAPI 時的問題和 php-fpm 是如何解決他們的對比列表。
描述
php自帶的
spawn-fcgi + spawn-php.sh + daemontools
php-fpm
php守護進程化: pid file, log file, setsid(), setuid(), setgid(), chroot()
(-)
(+)
(+)
進程管理。可以用 "graceful" 來停止并啟動 php worker 進程而不會丟失請求。能夠平滑地升級配置和二進制程序而不丟失任何請求。
php4 (-), php5 (只有 graceful)
(-)
(+)
嚴格限制來源請求的 web server 的 ip 地址
php4 (-) php5 (+) (從 5.2.2 開始)
(-)
(+)
根據負載動態調整進程數
(-)
(-)
Todo
用不同的 uid/gid/chroot/environment 和不同的 php.ini 選項啟動 worder 進程。你不需要 safe mode 了!
(-)
(-)
(+)
記錄 worker 進程 stdout 和 stderr 日志
(-)
(-)
(+)
如果使用優化器,在共享內存意外破壞的情況下緊急重啟所有的進程
(-)
(-)
(+)
如果 set_time_limit() 失敗,確保進程會結束
(-)
(-)
(+)
特色功能 Error header、優化的上傳支持、fastcgi_finish_request()
特色功能
所有這些特性都是“不打斷”的方式實現的。也就是說,如果你不使用它們,它們的存在不會影響php的功能性——他們都是“透明”的。
Error header
范圍:php.ini 選項
分類:便利性
默認情況下,如果被訪問的php腳本包含語法錯誤,用戶會收到一個空的“200 ok”頁。這是不方便的。Error header 這個 php.ini 選項允許在這種情況下產生一個 HTTP 錯誤碼,比如“HTTP/1.0 550 Server Made Big Boo”,從而中斷web server請求并顯示一個正確的錯誤頁。
如果要實現這樣的功能,需要在 php.ini 中添加一條 fastcgi.error_header = "HTTP/1.0 550 Server Made Big Boo"
在 php-5.2.4 中添加了類似,但不相同的功能:如果被訪問的php腳本包含語法錯誤,并且 display_errors = off,會立刻返回“HTTP/1.0 500 Internal Server Error”。
如果你需要設定一個 503 錯誤,或者想要使這個行為獨立于 display_errors 的設置,那么可以使用fastcgi.error_header。如果你在 php-5.2.5 或以上版本上啟用 php-fpm,那么 fastcgi.error_header的優先級更高。
優化的上傳支持
實質:web server 支持
類型:優化
這個特性正如名字那樣,可以加速對大 POST 請求的處理速度,包括文件上傳。優化是通過將請求體已寫入一個臨時文件,然后 fastcgi 協議傳遞文件名而不是請求體到來實現的。目前就我所知,只有 nginx0.5.9 以上才支持這個功能。顯然,這種模式只在 php 和 web server 在一臺機器上的時候才能用。
nginx 樣例配置:
location ~ \.php$ {
??? fastcgi_pass_request_body off;
??? client_body_in_file_only clean;
??? fastcgi_param? REQUEST_BODY_FILE?? $request_body_file;
??? ...
??? fastcgi_pass ...;
}
在php中不需要配置任何東西。如果php收到了參數REQUEST_BODY_FILE,就讀取其中的請求體,如果沒有,就自行從fastcgi 協議中讀取請求體。
結合這個特性,可以考慮對臨時文件使用內存文件系統,例如tmpfs(linux):
client_body_temp_path /dev/shm/client_body_temp;
fastcgi_finish_request()
范圍:php 函數
類型:優化
這個特性可以提高一些 php 請求的處理速度。如果有些處理可以在頁面生成完后進行,就可以使用這種優化。比如,在 memcached 中保存 session 就可以在頁面交給 web server 后進行。fastcgi_finisth_request() ,這一特性可以結束響應輸出,web server 可以立即開始交給等不及的客戶端,而此刻,php 可以在請求的上下文環境中處理許多事情。比如保存session,轉換上傳的視頻,處理統計等等。
fastcgi_finisth_request() 會觸發 shutdown 函數運行。
request_slowlog_timeout
范圍: php-fpm.conf 選項
分類: 方便
這個選項能讓你跟蹤執行緩慢的腳本并把他們連同調用棧一起記錄再日志文件中。例如如下設置:
<value name="request_slowlog_timeout">5s</value>
<value name="slowlog">logs/slow.log</value>
記錄的 slow.log 可能是這個樣子:
Sep 21 16:22:19.399162 pid 29715 (pool default)
script_filename =? /local/www/stable/www/catalogue.php
[0x00007fff23618120] mysql_query()? /srv/stable/common/Database/class.MySQLRequest.php:20
[0x00007fff23618560]? getResult() /srv/stable/common/Database/class.Facade.php:106
[0x00007fff23618aa0] query()? /srv/stable/common/mysite.com/ORM/class.UsersMapper.php:99
[0x00007fff23618d60] resolveByID()? /srv/stable/common/mysite.com/ORM/class.User.php:629
[0x00007fff236193b0]? getData() /srv/stable/common/class.DataEntity.php:90
[0x00007fff236195d0]? load() /srv/stable/common/mysite.com/ORM/class.User.php:587
[0x00007fff23619a00] getIsHidden()? /srv/stable/common/mysite.com/class.User.php:42
[0x00007fff2361a470]? getName() /local/www/stable/www/catalogue.php:41
同時,在 error.log 中保存了如下記錄:
Sep 21 16:22:19.399031 [WARNING] fpm_request_check_timed_out(), line 135:? child 29715, script '/local/www/stable/www/catalogue.php' (pool default)? executing too slow (5.018002 sec), logging
正如你再例子中看到的,腳本運行了 5 秒以上,并很可能是由于 mysql 響應慢造成的(top backtrace)。
FAQ
Q:php-fpm 可以和 ZendOptimize 一起用嗎?
A:完全可以。
Q:php-fpm 可以和 ZendPlatform、xcache、eAccelerator、APC 等的優化器一起用嗎?
A:是的。php-fpm 的架構和任何一種用于高速 opcode 緩存的共享內存都適用。唯一的限制是:所有的 worker 進程只能適用一個緩存,即使它們用不同的 uid/gid 運行
Q:為什么我要給 php 打補丁呢?spawn-fcgi 不需要這樣!
A:php-fpm 的創建是為了增強方便管理。沒有打過補丁的 php 不能做到:
平滑重啟 php 而不丟失請求,包括升級 php 二進制文件 以及/或者 擴展。
用不同的 uid / gid / chroot 環境運行 worker 進程
所有的設置只有一個配置文件
根據負載動態請求 (TODO)
對 php 請求實時統計性能 (TODO)
Q:為什么要用 root 運行 php-fpm 呢?這安全嗎?
A:用 root 啟動 php-fpm 只有在你打算用不同 uid/gid 的 php 來處理請求時才有意義。比如,在共享主機上的不同站點。因為只有在 master 進程用 root 運行的時候,才可以建立不同 uid/gid 的子進程。這是相當安全的。master 進程自己從來不會去處理請求。
在任何情況下,php- fpm 都不會用 root 身份來處理請求。
Q:php-fpm 可以加速 php 腳本處理速度嗎?
A:不,它不會影響處理速度。不過,如果你使用一些特殊特性,對于一些特定的請求還是可以有性能提升的。
Q:如果我把我的網站從 mod_php 遷移到 php-fpm ,我會得到性能提升嗎?
A:通常,當有服務器上有大量空閑內存可用時,能從遷移到 php-fpm 中得到的性能提升可能不大。但是如果內存并不充裕,性能提升還是很可觀的,在某些情況下可以達到 300-500%。這可能是由于 nginx + php-fpm 一般會比 Apache + mod_php 使用更少的內存。而且 VFS 緩存會由于更多的空余內存而更有效地工作。
Q:php- fpm 將來會被官方的 php 包含嗎?
A:我希望如此。目前,php-fpm 代碼的協議是 GPL 。所以現在 php-fpm 的代碼與 php 協議(類似 bsd)并不匹配。這是臨時性措施。這樣的選擇是為了簡化開發過程。一旦代碼的功能完備,比如自適應生成子進程和其他一些東西,協議會改為一個相匹配的。之后,php-fpm 會正式發布給 php 開發團隊,并被建議包含。
郵件列表
如果你有問題的話,請不要猶豫在郵件組里寫郵件。
English:?highload-php-en?Russian:?highload-php-ru
文檔
php-fpm 已經在 Linux、MacOSX、Solaris 和 FreeBSD 上測試通過。
確信 libxml2(在某些系統上叫做libxml2-devel)已經安裝。
下載最小的?php?和?php-fpm
$ bzip2 -cd php-5.2.5.tar.bz2 | tar xf -
$ gzip -cd php-5.2.5-fpm-0.5.7.diff.gz | patch -d php-5.2.5 -p1
$ cd php-5.2.5
$ ./configure --enable-fastcgi --enable-fpm
$ make all install
編輯
$prefix/etc/php-fpm.conf
運行
$prefix/bin/php-cgi --fpm
仔細檢查
$prefix/logs/php-fpm.log
運行 phpinfo() 檢查你的網站是否還正常運行
master 進程的 pid 被存放在
$prefix/logs/php-fpm.pid
master進程可以理解以下信號:
SIGINT, SIGTERM
立刻終止
SIGQUIT
平滑終止
SIGUSR1
重新打開日志文件
SIGUSR2
平滑重載所有worker進程并重新載入配置和二進制
關于
嗨,我的名字叫 Andrei Nigmatulin, 我是 php-fpm 的作者。
從 2004 年開始,我就在等有什么人讓 PHP FastCGI 能滿足產品環境,但我等不下去了。
php-fpm 是在數個項目種使用 PHP 的 FastCGI SAPI 中的知識、經驗和想法的產物。
php-fpm 可以在 GPL 協議下用在公共用途。和 php-fpm 綁定的修改版的?libevent?是在 BSD 協議下發布的。
我需要得到您的反饋——新的想法和建議——來改進和優化 php FastCGI SAPI。 如果您有什么想法、意見、補充和建議,我會很高興,很原意聽取,也許還會實現他們。給給我發郵件吧。(地址在本頁的末尾)。
如果你想支持 php-fpm 的開發,可以作一些捐贈: Paypal Yandex.Money
15/05/2007 - 第一次提交到 php-fpm.
andrei dot nigmatulin at gmail dot com
譯注:
php-fpm還帶有一個更方便的腳本,在$prefix/sbin/php-fpm。可以用php-fpm start|graceful|restart|stop來維護。稍編輯一下就可以讓它使用配置文件。
后記:
最開始,php-fpm 只有俄文文檔,弄的我很郁悶,于是我先用 google 翻譯先弄成英文,然后再人工翻成中文。這當中會難免會在我自己的英文水平引起的錯誤之外,再多些錯誤出來。后來終于有了一個英文的 wiki,并邀請我提供中文翻譯。同時,距上一次翻譯(2008年5月)以后,原來的文檔也已經有了更新。于是我就根據英文 wiki ,重新翻譯了一遍。
本文轉自守住每一天51CTO博客,原文鏈接:http://blog.51cto.com/liuyu/290950,如需轉載請自行聯系原作者
總結
- 上一篇: DVWA系列之17 CSRF攻击介绍与实
- 下一篇: ISDN的配置实例