1. 程式人生 > >php.ini 配置調優 —— 讓 PHP 應用效能維持在更高水平

php.ini 配置調優 —— 讓 PHP 應用效能維持在更高水平

預設安裝的 PHP 就像是在百貨商店裡購買的普通套裝,雖然合身,卻不完美。調優的 PHP 就像是定做的套裝,完全匹配你的尺寸。不過,需要注意的是,調優 PHP 只是提升 PHP 效能和效率的舉措,對拙劣的程式碼和無響應的 API 呼叫無計可施。

php.ini檔案

PHP 直譯器在 php.ini 檔案中配置和調優,這個檔案在不同作業系統中的位置有所不同,而且一般命令列對應的 php.ini 和 PHP-FPM 對應的 php.ini檔案是分開的。這裡我們假設配置的是 PHP-FPM 對應的 php.ini,但是下面講的優化措施適用於所有php.ini

注:我們首先應該使用 PHP Iniscan工具掃描 php.ini,檢查使用了安全方面的最佳實踐。

記憶體

執行 PHP 時需要關心每個 PHP 程序要使用多少記憶體, php.ini中的 memory_limit設定用於設定單個 PHP 程序可以使用的系統記憶體最大值。

這個設定的預設值是 128M,這對於大多數中小型 PHP 應用來說或許合適,不過,如果執行的是微型 PHP 應用,可以降低這個值,以便節省系統資源,反之,如果執行的是記憶體集中型 PHP 應用,可以增加這個值。這個值的大小由可用的系統記憶體決定,確定給 PHP 分配多少值是一門藝術,決定給 PHP 分配多少記憶體,以及能負擔起多少個 PHP-FPM 程序時,可以根據以下維度資訊進行判斷:

 


  • 一共可以分配給 PHP 多少記憶體?以一個 2G 記憶體的 VPS 為例,這臺裝置中可能還運行了其他程序,如 MySQL、Nginx 等,那麼留 512M 給 PHP 是合適的。
  • 每個 PHP 程序平均耗費多少記憶體?這個要監控程序的記憶體使用量,可以使用命令列命令 top,也可以在 PHP 指令碼中呼叫memory_get_peak_usage()函式,不管使用哪種方式,都要多次運行同一個指令碼,然後取記憶體消耗的平均值。
  • 能負擔起多少個 PHP-FPM 程序?假設我給 PHP 分配了 512M 記憶體,每個 PHP 程序平均耗費 15M 記憶體,那麼可以負擔起 34 個 PHP-FPM 程序。
  • 有足夠的系統資源嗎?最後還需要確認有足夠的系統資源執行 PHP 應用並處理預期的流量。 

 

注:我們應該使用 Apache Bench 或 Siege 在類似生產環境的條件下對 PHP 應用做壓力測試,以確定生產環境是否有足夠的資源可用。

Zend OPcache

確定要分配多少記憶體後,就可以配置 PHP 的 Zend OPcache 擴充套件,關於這個擴充套件的詳細資訊可參考這篇文章:http://laravelacademy.org/post/4396.html

PHP 5.5.0+ 內建了這個擴充套件,下面是在 php.ini 檔案中配置和優化 Zend OPcache 擴充套件所用的設定:

  • opcache.memory_consumption = 64:為操作碼快取分配的記憶體(單位是MB),分配的記憶體量應該可以儲存應用中所有 PHP 指令碼編譯得到的操作碼,這個值根據應用的體量可以設定成不同大小的值。
  • opcache.interned_strings_buffer = 16:用來儲存駐留字串的記憶體量(單位是MB),什麼是駐留字串呢?PHP 直譯器在背後會找到相同字串的多個例項,把這個字串儲存在記憶體中,如果再次使用相同的字串,PHP 直譯器會使用指標,這麼做的目的是節省記憶體。預設情況下,PHP 駐留字串會隔離在各個 PHP 程序中,這個設定能讓 PHP-FPM 程序池把所有程序駐留字串儲存到共享的緩衝區中,以便在 PHP-FPM 程序池中的多個程序之間引用駐留字串,這樣能節省更多記憶體。
  • opcache.max_accelerated_files = 4000:操作碼快取中最多能儲存多少個 PHP 指令碼,這個值的區間是 2000 到 100000 之間,這個值一定要比 PHP 應用中的檔案數大。
  • opcache.validate_timestamps = 1:這個設定的值為1時,經過一段時間後 PHP 會檢查 PHP 指令碼的內容是否有變化,檢查的時間間隔由 opcache.revalidate_freq 設定指定。如果這個設定的值為0,PHP 不會檢查 PHP 指令碼的內容是否有變化,我們必須自己動手清除快取的操作碼。建議在開發環境中設定為1,生產環境中設定為0。
  • opcache.revalidate_freq = 0:設定多久(單位是秒)檢查一次 PHP 指令碼內容是否有變化。設定為0秒的含義是僅當opcache.validate_timestamps 設定為1時,才會在每次請求時都重新驗證 PHP 檔案,因此,在開發環境中每次都會重新驗證 PHP 檔案,在生產環境中則不驗證。
  • opcache.fast_shutdown = 1:這麼設定能讓操作碼使用更快的停機步驟,把物件析構和記憶體釋放交給 Zend Engine 的記憶體管理器完成。

