天天看點

為 PHP 應用提速 Xcache

PHP 是一種腳本語言,常用于建立 Web 應用程式。它易于掌握,并能迅速生成可視化結果。然而,由于 PHP 是以解釋的方式執行的,是以 PHP 代碼每次執行時都會被解析和轉換成操作碼(opcode)。操作碼緩存能消除這項重複的工作,使 PHP 應用程式運作得更快。

在很短的時間内,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。

建構 XCache 的基本步驟

在開始之前,首先確定 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 使修改生效。重新開機後,檢驗新設定是否生效,鍵入:

$ 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。

$ ./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,在其中添加如下代碼行:

[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 設定。運作:

此處 password 為您的密碼。把輸出複制給 xcache.admin.pass。例如,若需将密碼設定為 op3nsesam3,可以運作:

MD5 ("op3nsesam3") = cd959ac3debe8f587546a3fa353b3268

然後把 cd959ac3debe8f587546a3fa353b3268 複制給 xcache.admin.pass。

設定好 XCache 後,重新開機 Apache Web 伺服器。對于大多數系統,可以以 root 使用者的身份使用 apachectl restart 進行重新開機。

/usr/sbin/apachectl restart: httpd restarted

檢驗 XCache 是否已啟用,需建立一個小型 PHP 程式用于調用 phpinfo() 并在 Web 浏覽器中打開那個檔案。這樣就能看到類似下圖的 XCache 版面。

要監控 XCache,需安裝 XCache 源代碼的 admin 目錄中的管理頁面。把整個 admin 目錄複制到 Apache 文檔根目錄下。通常來說,Mac OS X 中的文檔根目錄為 /Library/WebServer/Documents。

複制完成後,使用 sudo apachectl restart 重新開機 Web 伺服器。用浏覽器打開 http://localhost/admin,檢驗管理面闆是否工作正常。請參閱類似圖 2 的面闆。

測試應用程式

運作性能檢測

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。

$ sudo apachectl restart

Time taken for tests: 17.771 seconds

Failed requests: 98256

(Connect: 49128, Length: 49128, Exceptions: 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 配置選項的完整清單。無論選擇哪一個配置選項,都應該将:

添加到最終的配置指令。前一選項使 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% 的性能提升隻需幾個小時的優化和修補。想像一下您的機器利用這些空閑的周期能做多少事情吧!

參考資料

學習