在很短的時間內,PHP 成爲了一種非常流行的開發 Web 應用程序的程序設計語言。對初學者來說,PHP 易於安裝和學習。對於有經驗的開發人員而言,PHP(從 V5 開始)提供了強大的面向對象特性。PHP 開發人員擁有龐大的羣體,大量的開源及商業庫和工具擴展了該核心語言的功能。PHP 能迅速產生可視化結果,因此備受衆人推崇。
與其他開發 Web 應用程序的腳本語言(包括 Perl、Python 和 Ruby)相似,每次 HTTP 請求調用時,PHP 代碼都會被解析和翻譯爲操作碼(PHP 引擎直接執行的原語指令 —— 類似於彙編語言)再執行。在要求很低或可忽略的情況下,服務器看上去能立即執行這個複雜的解釋過程。但是一旦處理的頁面增加,解釋 —— 從本質上說,重複工作 —— 就會對服務器造成很大的負擔。在某些情況下,“編譯” PHP 代碼的時間會遠遠超過執行該代碼所需的時間。因此,當需求增加時,您常常會自食其果,因爲處理這些不斷解釋和動態生成的頁面需要消耗更多的系統資源。
若您對處理器和 RAM 的預算沒有限制,那麼就大可不必通過優化應用棧(硬件、操作系統、數據庫、Web 服務器和 PHP 代碼)來保證站點的可響應性。然而,由於資金通常都是最缺乏的資源,所以改善性能是必不可少的。調優意味着對系統增加內存、修改操作系統參數、加速 Web 或數據庫服務器、提高代碼效率或者這其中的一些組合。每一項都有其各自的作用。
節約 CPU 週期的另一種方法是減少運行 PHP 應用程序所需的重複工作。當然,沒有必要每次都把同樣的 PHP 代碼翻譯一遍。PHP 代碼被翻譯成操作碼後,可以把它保存起來並重複使用 —— 直到原始代碼被修改。確實,緩存 —— 用於保存和重用 PHP 操作碼 —— 是幾種 PHP 加速器內部的機制,包括開源 Alternative PHP Cache (APC)、支持 PHP 的 Turck MMCache、XCache、eAccelerator 和商業 Zend Platform。後三類加速器能夠緩存和優化字節碼,這爲系統提供了更多的速度提升。
這個月,我將探究如何安裝、部署和配置 XCache。XCache 相對較新,但是很多站點使用它的效果都很好。此外,XCache 易於構建、安裝和配置,因爲它是做爲 PHP 擴展實現的。不需對 Apache 和 PHP 進行重編譯。
本文基於 XCache V1.2.0。它可爲 PHP V4.3.11 至 V4.4.4、PHP V5.1.x 至 V5.2.x 以及 PHP V6 的早期版本提供可靠支持(XCache 並不支持 PHP V5.0.x)。XCache 兼容 mod_php 和 FastCGI 但並不支持 Common Gateway Interface (CGI) 和命令行 PHP 解釋器。XCache 源代碼能構建在許多系統上,包括 FreeBSD、Sun Solaris、Linux® 和這裏所示的 Mac OS X。使用 Cygwin UNIX® 仿真環境或 Visual C,能在 Microsoft® Windows® 上構建 XCache。還可以爲 Cygwin 或原生 Win32 構建 XCache。後者與 PHP 的官方 Win32 版本兼容。
本文的演示基於 Apache V2.2.3、PHP V5.2.0、XCache V1.2.0(2006 年 10 月發佈)和 Mac OS X V10.4.8 Tiger 上的 Xcode V2.4.1。硬件平臺爲配有 2-GHz Intel® Core Duo 處理器和 2 GB RAM 的 Apple MacBook。
在開始之前,首先確保 PHP 正常安裝並覈實 phpize
是否位於 shell 的 PATH
下。同時,還需要一個 C 編譯器,例如 GNU Compiler Collection (GCC),和一組包含
make
和 m4
的開發工具。在 Mac OS X 上,免費的 Xcode 軟件開發環境提供了必需的構建工具。
完成以下操作步驟,在 Mac OS X 上構建、部署 XCache 並對其進行性能檢測。在其他平臺上構建 XCache 與之類似。如果使用 Linux,則其發行版可能已經包含了 XCache 或者已經將其以預先打包好的格式提供給您。
首先增加 Mac OS X 上留出的共享內存總量。要實現這一目的,需創建(或編輯)文件 /etc/sysctl.conf 並創建如下條目:
kern.sysv.shmmax=33554432 kern.sysv.shmmin=1 kern.sysv.shmmni=32 kern.sysv.shmseg=8 kern.sysv.shmall=8192 |
這些設置把共享內存總量增加到了 32 MB。如還需進一步擴展共享內存,可以把 kern.sysv.shmall
設定爲
kern.sysv.shmmax
除以硬件頁面大小。使用 sysctl hw.pagesize
能獲得硬件頁面大小。例如,假設需要 128 MB 的共享內存,那麼設定
kern.sysv.shmmax=134217728
並設定 kern.sysv.shmall=32768
。
重啓 Mac OS X 使修改生效。重啓後,檢驗新設置是否生效,鍵入:
sysctl -a | grep kern.sysv |
接下來,通過源代碼構建 XCache。從 http://xcache.lighttpd.net 處下載源代碼。下載完後解壓代碼,並轉換到 .tar 文件創建的新目錄。
$ cd /tmp $ wget http://210.51.190.228/pub/XCache/Releases/xcache-1.2.0.tar.gz $ tar xzf xcache-1.2.0.tar.gz $ cd xcache |
運行 phpize
爲編譯 XCache 做準備。
$ phpize Configuring for: PHP Api Version: 20020918 Zend Module Api No: 20020429 Zend Extension Api No: 20050606 |
運行 configure
,創建適合於原生操作系統的 makefile。
清單 4. 運行 configure
創建 makefile
$ ./configure --enable-xcache --enable-xcache-coverager checking build system type... i686-apple-darwin8.8.1 checking host system type... i686-apple-darwin8.8.1 ... creating libtool configure: creating ./config.status config.status: creating config.h |
此處,--enable-xcache
選項包含 XCache 支持,--enable-xcache-coverager
選項包含用於測量加速器功效的附加特性。要啓用操作碼優化,添加
--enable-xcache-optimizer
。
當然,下一步將使用 make
命令行構建和安裝代碼。運行 make
,然後作爲 root 用戶運行
make install
。
$ make ... cp ./xcache.so /Users/strike/tmp/xcache/modules/xcache.so Build complete. $ sudo make install Installing shared extensions: /usr/lib/php/extensions/no-debug-non-zts-20020429/ |
如果上述兩項操作順利完成,那麼 XCache 將位於 /usr/lib/php/extensions/no-debug-non-zts-20020429/xcache.so。(路徑 /usr/lib/php/extensions/no-debug-non-zts-20020429 反映了正在使用的 API 版本和用於構建 PHP 的編譯選項。如果啓用了試用的 Zend Thread Safety 特性,則 "no-debug" 應爲 "debug","non-zts" 應爲 "zts"。)
因爲安裝了擴展,所以必需修改 php.ini 文件,使之包含 XCache 擴展並對其進行配置。打開文件 /private/etc/php.ini,在其中添加如下代碼行:
清單 6. 爲 XCache 擴展修改 php.ini 文件
[xcache-common] zend_extension = /usr/lib/php/extensions/no-debug-non-zts-20020429/xcache.so [xcache.admin] ; Change xcache.admin.user to your preferred login name xcache.admin.user = "admin" ; Change xcache.admin.pass to the MD5 fingerprint of your password ; Use md5 -s "your_secret_password" to find the fingerprint xcache.admin.pass = "0ad72f3f352fcd8acdf266bafd0ac48d" [xcache] ; Change xcache.size to tune the size of the opcode cache xcache.size = 24M xcache.shm_scheme = "mmap" xcache.count = 2 xcache.slots = 8K xcache.ttl = 0 xcache.gc_interval = 0 ; Change xcache.var_size to adjust the size of variable cache xcache.var_size = 8M xcache.var_count = 1 xcache.var_slots = 8K xcache.var_ttl = 0 xcache.var_maxttl = 0 xcache.var_gc_interval = 300 xcache.test = Off xcache.readonly_protection = On xcache.mmap_path = "/tmp/xcache" xcache.coredump_directory = "" xcache.cacher = On xcache.stat = On xcache.optimizer = Off [xcache.coverager] xcache.coverager = On xcache.coveragedump_directory = "" |
注意:爲了簡明起見,此處省略了一些註釋。要了解每個參數的含義,請參閱 XCache 源代碼中 xcache.ini 文件設置的例子。
操作碼和變量緩存的大小是 32 MB,這是 /etc/rc 留出的最大值。對於 Mac OS X,xcache.mmap_path
必須爲文件名。因爲 PHP 代碼將在 MacBook 上運行,所以
xcache.count
應設爲 2,表示 MacBook 中 CPU 的數量。要訪問 XCache 統計信息頁面,需改變
xcache.admin.pass
設置。運行:
$ md5 -s "password" |
此處 password
爲您的密碼。把輸出複製給 xcache.admin.pass
。例如,若需將密碼設定爲
op3nsesam3
,可以運行:
$ md5 -s "op3nsesam3" MD5 ("op3nsesam3") = cd959ac3debe8f587546a3fa353b3268 |
然後把 cd959ac3debe8f587546a3fa353b3268
複製給 xcache.admin.pass
。
設置好 XCache 後,重啓 Apache Web 服務器。對於大多數系統,可以以 root 用戶的身份使用 apachectl restart
進行重啓。
$ sudo apachectl restart /usr/sbin/apachectl restart: httpd restarted |
檢驗 XCache 是否已啓用,需創建一個小型 PHP 程序用於調用 phpinfo()
並在 Web 瀏覽器中打開那個文件。這樣就能看到類似下圖的 XCache 版面。
圖 1. phpinfo() 方法給出了 XCache 設置
要監控 XCache,需安裝 XCache 源代碼的 admin 目錄中的管理頁面。把整個 admin 目錄複製到 Apache 文檔根目錄下。通常來說,Mac OS X 中的文檔根目錄爲 /Library/WebServer/Documents。
$ cp -pr admin /Library/WebServer/Documents |
複製完成後,使用 sudo apachectl restart
重啓 Web 服務器。用瀏覽器打開 http://localhost/admin,檢驗管理面板是否工作正常。請參閱類似圖 2 的面板。
選擇一個或兩個應用程序進行測試。您可以使用自己的代碼或者,如果想要更復雜一點,使用大型的 PHP 應用程序,例如 phpMyAdmin 或者 Serendipity。
Apache HTTP Web 服務器提供了一個叫做 ab
的工具,即 Apache HTTP 服務器性能檢測(benchmark)工具的縮寫。ab
用於爲 PHP 頁面自動化處理大量的請求。phpMyAdmin 應用程序將會是一個很好的選擇,因爲它很可能已經安裝到您的系統上了。
ab
工具易於使用:只需提供給它一個重複數和一個 URL。ab
工具對這個 URL 提交若干次請求並返回統計信息。由於 XCache 已啓用,所以第一個性能檢測顯示了加速後的性能。
在運行 ab 之前,用瀏覽器導航到 http://localhost/phpmyadmin/。訪問這個 PHP 頁面一次,便會加載用來將此頁呈現到緩存內的所有 PHP 代碼。此時,運行如下的性能檢測,重複 100000 次。
$ ab -n 100000 http://localhost/phpmyadmin ... Concurrency Level: 1 Time taken for tests: 14.597 seconds Complete requests: 100000 Failed requests: 98262 (Connect: 49131, Length: 49131, Exceptions: 0) Broken pipe errors: 0 Non-2xx responses: 50869 Total transferred: 25739714 bytes HTML transferred: 12005084 bytes Requests per second: 6850.72 [#/sec] (mean) Time per request: 0.15 [ms] (mean) Time per request: 0.15 [ms] (mean, across all concurrent requests) Transfer rate: 1763.36 [Kbytes/sec] received |
有用的統計信息包括每秒的請求數和完成所有測試的總時間。對於前者,值越大越好;對於後者,值越小越好。
現在,在 php.ini 文件中禁用 XCache,然後再一次運行性能檢測,如清單 8 所示。可以註釋掉對 XCache 擴展的引用,或者關閉所有的 XCache 特性。再次運行性能檢測之前,需重啓 Apache。
清單 8. 禁用 XCache 時的 phpMyAdmin 性能檢測
$ sudo apachectl restart $ ab -n 100000 http://localhost/phpmyadmin Concurrency Level: 1 Time taken for tests: 17.771 seconds Complete requests: 100000 Failed requests: 98256 (Connect: 49128, Length: 49128, Exceptions: 0) Broken pipe errors: 0 Non-2xx responses: 50872 Total transferred: 25741232 bytes HTML transferred: 12005792 bytes Requests per second: 5627.15 [#/sec] (mean) Time per request: 0.18 [ms] (mean) Time per request: 0.18 [ms] (mean, across all concurrent requests) Transfer rate: 1448.50 [Kbytes/sec] received |
此處,XCache 禁用之後,每秒的請求數有所下降,表示 Apache 服務器處理每個請求需更長的時間。運行整套測試所需的時間也因此增加了。
儘管這只是一個簡單的性能檢測 —— phpMyAdmin 連接數據庫的功能被禁用了,這樣能限制單獨解釋 PHP 的處理時間 —— 並且不是非常科學,但它確實向我們演示了使用 XCache 能夠完成哪些任務。對於微小的投入(欣慰地是,PHP 或 Apache 不需重編譯),XCache 能產生一個相對較大的回報。代碼越複雜,可能的受益也越大。
若想了解 XCache 是如何有效地運行的,請訪問 http://localhost/xadmin 並單擊 List PHP。您能看到緩存中的 PHP 文件列表,連同 cache hit、操作碼的代碼大小、源文件的字節大小,等等。圖 3 顯示了 XCache 專門爲 XAMPP 棧包構建時的結果。
前面已經提及,XCache 是許多加速器中的一種。在強大的 Zend 軟件中還有許多免費的開源替代方案和一個商業化產品可選。每種 PHP 加速器都有自己的系統需求,所以應主要根據現有的或預期的配置以及應用程序的特性選擇合適的加速器。從中推薦一種很難,但是安裝編譯器緩存是我建議您務必要做的。
除了緩存之外,還有許多其他途徑可以加速應用程序。可以通過刪除 PHP 引擎的一些很深奧的特性來簡化它。例如,若不需使用 TCP/IP V6 (IPv6) 網絡,便可在構建 PHP 時禁用該屬性。通過在 PHP 源代碼樹的頂部輸入
./configure --help
可以參閱 PHP 配置選項的完整列表。無論選擇哪一個配置選項,都應該將:
--enable-inline-optimization --disable-debug |
添加到最終的配置命令。前一選項使 PHP 有可能更快地執行(不需使用類似 Zend Engine 的軟件進行額外的操作碼優化);後一選項取消了 PHP 的調試模式,只有當需要解決 PHP 應用服務器本身的問題時才需開啓該模式。
當然,正如一些 C 應用程序,我們能利用 C 編譯器構建更佳的可執行程序。如果把 PHP 作爲 Linux 或 FreeBSD 上的 Apache Dynamic Shared Object (DSO) 在 x86 處理器上運行,需考慮在
CFLAGS
(存儲 C 編譯器選項的環境變量)中添加 -prefer-non-pic
選項。non-pic 會使用位置獨立的代碼構建 PHP 並能提供 10% 的性能提升。還可以使用
CFLAGS
中的 -march
確定處理器的類型,例如 -march=opteron
表示處理器類型爲 AMD Opteron。
提升速度的另一個途徑是操作碼優化。此處,Zend Engine 之類的軟件會優化編譯過程中產生的操作碼,這理論上會減少代碼執行的工作總量。
緩存和優化都是透明的,並不需額外的編程。要應用一些優化操作,執行結構分析,或檢查代碼在哪花費了時間。重複的工作既不經濟又運算緩慢,這顯然會產生瓶頸。通過代碼優化彌補週期的不足是很有價值的 —— 但是在結構分析之前不要嘗試進行任何優化。
在接下來的幾個月我將再次討論優化,會談及調試、快速正文搜索、交替 Web 服務器等內容。同時,還將研究一個或多個 PHP 加速器和操作碼優化器。實現 10% 到 200% 的性能提升只需幾個小時的優化和修補。想像一下您的機器利用這些空閒的週期能做多少事情吧!