2017年2月12日 星期日

Apache + php-fpm in CentOS 7

參考 1: Apache 2.4 mpm_event + php-fpm in CentOS 7
參考 2: Install PHP-FPM to make PHP scripts be fast
參考 3: High-performance PHP on apache httpd 2.4.x using mod_proxy_fcgi and php-fpm

prefork+module_php

依照網上找到的說明,裝好 Apache、PHP、PHP-FPM。
預設的安裝,是使用 prefork+module_php。
phpinfo() 送回的資訊為 "Server API: Apache 2.0 Handler"

prefork+php-fpm

修改 /etc/httpd/conf.d/php.conf,取消原來的 AddHandler,新增 SetHandler
# AddHandler php7-script .php
SetHandler "proxy:fcgi://127.0.0.1:9000"

即可在 prefork 模式下,透過 proxy:fcgi 來呼叫 PHP-FPM 處理 PHP 程式
phpinfo() 送回的資訊為 "Server API:  FPM/FastCGI"

event+php-fpm

更進一步,修改 /etc/httpd/conf.modules.d/00-mpm.conf,取消 mod_mpm_prefork.so,改用 mod_mpm_event.so
# LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
LoadModule mpm_event_module modules/mod_mpm_event.so

以及在 /etc/httpd/conf/httpd.conf 中,加上
<IfModule mpm_event_module>
     ProxyPassMatch ~.php$ fcgi://127.0.0.1:9000
</IfModule>

則可使用 event 模式+PHP-FPM。

測試說明

以下,稍微用 ab 跑一下測試,瞭解一下差異。
$ ab -c 60 -n 2000 http://10.161.91.37:8080/laravel51-test/

取回資料的長度:        1197 bytes

計算 httpd process 的數量,注意,以下的指令會多算一個
# ps ax | grep httpd | wc -l 

另外,使用 htop 觀察系統各項資源的情形。

1. 預設的 prefork+module_php

重新啟動 (systemctl restart httpd) 之後
process: 6
memory: 238M, 其中,1.8% *1 、0.5 * 5
測試時,大約的最大值
process: 132
memory: 950M,其中 1.8% *1、1.2%*1、其餘 1.1%
效能
Requests per second:    150.58 [#/sec] (mean)
Time per request:       398.449 [ms] (mean)

2. prefork+php-fpm

重新啟動之後
process: 7
memory: 245M,1.8% *1、0.5% *6
php-fpm 的 memory:  master: 1.6% *1、其餘: 0.5%
測試時,大約的最大值
process: 72
memory: 609M
效能
Requests per second:    171.73 [#/sec] (mean)
Time per request:       349.376 [ms] (mean)

3. event+php-fpm

重新啟動之後
process: 5
memory: 243M,0.9% *1、其餘 0.6%。
假如 php-fpm 也重新啟動,memory: 214M
測試時,大約的最大值
process: 8,外加一堆 thread
memory: 535M
 效能
Requests per second:    147.16 [#/sec] (mean)
Time per request:       407.722 [ms] (mean)


小結

使用 event 模式,就是省記憶體,效能則一樣是取決於 PHP。70

大家都在傳 Nginx 很快,但也有測試比較的結果,假如 Apache 把 .htaccess 的 override 關掉,效能立刻變好。而且,在 PHP 的網頁,效能取決於 PHP。雖然,有人聲稱 .htaccess是萬惡之源,但想偷懶,就繼續用囉。

下載伺服器測試

prefork+mod_php: 139 processes, 600MB
prefork+php-fpm: 130 processes, 700MB
event+php-fpm: 120 threads, 800MB/ 150 threads, 920MB

先前聽說 Nginx 多強大,決定將原來運作的下載伺服器,改用 Nginx。但在換成 Nginx 之後,發現CPU使用率飆高,外部很難連上來,然後,就開始不穩定,PHP-FPM會當掉。

改回 Apache 之後, 發現不論那一種組合,運作都很穩定,CPU和記憶體的使用率,都沒有太大的差異。所以,真的有點懷疑網路上,對 Nginx 的吹捧。除非,我的設定,真的那裡有問題,而我能力有限,無法進一步改善。

嗯,我的下載伺服器,就只是跑一堆像下面的程式,把下載的速度控制在 800KB/s 左右,避免頻寬被吃光。改用 Nginx,伺服器就一付快掛的樣子,而用 Apache,硬就是游刃有餘。

哦,對了,順帶一提,這程式支援續傳 (resume),有興趣的人,可以參考參考。請多指教!

<?php

$fullname = $doc_root.'/mp4/'.$fname;

if (!is_file($fullname)) {
    // file does not exist
    ob_clean();
   
    header("HTTP/1.0 404 Not Found");
    // header("HTTP/1.0 404 Not Found", true, 404);
    die ('Sorry, file not found!!');
    exit;
}

$file_size = filesize($fullname);
$fp = fopen($fullname, 'rb');


if (!$fp) {
    // file couldn't be opened
    ob_clean();
    flush();
    header("HTTP/1.0 500 Internal Server Error");
    exit;
}

if(isset($_SERVER['HTTP_RANGE'])) {
    list($size_unit, $range_orig) = explode('=', $_SERVER['HTTP_RANGE'], 2);
    if ($size_unit == 'bytes')
    {
        //multiple ranges could be specified at the same time, but for simplicity only serve the first range
        //http://tools.ietf.org/id/draft-ietf-http-range-retrieval-00.txt
        list($range, $extra_ranges) = explode(',', $range_orig, 2);
    } else {
        $range = '';
        header('HTTP/1.1 416 Requested Range Not Satisfiable');
        exit;
    }
} else {
    $range = '';
}

//figure out download piece from range (if set)
list($seek_start, $seek_end) = explode('-', $range, 2);

//set start and end based on range (if set), else set defaults
//also check for invalid ranges.
$seek_end   = (empty($seek_end)) ? ($file_size - 1) : min(abs(intval($seek_end)),($file_size - 1));
$seek_start = (empty($seek_start) || $seek_end < abs(intval($seek_start))) ? 0 : max(abs(intval($seek_start)),0);

ob_clean();

header('Content-type: application/mp4'); //告訴瀏覽器 為下載
header('Content-Transfer-Encoding: Binary'); //編碼方式
header("Content-Disposition:attachment; filename=\"".$fname."\""); //檔名.

//Only send partial content header if downloading a piece of the file (IE workaround)
if ($seek_start > 0 || $seek_end < ($file_size - 1)) {
    header('HTTP/1.1 206 Partial Content');
    header('Content-Range: bytes '.$seek_start.'-'.$seek_end.'/'.$file_size);
    header('Content-Length: '.($seek_end - $seek_start + 1));
} else {
    header("Content-Length: $file_size");
}

header('Accept-Ranges: bytes');

set_time_limit(0);
fseek($fp, $seek_start);

while(!feof($fp)) {
    // limited rate to about 0.5 MB/Sec
    // 10KB * 50 = 500KB
    // 1000,000/50 = 20,000
    print(@fread($fp, 1024*100));
    ob_flush();
    flush();
    // wait for 20,000 micro-seconds
    usleep(1.2*pow(10,5));
    if (connection_status()!=0) {
        @fclose($fp);
        exit;
    }
}

ob_end_flush();
exit;
 




沒有留言: