FreeBSD 建置 Apache + mod_fastcgi + php-fpm

近日在實驗 Apache 使用 FastCGI (mod_fastcgi) 搭配 PHP 提供的 PHP-FPM 網頁架構。

Apache 如果什麼都沒有動的話,應該預設是跑 prefork ,也就是預先 fork 一些子程序出來等連線,這樣的架構在大量連線的伺服器來說不是很穩定。更改編譯選項可以換成用 worker mpm 方式,如此一來 Apache 可以用 thread  的方式來執行,資源利用較有效率。

除此之外,PHP 的部份也可以改用 FastCGI 的方式來執行。

預設安裝的 mod_php5 的執行方式是由 Apache 呼叫,等待 PHP 程式執行完畢之後再一起輸出給使用者。若是使用 CGI 的方式來執行,則當 Apache 收到 PHP 執行需求的時候,會去叫起 php-cgi 這隻程式,等待其執行完畢之後再回傳結果。當然這也不是有效率的作法,因為一次只接受一個連線,若有多個連線要叫起一堆的 php-cgi。若採用 FastCGI protocol 的方式執行,php-cgi 這隻程式會成為一隻 daemon 在背景執行,隨時等待連線。

FastCGI protocol 在 Apache 裡面的實做方式有兩種,mod_fastcgi 與 mod_fcgid。前者發展較早,由 fastcgi.com 維護,fastcgi process 開起來之後會一直在後台跑,隨時接受連線;後者為 Apache 基金會自己的項目,目標是可以隨時動態增減 fastcgi process 的數量,一旦用完就殺掉,有效利用資源又不致於在 晚上 流量大的時候被打掛。關於這兩個的優劣並沒有絕對,各位可以上網搜尋相關資料。

php-fpm 則是 PHP 下面的項目,目標是改善 FastCGI 無法有效控制生出來的 php-cgi 程式的問題,不論是記憶體管理或者是 process number 上都有較好的限制,除此之外還可以用 setuid、chroot 之類的功能作到更好的權限控管 (替換掉一點都不安全的 php safe_mode)。

這邊要注意的是,PHP-FPM 目前只能搭配 mod_fastcgi 運作,因為 mod_fcgid 不支援呼叫外部  FastCGI server (跑在 socket 也算)。若必須要使用 mod_fcgid,則要透過 mod_proxy_fcgi。該專案仍在開發中,感覺還不穩定,因此本例中不採用。

首先當然就是安裝 mod_fastcgi。

# cd /usr/ports/www/mod_fastcgi && make install

再來就是確定 PHP 編譯時有選取 FPM 這個選項,可以在系統裡找看看有沒有 php-fpm 這隻程式,如果沒有的話也要重新編譯 PHP。
(關於 FreeBSD 近期新增的 OptionsNG 編譯選項,留待日後再專文討論 :P)

我的習慣是在 Includes 裡面新增一個 php-fpm.conf:

<IfModule mod_fastcgi.c>
        ScriptAlias /php5.fcgi /usr/local/www/apache22/fastcgi/php5.fcgi
        FastCGIExternalServer /usr/local/www/apache22/fastcgi/php5.fcgi -socket /tmp/php-fpm.sock
        AddType application/x-httpd-fastphp5 .php
        Action application/x-httpd-fastphp5 /php5.fcgi

        <Directory "/usr/local/www/apache22/fastcgi">
                Order deny,allow
                Options ExecCGI
                Deny from all
                <Files "php5.fcgi">
                    Order allow,deny
                    Allow from all
                </Files>
        </Directory>
</IfModule>

這邊要注意的是事實上並沒有 php5.fcgi 這個檔案,由於要接到 PHP-FPM 的 socket,所以這樣寫是為了讓 Apache 以為那裡有一個虛擬的 handler 可以處理。我們只需要建立 /usr/local/www/apache22/fastcgi 這個資料夾即可。

上面也定義了 PHP-FPM 所使用的本機 socket,本例是放在 /tmp/php-fpm.sock,若是有需要也可以設定為網路上的其他主機,預設是 127.0.0.1:9000。

error_log = log/php-fpm.log
log_level = notice
; log 看個人習慣
pm.max_children = 10
; 最多可以生出來的子進程
pm.start_servers = 2
; 一開始生出來的子進程
pm.min_spare_servers = 2
; 可閒置子進程的最低數量
pm.max_spare_servers = 4
; 可閒置子進程的最高數量
;pm.max_requests = 1000
; 每個子進程可以接受的最多連線數,超過會砍掉重生
listen = /tmp/php-fpm.sock
; 要聽的 socket

 最後在 /etc/rc.conf 加上 php_fpm_enable=”YES” 就好了。
# apachectl restart && /usr/local/etc/rc.d/php-fpm start 之後看看成果吧!

若是 phpinfo() 中的 Server API 顯示 FPM/FastCGI 代表你成功了!可以把 httpd.conf 裡面的 php module 拿掉,留 mod_fastcgi 即可。

參考資料

http://blog.gslin.org/archives/2010/12/06/2370/freebsd-%E4%BD%BF%E7%94%A8-fastcgi-php-5-3-%E6%8F%90%E4%BE%9B%E7%9A%84-php-fpm/
http://funcptr.net/2010/11/14/apache-mod_fastcgi-and-php-with-php-fpm/

FreeBSD 建置 Apache + mod_fastcgi + php-fpm

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料