默認情況下安裝的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 擴展
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〜100,000。此值必須大於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
默認情況下,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...';
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'
緩衝輸出
如果在更少的塊中發送更多的數據,而不是在更多的塊中發送更少的數據,則網絡將更加高效,也就是說,以更少的片段瀏覽器傳遞內容以進行訪問,這可以減少HTTP請求的總數。
因此,我們必須讓PHP緩衝輸出。默認情況下,PHP已啓用輸出緩衝功能,並且PHP將在緩衝4096字節的輸出後將內容發送到Web服務器。
output_buffering = 4096
implicit_flush = false
注:如果想要修改輸出緩衝區的大小,確保使用的值是4(32位系統)或8(64位系統)的倍數。
真實路徑緩存
PHP 會緩存應用使用的文件路徑,這樣每次包含或導入文件時就無需不斷搜索包含路徑了,這個緩存叫真實路徑緩存(realpath cache),如果運行的是大型的 PHP 文件(如 Composer 組件),使用了大量文件,增加 PHP 真實路徑緩存的大小能得到更好的性能。
真實路徑緩存的默認大小爲16K。此緩存所需的確切大小不易確定,但可以使用一些技巧:首先,增加實際路徑高速緩存的大小並將其設置爲特別大的值,例如256K。最後在php腳本末尾添加上 print_r(realpath_cache_size());
,輸出真實路徑緩存的真正大小,最後,把真實路徑緩存的大小改爲這個真正的值。我們可以在 php.ini
文件中設置真實路徑緩存的大小:
realpath_cache_size = 64K