參考 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"
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
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>
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, 600MBprefork+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;
$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;
沒有留言:
張貼留言