Thursday, May 8, 2014

Apache MPM Worker + mod_fastcgi + PHP-FPM

Apache MPM Worker + mod_fastcgi + PHP-FPM

Quick Notes:
[] There are two kinds of Apache MPM (Multi-Processing Modules):
- prefork
- worker (threaded MPM)

[] Apache MPM:
- MPM prefork + mod_php
- MPM worker (threaded MPM) + mod_fastcgi
- MPM worker (threaded MPM) + mod_fcgid

Note: if you want to use either mod_fastcgi or mod_fcgid, be aware of that each process has its own APC opcode cache, which in turn wastes memory resource, unless you use PHP-FPM to share APC cache between processes.

[] 由於 php-fpm 是自帶的 FastCGI Process Manager , 所以和原本的 php fastcgi 有所不同 , php-fpm 若要搭配 Apache 只能以 mod_fastcgi 來運作 , 原本 Apache 有開發 mod_fcgid , 但 mod_fcgid 本身算是個 FastCGI Process Manager , 只能執行本地端 FastCGI , 而 php-fpm 可以用 Unix Socket 或 TCP 模式讓任何具備執行外部 FastCGI 程序的 WebServer 連接 , 因此 lighttpd 或 Ngix 等都可以 , 唯獨世上次爛的 Apache 要外掛 mod_fastcgi , 最爛的當然是 IIS 了 , 哈

