2015-12-19 88 views
3

我正在分析我的PHP網站的性能,並驚訝地發現瓶頸是header函數。爲什麼header()函數非常慢?

我在PHP 5.3和Apache 2.4上運行。

我爲基準兩個簡單的文件與ab,發現第一 - 執行phpinfo() - 是大大低於第二快 - 呼叫header

第一個文件(能夠以每秒超過1000個請求運行):(!只能每秒12個的請求)

<?php phpinfo(); ?> 

第二個文件:

<?php header('HTTP/1.1 200 OK'); ?> 

從完全ab輸出

第一次測試:

C:\work\apache24\bin>ab -n 1000 -c 200 http://q.localhost/test.php 
This is ApacheBench, Version 2.3 <$Revision: 1663405 $> 
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ 
Licensed to The Apache Software Foundation, http://www.apache.org/ 

Benchmarking q.localhost (be patient) 
Completed 100 requests 
Completed 200 requests 
Completed 300 requests 
Completed 400 requests 
Completed 500 requests 
Completed 600 requests 
Completed 700 requests 
Completed 800 requests 
Completed 900 requests 
Completed 1000 requests 
Finished 1000 requests 


Server Software:  Apache/2.4.16 
Server Hostname:  q.localhost 
Server Port:   80 

Document Path:   /test.php 
Document Length:  69600 bytes 

Server Software:  Apache/2.4.16 
Server Hostname:  q.localhost 
Server Port:   80 

Document Path:   /test.php 
Document Length:  69600 bytes 