檔案上傳

如果你的應用允許上傳檔案,最好設定最大能上傳的檔案大小。除此之外,最好還要設定最多能同時上傳多少個檔案:

file_uploads = 1
upload_max_filesize = 10M
max_file_uploads = 3
  • 1
  • 2
  • 3

預設情況下,PHP 允許在單次請求中上傳 20 個檔案,上傳的檔案最大為 2MB,這裡我設定為單次請求最多隻能上傳 3 個檔案,每個檔案最大為 10MB,這個值不要設定太大,否則會出現超時。

注:如果非要上傳大檔案,Web 伺服器的配置也要做相應調整。除了在 php.ini 中設定之外,還要調整 Nginx 虛擬主機配置中的 client_max_body_size 設定。

最長執行時間

php.ini 檔案中的 max_execution_time 用於設定單個 PHP 程序在終止之前最長可執行時間。這個設定預設是 30 秒,建議將其設定為 5 秒:

max_execution_time = 5

注:在 PHP 指令碼中可以呼叫 set_limit_time() 函式覆蓋這個設定。

假設我們想要生成報告,並把結果製作成 PDF 檔案,這個任務可能要花 10 分鐘才能完成,而我們肯定不想讓 PHP 請求等待 10 分鐘,我們應該單獨編寫一個 PHP 檔案,讓其在單獨的後臺程序中執行,Web 應用只需幾毫秒就可以派生一個單獨的後臺程序,然後返回 HTTP 響應:

<?php
exec('echo "create-report.php" | at now');
echo 'report pending...';
  • 1
  • 2
  • 3

create-report.php 在單獨的後臺程序中執行,執行完畢後可以更新資料庫,或者通過電子郵件把報告發給收件人。不過這種用法很少見,更多時候我們是通過非同步消費佇列來實現類似的功能,無論從安全性、擴充套件性、可維護性上來講,效果更好,相關的元件有輕量級訊息佇列 PHPResque 等。

處理會話

PHP 預設的會話處理程式會拖慢大型應用,因為這個處理程式會把會話資料儲存在硬碟中,需要建立不必要的磁碟 I/O,浪費時間。我們應該把會話資料儲存在記憶體中,例如可以使用 Memcached 或 Redis。這麼做還有個額外好處 —— 以後便於伸縮。如果會話資料儲存在硬碟中,不便於增加額外的伺服器,如果把會話資料存放在 Memcached 或 Redis 裡,任何一臺分散式 PHP-FPM 伺服器都能訪問會話資料。

如果想把會話資料儲存在 Memcached 中,需要做如下配置:

session.save_handler = 'memcached'
session.save_path = '127.0.0.1:11211'
  • 1
  • 2

緩衝輸出

如果是在較少的塊中傳送更多資料,而不是在較多的塊中傳送較少的資料,那麼網路的效率會更高,也就是說,在較少的片段中把內容傳遞給訪問者的瀏覽器,能減少 HTTP 請求總數。

因此,我們要讓 PHP 緩衝輸出,預設情況下,PHP 已經啟用了輸出緩衝功能,PHP 緩衝 4096 位元組的輸出之後才會把內容傳送給 Web 伺服器,推薦配置如下:

output_buffering = 4096
implicit_flush = false
  • 1
  • 2

注:如果想要修改輸出緩衝區的大小,確保使用的值是4(32位系統)或8(64位系統)的倍數。

真實路徑快取

PHP 會快取應用使用的檔案路徑,這樣每次包含或匯入檔案時就無需不斷搜尋包含路徑了,這個快取叫真實路徑快取(realpath cache),如果執行的是大型的 PHP 檔案(如 Composer 元件),使用了大量檔案,增加 PHP 真實路徑快取的大小能得到更好的效能。

真實路徑快取的預設大小是 16K,這個快取所需的準確大小不容易確定,不過可以使用一個小技巧:首先,增加真實路徑快取的大小,設定為特別大的一個值,如 256K,然後,在一個 PHP 指令碼的末尾加上 print_r(realpath_cache_size());,輸出真實路徑快取的真正大小,最後,把真實路徑快取的大小改為這個真正的值。我們可以在 php.ini 檔案中設定真實路徑快取的大小:

realpath_cache_size = 64K