[] PHP-FPM not only supports TCP/IP connections (ex: but also the socket based connections (ex: /tmp/php-fpm.sock).

The advantage of running PHP-FPM on socket connections instead of TCP/IP is that the socket connections are much more faster than TCP/IP connections (around 10-15%) because it saves the passing the data over the different layers of TCP/IP stack.
Therefore, it is recommended to run the PHP-FPM on socket connections over TCP/IP when you are using the same server for Apache and PHP-FPM. If you are using the different servers for Apache and PHP-FPM then the socket connections for PHP-FPM will not work.

[] the topic of sharing APC opcode cache between processes.

[] Apache 改為 MPM Worker 模式運作 (instead of MPM prefork)

甚麼是 worker 模式 ? 簡單來說就是 Apache 會搭配多行程 + 多執行緒的方式運作 , 每個行程會有多個執行續同時服務客戶端連線 , 記憶體及效能都較好 , 由於 php-fpm 或 php fastcgi 都已經是獨立於 Apache 行程了 , 所以 Apache 若再跑 prefork 模式就浪費了 , 因此可以切換為 worker 模式 。

[] Use mod_fastcgi's FastCgiExternalServer to point to PHP-FPM, no more wrapper script please!!

[] Most of apache config examples are outdated or wrong, or copy from other wrong articles.

[] PHP-FPM is a daemon and mod_fcgid's official site ( is not talking about PHP-FPM, it is talking about php patched with fastcgi library

[] PHP-FPM is native in PHP since 5.3.3, so the mod_fcgid is not the choice for PHP user at the mean time, unless it provide Directive similiar to mod_fastcgi's FastCgiExternalServer.

[] Why shouldn't I use Apache2 with a threaded MPM in a production environment?
PHP is glue. It is the glue used to build cool web applications by sticking dozens of 3rd-party libraries together and making it all appear as one coherent entity through an intuitive and easy to learn language interface. The flexibility and power of PHP relies on the stability and robustness of the underlying platform. It needs a working OS, a working web server and working 3rd-party libraries to glue together. When any of these stop working PHP needs ways to identify the problems and fix them quickly. When you make the underlying framework more complex by not having completely separate execution threads, completely separate memory segments and a strong sandbox for each request to play in, further weaknesses are introduced into PHP's system.

If you want to use a threaded MPM, look at a FastCGI configuration where PHP is running in its own memory space.

System Specifications
- FreeBSD 8.2-STABLE-201105
- apache-worker-2.2.19
- php5-5.3.6_1
- php5-extensions-1.5
- mysql-server-5.5.13
- ap22-mod_fastcgi-2.4.6_1
- pecl-APC-3.1.9_1
- memcached-1.4.5_2
- pecl-memcached-1.0.2

Install Apache
# cd /usr/ports/www/apache22-worker-mpm ; make install

Install PHP5
# cd /usr/ports/lang/php5 ; make install
# cd /usr/ports/lang/php52 ; make install

FPM=on "Build FPM version (experimental)"
MULTIBYTE=on "Enable zend multibyte support"
SUHOSIN=on "Enable Suhosin protection system"
MAILHEAD=on "Enable mail header patch"
LINKTHR=on "Link thread lib (for threaded extensions)"

/usr/ports/lang/php52 # make showconfig
===> The following configuration options are available for php52-5.2.17_2:
CLI=on "Build CLI version"
CGI=on "Build CGI version"
APACHE=off "Build Apache module"
DEBUG=off "Enable debug"
SUHOSIN=on "Enable Suhosin protection system (not for jails)"
MULTIBYTE=on "Enable zend multibyte support"
IPV6=off "Enable ipv6 support"
MAILHEAD=on "Enable mail header patch"
REDIRECT=off "Enable force-cgi-redirect support (CGI only)"
DISCARD=off "Enable discard-path support (CGI only)"
FASTCGI=on "Enable fastcgi support (CGI only)"
FPM=on "Enable fastcgi process manager (CGI only)"
PATHINFO=on "Enable path-info-check support (CGI only)"
LINKTHR=on "Link thread lib (for threaded extensions)"
===> Use 'make config' to modify these settings

Copy php.ini file
// For PHP5.3
# cp /usr/local/etc/php.ini-production /usr/local/etc/php.ini

// For PHP5.2
# cp /usr/local/etc/php.ini-recommended /usr/local/etc/php.ini

Install PHP Extensions
# cd /usr/ports/lang/php52-extensions ; make install

/usr/ports/lang/php52-extensions # make showconfig
===> The following configuration options are available for php52-extensions-1.3_1:
BCMATH=off "bc style precision math functions"
BZ2=off "bzip2 library support"
CALENDAR=off "calendar conversion support"
CTYPE=on "ctype functions"
CURL=on "CURL support"
DBA=off "dba support"
DBASE=off "dBase library support"
DOM=on "DOM support"
EXIF=off "EXIF support"
FILEINFO=off "fileinfo support"
FILTER=on "input filter support"
FRIBIDI=off "FriBidi support"
FTP=off "FTP support"
GD=on "GD library support"
GETTEXT=on "gettext library support"
GMP=off "GNU MP support"
HASH=on "HASH Message Digest Framework"
ICONV=on "iconv support"
IMAP=off "IMAP support"
INTERBASE=off "Interbase 6 database support (Firebird)"
JSON=on "JavaScript Object Serialization support"
LDAP=off "OpenLDAP support"
MBSTRING=on "multibyte string support"
MCRYPT=off "Encryption support"
MHASH=off "Crypto-hashing support"
MING=off "ming shockwave flash support"
MSSQL=off "MS-SQL database support"
MYSQL=off "MySQL database support"
MYSQLI=on "MySQLi database support"
NCURSES=off "ncurses support (CLI only)"
ODBC=off "unixODBC support"
OPENSSL=off "OpenSSL support"
PCNTL=off "pcntl support (CLI only)"
PCRE=on "Perl Compatible Regular Expression support"
PDF=off "PDFlib support (implies GD)"
PDO=on "PHP Data Objects Interface (PDO)"
PDO_SQLITE=on "PDO sqlite driver"
PDO_MYSQL=on "PDO mysql driver"
PGSQL=off "PostgreSQL database support"
POSIX=on "POSIX-like functions"
PSPELL=off "pspell support"
READLINE=off "readline support (CLI only)"
RECODE=off "recode support"
SESSION=on "session support"
SHMOP=off "shmop support"
SIMPLEXML=on "simplexml support"
SNMP=off "SNMP support"
SOAP=off "SOAP support"
SOCKETS=off "sockets support"
SPL=on "Standard PHP Library"
SQLITE=on "sqlite support"
SYBASE_CT=off "Sybase database support"
SYSVMSG=off "System V message support"
SYSVSEM=off "System V semaphore support"
SYSVSHM=off "System V shared memory support"
TIDY=off "TIDY support"
TOKENIZER=on "tokenizer support"
WDDX=off "WDDX support (implies XML)"
XML=on "XML support"
XMLREADER=on "XMLReader support"
XMLRPC=off "XMLRPC-EPI support"
XMLWRITER=on "XMLWriter support"
XSL=off "XSL support (Implies DOM)"
YAZ=off "YAZ support (ANSI/NISO Z39.50)"
ZIP=off "ZIP support"
ZLIB=off "ZLIB support"
===> Use 'make config' to modify these settings

Install mod_fastcgi
# cd /usr/ports/www/mod_fastcgi ; make install

Edit httpd.conf
# vim /usr/local/etc/apache22/httpd.conf
LoadModule fastcgi_module libexec/apache22/
Include etc/apache22/extra/httpd-mpm.conf

Edit php.conf
# vim /usr/local/etc/apache22/Includes/php.conf
<IfModule prefork.c>
  LoadModule php5_module libexec/apache22/
  AddType application/x-httpd-php .php .html
  AddType application/x-httpd-php-source .phps

<IfModule worker.c>
  FastCGIExternalServer /usr/local/sbin/php-fpm -socket /tmp/php-fpm.sock -idle-timeout 900
  AddHandler php-fastcgi .php
  Action php-fastcgi /usr/local/sbin/php-fpm.fcgi
  ScriptAlias /usr/local/sbin/php-fpm.fcgi /usr/local/sbin/php-fpm

  <Directory /usr/local/sbin>
    Options ExecCGI FollowSymLinks
    SetHandler fastcgi-script
    Order allow,deny
    Allow from all

DirectoryIndex index.php index.html index.htm

Edit php-fpm.conf:
# vim /usr/local/etc/php-fpm.conf
#listen =
listen = /tmp/php-fpm.sock

listen.owner = www = www
listen.mode = 0660

Edit rc.conf
# vim /etc/rc.conf
## fpm

## apache

Edit no-accf.conf
# vim /usr/local/etc/apache22/Includes/no-accf.conf
### make sure you do comment out following two lines
### in order to make accf_http module (the 'httpready' Accept Filter) to work.
#AcceptFilter http none
#AcceptFilter https none

Start php-fpm, apache22:
# /usr/local/etc/rc.d/php-fpm start
# /usr/local/etc/rc.d/apache22 start

Make sure it's running as MPM Worker
# httpd -V
Server MPM: Worker

Benchmarking Apache to give us an impression of how our current Apache installation performs
# ab -c 100 -n 10000 http://web-test.local/index.php

隨便寫個 <?php echo "hello world"; ?> 來測試

我用 ab -c xx -n xxxx 的方式來測試效能及穩定度 , 分別用 20 , 100 , 500 條連線來測試 50000 次 request

大概可以直接說結果 , 就不看數據了

在 20 及 100 條連線下 , mod_php 的執行時間大約在 3~4 秒 , php-fpm 則在 7~8 秒 , 看樣子 php-fpm 挺鳥的說 ~~

但 500 條連線就見真章了 , mod_php 會很不穩 , 中間會 lag , 所以測試的數據忽上忽下 , 有時 7 秒 , 有時 10 秒甚至 15 秒

而 php-fpm 仍然在 7~8 秒 , 非常穩定

這代表甚麼 ????

Apache worker 模式 + php-fpm 在一個連線數量很多很操的 Server 上會表現得很穩定 , 另外我要說一下 , mod_fastcgi 其實效能並不佳 , 很多測試數據都有說比 Apache 自己寫的 mod_fcgid 差很多 , 我自己也玩過 mod_fcgid + php 也是如此 , 但 mod_fastcgi 表現卻比較穩定 , mod_fcgid 在連線數量多及連續 request 次數多時也會有 lag 情形 , 因此, 有興趣尋求最佳php運作環境的人的可以試試看 lighttpd 或 ngix 甚至是號稱比 lighttpd 及 ngix 快很多的 cherokee 來搭配 php-fpm , 應該會有更棒的表現

後來想想 , hello world 在傳輸的數據太少 , 於是再多測試 <?php phpinfo(); ?> 這個方式

也是用 20 /100/500 條連線來 request 1 萬次

20 條連線時 , mod_php 最佳時間為 6.45 秒 , 而 php-fpm 為 6.42 秒 , 差不多 , 而且都不會 lag

100 條連線時 , mod_php 最佳時間為 6.43 秒 ,php-fpm 為 6.37 秒 , 還是差不多 , 而且都不會 lag

500 條連線時 , mod_php 最佳時間為 6.69 秒 , php-fpm 為 6.42 秒 , 看起來還是一樣 , 但 500 條連線時 , mod_php 發生 lag 情形較多次 , 也就是說可能會看到超過 10 秒以上的時間挺多次的

從上面的測試不難發現 , Apache fork 模式的架構仍有一定的瓶頸 , 而且在實際網站應用上不光只有 php , 還有其他的靜態網頁 , 如果使用 Apache+mod
_php 跑 , 這樣靜態網頁的效能會跟著被拖慢 , 而 Apache worker + php-fpm (或 php fastcgi) 的好處是 , Apache 只把 php 的處理權交出去 , 靜態網頁仍由 Apache 處理 , 這樣在整體效能及記憶體用量都會改善許多

若以單項只跑 php 來看 , mod_php 在一個人不多的網站其實是最快的 , 但當流量大到一定程度 , 除非多買硬體啦 , 若要節省成本 , 採用 FastCGI 架構才是最好的方式


Thursday, May 1, 2014


莫札特(Wolfgang Amadeus Mozart)寫出經典的第九號鋼琴協奏曲時,已持續創作協奏曲10年;

投資大師華倫‧巴菲特(Warren Buffett)早在11歲時,就進行了人生第一筆股票投資交易;


微軟(Microsoft)創辦人比爾‧蓋茲(Bill Gates)在上大學前5年,幾乎天天都在寫程式。

這些「成功人士」的共同點是什麼?《異數》(Outliers)作者麥爾坎‧葛拉威爾(Malcolm Gladwell)認為,「成功最重要的關鍵似乎是準備,而非才能。」成功者都在專業生涯剛起步時,就開始密集練習日後藉以揚名立萬的專業,葛拉威爾將此稱之為「1萬小時的努力」。


葛拉威爾以心理學家艾瑞克森(K. Anders Ericsson)的實驗,說明「勤於練習」的重要。





成功者通常擁有至少一種專業。所謂「專業」就是精通某一個領域,而精通形同「絕對的稱職」。領導學大師華倫.班尼斯(Warren Bennis)在《領導,不需要頭銜》(On Becoming A Leader)一書中,引述作家喬治‧李奧納德(George Leonard)對於「精通」的定義:「精通建立於勤奮不懈地練習,雖然這也是冒險所在。……無論是運動、藝術或其他工作,被稱為大師的人,都是無視於別人的想法,熱情地投入他們的天職。」



年僅26歲的華裔設計師吳季剛,因為設計的禮服被美國總統夫人蜜雪兒‧歐巴馬(Michelle Obama)挑中,一炮而紅。看似少年得志的他,其實5歲起就喜歡看婚紗、幫洋娃娃設計衣裳,12歲便正式投入大師門下學習服裝設計。面對旁人異樣的眼光,吳季剛在家人的支持下持續地投入,也讓他比多數設計師同儕,足足多練習了10年。



《成功長青》(Success Built to Last)一書指出,成功的實踐家熱愛自己的工作,所以願意投入大量時間研究;而專注精神和專業知識,則讓他們能觀察到微妙的產業變化,掌握機會。




《從A到A+》(From Good to Great)一書中引用了一個經典寓言故事:「狐狸知道很多事情,但刺蝟只知道一件大事。」成功的實踐家,多半都具備刺蝟特質,專心致力於能夠點燃他們熱情的「一件事」,憑著努力、毅力與應變力,在專業的路上不斷突破創新。