Concurrency Level:  200 
Time taken for tests: 0.984 seconds 
Complete requests:  1000 
Failed requests:  0 
Total transferred:  69768000 bytes 
HTML transferred:  69600000 bytes 
Requests per second: 1015.82 [#/sec] (mean) 
Time per request:  196.885 [ms] (mean) 
Time per request:  0.984 [ms] (mean, across all concurrent requests) 
Transfer rate:   69210.84 [Kbytes/sec] received 

完成ab從第E二次測試:

C:\work\apache24\bin>ab -n 1000 -c 200 http://q.localhost/test.php 
This is ApacheBench, Version 2.3 <$Revision: 1663405 $> 
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ 
Licensed to The Apache Software Foundation, http://www.apache.org/ 

Benchmarking q.localhost (be patient) 
Completed 100 requests 
Completed 200 requests 
Completed 300 requests 
Completed 400 requests 
Completed 500 requests 
Completed 600 requests 
Completed 700 requests 
Completed 800 requests 
Completed 900 requests 
Completed 1000 requests 
Finished 1000 requests 

Server Software:  Apache/2.4.16 
Server Hostname:  q.localhost 
Server Port:   80 
Document Path:   /test.php 
Document Length:  0 bytes 
Concurrency Level:  200 
Time taken for tests: 80.099 seconds 
Complete requests:  1000 
Failed requests:  0 
Total transferred:  168000 bytes 
HTML transferred:  0 bytes 
Requests per second: 12.48 [#/sec] (mean) 
Time per request:  16019.840 [ms] (mean) 
Time per request:  80.099 [ms] (mean, across all concurrent requests) 
Transfer rate:   2.05 [Kbytes/sec] received 

一個簡單的調用header功能帶來的性能下降到每秒12個請求。這讓我感到震驚。

爲什麼header()的功能如此之慢,而且有什麼我可以在我的配置中更改以解決它?

+0

非常有趣......我可以在我的(Ubuntu)機器上重現這一點。它不是與身體缺乏產出有關, '<?php echo'foo'; ?>'很快,但是<?php頭('HTTP/1.1 200 OK');回聲'foo'; ?>仍然很慢。 –

+0

如果將以下代碼追加到代碼中,會發生什麼情況? '沖洗(); ob_flush();' – Paolo

+0

@Paolo沒有幫助;根本不會改變結果。 (順便說一下,從邏輯上說,這些刷新應該是相反的,即'ob_flush(); flush()',因爲ob_緩衝區位於寫入緩衝區之前,儘管如此,這也沒有幫助。) –

回答

2

更新:在2017年,我終於到處備案a bug report


我可以重現此問題我自己的機器上(在Apache 2.4.12,無論是使用PHP 5.6或PHP 7.0 - 的行爲上是相同的),在看到一個呼叫分享您的「休克」以header()將腳本的性能降低兩個數量級。我仍然不知道發生了什麼;它絕對是應該不會正在發生。

不過,我至少可以提出如何解決它:

  • 在PHP 5.4及以上,使用http_response_code來設置,而不是header狀態代碼。
  • 如果您處於困擾PHP 5.3的可怕位置,請嘗試在傳遞給header的參數中使用小寫http而不是大寫HTTP。例如

    <?php header('http/1.1 200 OK'); ?> 
    

    在我的機器,這仍然設置狀態代碼(如the docs注,在header設置狀態代碼的特殊情況下的邏輯是不區分大小寫),但使得性能問題消失。

如果你想知道,是的,這種行爲是gibberingly瘋了,甚至比低理智底線,我從PHP期待。我將再探索一下,看看我能否弄清楚發生了什麼,但希望這至少能讓你和任何遇到這個問題的人解決他們直接的性能問題。

+2

Apache/2.4.17(Fedora)PHP/5.6.16 - 同樣的問題。那是......只是......言語讓我失望。這很瘋狂,但我很想知道原因。這意味着我們必須相應地改變[一些流行的圖書館](https://github.com/symfony/symfony/blob/master/src/Symfony/Component/HttpFoundation/Response.php#L340)? – Federkun

1

我只是試着用

ab -n 1000 -c 200 -H "Connection:close" http://localhost/test.php 

其中test.php的含有

<?php header('HTTP/1.1 200 OK'); ?> 

,輸出是:

This is ApacheBench, Version 2.3 <$Revision: 1706008 $> 
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ 
Licensed to The Apache Software Foundation, http://www.apache.org/ 

Benchmarking localhost (be patient) 
Completed 100 requests 
Completed 200 requests 
Completed 300 requests 
Completed 400 requests 
Completed 500 requests 
Completed 600 requests 
Completed 700 requests 
Completed 800 requests 
Completed 900 requests 
Completed 1000 requests 
Finished 1000 requests 


Server Software:  Apache/2.4.17 
Server Hostname:  localhost 
Server Port:   80 

Document Path:   /test.php 
Document Length:  3 bytes 

Concurrency Level:  200 
Time taken for tests: 0.364 seconds 
Complete requests:  1000 
Failed requests:  0 
Total transferred:  206000 bytes 
HTML transferred:  3000 bytes 
Requests per second: 2744.74 [#/sec] (mean) 
Time per request:  72.867 [ms] (mean) 
Time per request:  0.364 [ms] (mean, across all concurrent requests) 
Transfer rate:   552.16 [Kbytes/sec] received 

Connection Times (ms) 
       min mean[+/-sd] median max 
Connect:  0 4 6.7  0  19 
Processing:  1 66 72.9  34  330 
Waiting:  0 33 51.3  16  306 
Total:   1 69 74.7  37  348 

Percentage of the requests served within a certain time (ms) 
    50%  37 
    66%  87 
    75% 110 
    80% 129 
    90% 153 
    95% 219 
    98% 334 
    99% 347 
100% 348 (longest request) 

所以,似乎發送Connection: close頭解析問題。您應該使用ab並打開-k標誌。這就是瀏覽器在默認情況下所做的功能keep-alive。附:

ab -n 1000 -c 20 -k http://localhost/test.php 

加載時間正常。

但不要問我,爲什麼ab -n 1000 -c 200 http://q.localhost/test.php的輸出,其中包含test.php<?php header('HTTP/1.1 200 OK'); ?><?php header('http/1.1 200 OK'); ?>不同,因爲我真的不知道。

+0

是的,「保持活躍」的時間是正常的,所以這意味着,如果一個網站有這個頭,它應該在普通的瀏覽器中快速,但是對於「非正常」連接可能非常慢,例如。一個爬蟲,或一個沒有「保持活着」的特殊瀏覽器,對吧? – henry

相關問題