日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > php >内容正文

php

PHP 性能分析

發布時間:2025/6/15 php 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 PHP 性能分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

什么是性能分析?

性能分析是衡量應用程序在代碼級別的相對性能。性能分析將捕捉的事件包括:CPU的使用,內存的使用,函數的調用時長和次數,以及調用圖。性能分析的行為也會影響應用性能。

影響的程度取決于基準測試?;鶞蕼y試在外部執行,用于衡量應用真實性能。所謂真實性能,即終端用戶所體驗的應用表現。

什么時候應該進行性能分析?

在考慮是否進行性能分析時,你首先要想:應用是否存在性能問題?如果有,你要進一步考慮:這個問題有多大?

如果你不這樣做,將會陷入一個陷阱——過早優化,這可能會浪費你的時間。

為了評斷應用是否存在性能問題,你應該確定性能目標。例如,100 個并發用戶的響應時間小于 1s 。然后,你需要進行基準測試,看是否達到這個目標。一個常見的錯誤是,在開發環境進行基準測試。事實上,你必須在生產環境進行基準測試。(實際生產環境或模擬的生產環境,后者很容易在 SaaS 實現(例如:OneAPM PHP 應用性能在線分析示例)。

用于基準測試的產品很多,包括 ab,siege 和 JMeter。我個人比較喜歡 JMeter 的功能集,但 ab 和 siege 更加易用。

一旦你確定應用存在性能問題,就需要分析其性能,實施改進,然后再一次進行基準測試,查看問題是否解決。每一次變更之后,你都該進行基準測試查看效果。如果你做了很多變更,卻發現應用性能有所下降,你就無法確定具體是哪一次變更導致了這個問題。

下圖是我定義的性能生命周期:

性能下降的一般原因

導致性能下降的一般原因中,有些相當出人意料。即便是像 PHP 這樣的高級語言,代碼的好壞也很少是問題的根源。在當今的硬件配置條件下,CPU 很少是性能限制的原因。常見的原因反而是:

數據存儲

  • PostgreSQL
  • MySQL
  • Oracle
  • MSSQL
  • MongoDB
  • Riak
  • Cassandra
  • Memcache
  • CouchDB
  • Redis

外部資源

  • APIs
  • 文件系統
  • 網絡接口
  • 外部流程

糟糕的代碼

選擇哪一種性能分析器?

在 PHP 世界里,有兩個截然不同的的性能分析器——主動和被動。

主動 VS 被動性能分析

主動分析器在開發過程中使用,由開發人員啟用。主動分析器收集的信息比被動分析器多,對性能的影響更大。通常,主動分析器不能用在生產環境中。XDebug 就是一種主動分析器。

因為無法在生產環境中使用主動分析器,Facebook 推出了一個被動分析器——XHProf。XHProf 是為了在生產環境中使用而打造的。它對性能的影響最小,同時收集足夠的信息用于診斷性能問題。XHProf 和 OneAPM 都是被動分析器。

通常,XDebug 收集的額外信息對于一般的性能問題分析并不必要。這意味著,被動分析器是用于不間斷性能分析的更佳選擇,即使是在開發環境中。

XHProf + XHGui

XHProf 由 Facebook 開發的,包含一個基本的用戶界面用于查看性能數據。此外,Paul Reinheimer 開發了 XHGui 和一個增強的用戶界面(UI)用于查看、比較和分析性能數據。

安裝

安裝 XHProf

XHProf 可通過 PECL 安裝,步驟如下:

$ pecl install xhprof-beta

該 pecl 命令將嘗試自動更新你的 php.ini 設置。pecl 嘗試更新的文件可以使用以下命令找到:

$ pecl config-get php_ini

它會在指定的文件(如果有的話)頂部增加新的配置行。你可能想把他們移到一個更合適的位置。

一旦你編譯了該擴展程序,您必須啟用它。為此,您需要在 PHP INI 文件添加以下代碼:

[xhprof] extension=xhprof.so

之后,結合 XHGui 就能輕松地執行性能分析與檢查。

安裝 XHGui

安裝 XHGui,必須直接從 git 獲取。該項目可以在 github 上找到,地址為https://github.com/perftools/xhgui

XHGui 要求:

  • PHP 5.3+
  • ext/mongo
  • composer
  • MongoDB (若只需要收集數據,則可選可不選;若需要數據分析,則為必選)

首先,克隆項目到任意位置。在基于 Debian 的 Linux 系統(例如 Ubuntu 等等),可能是 /var/www。在 Mac OS X 系統,可能是 /Library/WebServer/Documents。

$ cd /var/www $ git clone https://github.com/perftools/xhgui.git $ cd xhgui $ php install.php

最后一個命令是運行 composer 以安裝依賴并檢查 XHGui 緩存目錄的權限。如果失敗,你可以手動運行 composer install。

下一步,你可能需要創建配置文件。這一步很容易實現,可以使用在 /path/to/XHGui/config/config.default.php 下的默認配置文件。

如果你在本地運行 MongoDB,沒有身份驗證,則可能不需要這樣做。因為它將回退為默認值。而在多服務器環境中,你會需要一個所有服務器都能進行存儲的遠程 MongoDB 服務器,并進行恰當的配置。

為提高 MongoDB 的性能,你可以運行以下指令以添加索引:

$ mongo> use xhprof db.results.ensureIndex( { 'meta.SERVER.REQUEST_TIME' : -1 } ) db.results.ensureIndex( { 'profile.main().wt' : -1 } ) db.results.ensureIndex( { 'profile.main().mu' : -1 } ) db.results.ensureIndex( { 'profile.main().cpu' : -1 } ) db.results.ensureIndex( { 'meta.url' : 1 } )

其他配置

如果你不想在生產環境中安裝 mongo ,或無法讓 Web 服務器訪問 mongo 服務器,您可以將性能分析數據保存在磁盤中,再導入到本地 MongoDB 供以后分析。

為此,請在 config.php 中進行以下修改:

<?php 'save.handler' = 'file', 'save.handler.filename' => '/path/to/xhgui/xhprof-' .uniqid("", true). '.dat', ?>

改變文件中的 save.handler,然后取消批注 save.handler.filename ,為其賦一個恰當的值。

注意:默認每天只保存一個分析文件。

一旦分析數據的準備就緒,你就可以使用 XHGui 附帶的腳本導入之:

$ php /path/to/xhgui/external/import.php /path/to/file.dat

在此之后的步驟都相同。

運行 XHGui

XHGui 是以 PHP 為基礎的 Web 應用程序,你可以以 /path/to/xhgui/webroot 為根文件,設置一個標準的虛擬主機。

或者,你可以簡單地使用?PHP 5.4+ cli-server?例如:

$ cd /path/to/xhgui $ php -S 0:8080 -t webroot/

這將使 XHGui 在所有網絡接口都可通過 8080 端口進行通信。

運行性能分析器

運行分析器時,你需要在待分析的所有頁面包含 external/header.php 腳本。為此,你可以在 PHP ini 文件設置 auto_prepend_file 。你既可以直接在公共 INI 文件進行設置,也可以限制到單一的虛擬主機。

對于 Apache 服務器,添加以下代碼:

php_admin_value auto_prepend_file "/path/to/xhgui/external/header.php"

對于 Nginx 服務器,在服務器配置中添加以下代碼:

fastcgi_param PHP_VALUE "auto_prepend_file=/path/to/xhgui/external/header.php";

如果您使用 PHP 5.4+ cli-server(PHP -S),則必須通過命令行標記進行設置:

$ php -S 0:8080 -dauto_prepend_file=/path/to/xhgui/external/header.php

默認情況下,分析器運行時只分析(大約) 1% 的請求。這是由以下?external/header.php?代碼控制的:

<?php if (rand(0, 100) !== 42) { return; } ?>

如果你想分析每一個請求(例如,在開發階段),你可以將這段代碼注釋掉。如果你想讓分析 10% 的請求,你可以做如下改動:

<?php if (rand(0, 10) !== 4) {return; } ?>

這允許你對一小部分用戶請求進行分析,而不過多影響單個用戶或太多用戶。

如果你想在性能分析時進行手動控制,你可以這樣做:

<?php if (!isset($_REQUEST['A9v3XUsnKX3aEiNsUDZzV']) && !isset($_COOKIE['A9v3XUsnKX3aEiNsUDZzV'])) { return; } else {// Remove trace of the special variable from REQUEST_URI$_SERVER['REQUEST_URI'] = str_replace(array('?A9v3XUsnKX3aEiNsUDZzV', '&A9v3XUsnKX3aEiNsUDZzV'), '', $_SERVER['REQUEST_URI']);setcookie('A9v3XUsnKX3aEiNsUDZzV', 1); }if (isset($_REQUEST['no-A9v3XUsnKX3aEiNsUDZzV'])) { setcookie('A9v3XUsnKX3aEiNsUDZzV', 0, time() - 86400);return; } ?>

這段代碼會檢查一個隨機命名的 GET/POST/COOKIE 變量(在此例中為:A9v3XUsnKX3aEiNsUDZzV),同時創建一個同名的 Cookie ,用于分析該請求的整個過程,例如:表單提交后的重定向,Ajax 請求等等。

此外,它允許一個名為 no-A9v3XUsnKX3aEiNsUDZzV 的 GET/POST 變量來刪除 Cookie ,停止分析。

當然,我們歡迎大家嘗試使用 OneAPM 來為您的?PHP?和?Java?應用做免費的性能分析。OneAPM 獨有的探針能夠深入到所有 PHP 和 Java 應用內部完成應用性能管理和監控,包括代碼級別性能問題的可見性、性能瓶頸的快速識別與追溯、真實用戶體驗監控、服務器監控和端到端的應用性能管理。 OneAPM 可以追溯到性能表現差的 SQL 語句 Traces 記錄、性能表現差的第三方 API、Web 服務、Cache 等等。

使用 XHGui

XHGui 提供了許多協助性能評估的功能,既適用于單次運行,也能滿足聚合環境——讓你精確至具體問題、發現趨勢。

術語

為了提高 XHGui 的使用效率,你需要熟悉許多術語:

1.調用次數

函數調用的次數

2.[包含] 實際執行時間 (wt)

函數實際執行時間

3.[包含] CPU 使用/CPU 用時 (cpu)

運行該函數 CPU 所用時間

4.[包含] 內存使用 (mu)

目前該函數使用的內存量

5.[包含] 內存使用量峰值 (pmu)

函數使用的內存高峰

6.專一實際執行時間 (ewt)

7.專一 CPU 時間 (ecpu)

8.專一內存使用量 (emu)

9.專一內存使用量峰值 (epmu)

術語 2 至 5 都是包含型的測量指標(盡管不總是明確指出),這些指標會計算函數及其子函數的調用。術語 6 至 9 是專一型的測量指標——它們只計算函數本身的資源調用。所有的測量數值都是調用該函數后的累計值。(例如,如果一個函數調用兩次,第一次用時 900 毫秒,第二次,因為緩存的緣故,只耗時 40 毫秒,最終顯示的時間就是 940 毫秒)。

準備開始

一旦在 HTTP 服務器上運行 XHGui ,你首先會看到:

在頂部,你會看到一個菜單,它包含:

Recent — 近期大部分運行 (分頁)

Longest wall time — 根據實際執行時間從最慢的運行開始排序

Most CPU — 從占用 CPU 時間最多的運行開始排序

Most Memory — 從占用內存最多的運行開始排序

Custom View — 執行 MongoDB 自定義查詢

Watch Functions — 應該出現在審查頁面頂部的標記函數

Waterfall — 從實驗性視圖查看并發請求的相互影響

在本教程中,我選擇分析用 WordPress 搭建的網站性能?;ヂ摼W上多于18% 的網站都是基于 WordPress 搭建的,這意味著,即便是對 WordPress 很小的性能改進, 亦能產生巨大影響。

查看一次運行的性能數據

分析了幾個頁面的性能(或導入了文件)之后,你會看到它們羅列在 XHGui :

查看一次運行的性能數據,只需點擊日期。

通過單擊適當的表頭,你可以根據實際執行時間 (wt) , CPU 時間 (CPU) 、內存使用量 (mu) 或 內存使用量峰值 (pmu) 查看這些運行情況。從而輕易找出最慢的頁面。

單個性能頁面展示了相當多的信息。在左側可以看到運行的總體情況,以及運行時的環境數據,包括 GET (或 POST) 數據和服務器數據:

在右側,展示了 watch function 列表:

該表詳細列出了函數名稱,調用次數 ,專一實際執行時間 (ewt), 專一內存使用量(emu)、和專一內存使用峰值(epmu)。此外,你可能會注意到頁面頂部的兩個按鈕, “View Callgraph(查看調用圖)” 和 “Compare this run(對比此次運行)”。

接下來,我們看到兩個圖。圖一展示了專一實際執行時間最長的六個函數,該時間是用在函數本身的時間(不包含任何子函數調用所占的時間)。圖二展示內存使用量最大的六個函數。這些圖通常能將你指向性能瓶頸。

函數的細節在下方列出。如果將鼠標滑過圖中的圓柱,這些信息也將出現在提示框中。

最后,我們看到性能分析器收集到的大宗信息——函數列表:

該表包含一個浮動的標題欄(即便鼠標向下滾動,該欄目也會保持在屏幕頂端),包含函數名,調用次數,和前面提到的專一和包含的測量值。

默認情況下,該表按專一實際執行時間排序,時間最長者排在首位。通常你不會想改變這一次序,因為這讓你快速找出運行最慢的函數,除非你想看內存使用量。

當你想查看一個函數的運行情況時,點擊該函數,會跳轉到其詳細頁面。該頁面首先會遞歸展示函數本身的細節。接下來, “Parent Functions(父函數)” 部分列出所有直接調用該函數的函數。最后,“Child Functions(子函數)”列出該函數直接調用的其他函數。

父函數按照專一實際運行時間,列出標準列表數據。

你需要確定:是函數本身運行緩慢,還是調用它的次數太多導致累積的實際執行時間太長。通過檢查該函數的調用計數,然后回顧其父函數列表。

如果你覺得函數調用次數沒問題,你就要看看子函數運行情況。此處才是函數運行消耗時間的部分。

子函數只顯示包含測量值;這是因為你想很快找到耗時最長的代碼路徑。

你可以點擊每個子函數,下鉆到相同的細節視圖,并進行相同的分析。

比較性能數據

XHGui 最好的特性在于比較兩個不同的運行。這使你:

  • 修改系統 (如啟用 OpCache, MySQL 查詢緩存) 并比較結果
  • 修改代碼(代碼或 SQL 優化)并比較結果
  • 將異常的運行與“正?!边\行比較

比較兩個運行時,你必須首先選擇一個基礎運行。點擊其日期就能看到該運行的詳細信息頁。

接下來,單擊右上角的 “Compare this run” 按鈕:

接著會跳轉到同一 URL 下的運行列表,你可以選擇一個進行比較:

點擊你想進行比較的運行的 "Compare" 按鈕,將跳轉到比較頁面。

比較視圖只顯示兩個運行之間的差異。在頁面頂部顯示比較中的兩個運行,以及一些輔助修改排序的按鈕。

接下來是概覽:

盡管這個表的所有信息都有用,但特別值得注意的兩個差別是 "函數調用次數" 和 "專一實際運行時間" 。

函數調用次數的差別暗示著兩次運行的重要差異:不同的代碼路徑或緩存。第一個差別可能是有意的優化導致的,但若這并非你的目的,比較這兩個運行很可能不會有太大的價值。另一方面,緩存是有益且有效的提高性能的方式。這種比較很容易驗證緩存是否發生。

包含實際執行時間的百分比差展示了性能調優的實際成果。理想情況下,我們將看到一個較小的百分比——這是第二運行時間比上第一次運行時間的占比。在截圖中,第二次運行只花了第一次運行 79% 的時間,這意味著性能提升了 21%。

最后,我們看到功能細節:

請記住,該視圖只展示差別。差別通過綠色的負數和紅色的正數表示。(負數表明調用次數更少,實際執行時間更短,CPU 耗時更短或內存消耗更少)如果沒有差異,則顯示為灰色的 0。

與其他表一樣,您可以在任意列進行排序,默認的順序方式是函數的調用次序。

在這里你可以驗證,你做的改變是否確有效果,是否為預期效果。你也可以在性能下降時使用該視圖追蹤原因。

性能提高的一個好例子是:基于一個條件只調用一個函數——例如,您可能不需要過濾數據,如果之前已經做了。

當你做出這種改變時,你會預期過濾函數的調用次數減少,從而性能提升。

這兩件事都可以在此處得到驗證,以及其他意想不到的原因——你的條件比過濾本身需要更長的時間?如果真是如此,這將對性能產生負面影響。

在此處,我們可以看到, NOOP_Translations::translate 和 apply_filter 的調用次數都減少了,但是 apply_filter 的專一內存使用量增加了 133560 個字節!

發現趨勢

對我來說,XHGui 最強大的功能是查看趨勢。因為 XHProf 是被動分析器,可以在所有環境中啟用 (dev、qa、階段性、生產),可以持續地對流量取樣分析。

審查給定 URL 的所有數據,只需在運行列表點擊它:

這將跳轉到該 URL 運行頁面。

該頁面顯示兩個重要圖表。第一個顯示實際運行時間和 CPU 時間,第二個顯示內存使用情況和峰值內存使用。這些圖表列表中運行的數據,包括每次運行的 URL,時間,實際運行時間、CPU 時間、內存使用和峰值。

這些圖是查看趨勢和異常值的關鍵所在。但是該如何處理這些信息呢?

對于數據異常者,首先你可以將鼠標懸浮在它上面驗明正身,接著,你可以看一下它的單次運行?;蛴闷渌_\行與其比較,從而發現不同。

對于趨勢,最好的選擇是審查趨勢開始的時間——你在此時添加緩存了嗎?隨著緩存變得更加完整,整體趨勢應該向下?;蛘吣愕木彺媸?#xff0c;你將看到一個上升趨勢,此時緩存正在重建。

默認情況下,這些圖表顯示最近 100 次運行,你可以點擊下一頁去查看更久遠時間的運行。

另外,你可以點擊搜索按鈕來定制顯示的界面:

單擊該按鈕將顯示搜索表單:

你可以搜索具體日期之間的運行。也可以查看最近 30分鐘、1小時、2小時、12小時、24小時、1周、2周或 30天內 的運行——更小的時間間隔適合評估性能調優的結果。

最后,你可以使用 PHPs DateTimeIntervalInterval?規范格式指定自定義時間區間——例如,最近 2天 可使用 P2D,最近 15分鐘 可使用 PT15M。

Watch Functions

Watch functions 允許你通過正則表達式識別特定的函數,或函數組,并顯示在單個運行頁面(見前文)。

因為可以使用正則表達式,我們可以輕易地查看一個模塊或擴展中的功能。

例如,查看所有 MySQL 活動,只需添加如下列表的任意一項:

  • mysql_(.*)for ext/mysql
  • mysqli(.*)for ext/mysqli
  • pdo(.*)for PDO (適用于所有 PDO-based 數據庫交互)

如果你使用諸如 Propel 的 ORM,你可能使用?(.*)Query::(.*)?追蹤所有 Query 類。

調用圖(Callgraphs)

XHProf 的最后一部分是調用圖 ,該圖展示運行的代碼執行路徑。

點擊單一運行頁面頂部的“View Callgraph”按鈕即可查看調用圖。

在調用圖中,拖拽結點可以更好地查看數據。鼠標懸浮在每個點擊上,會顯示其包含實際執行時間,同時允許你進入該函數的詳情頁。

性能調優

不用運行的代碼才是絕好的代碼。其他只是好的代碼。所以,性能調優時,最好的選擇是首先確保運行盡可能少的代碼。

OpCode 緩存

首先,最快且最簡單的選擇是啟用 OpCode 緩存。OpCode 緩存的更多信息可以在?這里?找到。

在上圖,我們看到啟用 Zend OpCache 后發生的情況。最后一行是我們的基準,也即沒有啟用緩存的情況。

在中間行,我們看到較小的性能提升,以及內存使用量的大幅減少。小的性能提升(很可能)來自 Zend OpCache 優化,而非 OpCode 緩存。

第一行是優化和 OpCode 緩存后結果,我們看到很大的性能提升。

現在,我們看看 APC 之前和之后的變化。如上圖所示,跟 Zend OpCache 相比,隨著緩存的建立,我們看到初始(中間行)請求的性能下降,在消耗時長與內存使用量方面的表現都明顯下降。

接著,隨之 opcode 緩存的建立,我們看到類似的性能提升。

內容緩存

第二件我們能做的事是緩存內容——這對 WordPress 而言小菜一碟。它提供了許多安裝簡便的插件來實現內容緩存,包括 WP Super Cache。WP Super Cache 會創建網站的靜態版本。該版本會在出現諸如評論事件時依照網站設置自動過期。(例如,在非常高負載情況下,您可能會想禁止任何原因造成的緩存過期)。

內容緩存只能在幾乎沒有寫操作時有效運行,寫操作會使緩存失效,而讀操作不會。

你也應該緩存應用從第三方 API 處收到的內容,從而減少由于 API 可用性導致的延遲與依賴。 ? WordPress 有兩個緩存插件,可以大大提高網站的性能:?W3 Total Cache?和?WP Super Cache。

這兩個插件都會創建網站的靜態 HTML 副本,而不是每次收到請求時再生成頁面,從而壓縮響應時間。

如果你正在開發自己的應用程序,大多數框架都有緩存模塊:?

  • Zend Framework 2:Zend\Cache
  • Symfony 2:Multiple options
  • Laravel 4:Laravel Cache
  • ThinkPHP 3.2.3:ThinkPHP??Cache

查詢緩存

另一個緩存選項是查詢緩存。針對 MySQL,有一個通用的查詢緩存幫助極大。對于其他數據庫,將查詢結果集緩存在 Memcached 或者 cassandra 這樣的內存緩存,也非常有效。

跟內容緩存一樣,查詢緩存在包含大量讀取操作的場景是最有效的。由于少量的數據改動就會使大塊的緩存區無效,尤其不能在這種情況下依賴 MySQL 查詢緩存來提高性能。

查詢緩存或許在生成內容緩存時對性能有提升。

如下圖所示,當我們開啟查詢緩存后,實際運行時間減少了 40% ,盡管內存使用量沒有明顯改變。

現有三種類型的緩存選項,由?query_cache_type?控制設置。

  • 設置值為?0?或?OFF?將禁用緩存
  • 設置值為?1?或?ON?將緩存除了以?SELECT SQL_NO_CACHE?開頭之外的所有選擇
  • 設置值為?2?或?DEMAND?只會緩存以?SELECT SQL_CACHE?開頭的選擇

此外,你應該將?query_cache_size?設置為非零值。將它設置為零將禁用緩存,不管query_cache_type?是否設置。

想得到設置緩存的幫助,與許多其他性能相關的設置,請查看?mysql-tuning-primer?腳本。

MySQL 查詢緩存的主要問題是,它是全局的。對緩存結果集構成的表格的任何更改都將導致緩存失效。在寫入操作頻繁的應用程序中,這將使緩存幾乎無效。

然而,你還有許多其他選擇,可以根據你的需求和數據集建立更多的智能緩存,例如?Memcached?,?riak?,?cassandra?或?redis

查詢優化

如前所述,數據庫查詢常常是程序執行緩慢的原因,查詢優化往往能比代碼優化帶來更多切身的好處。

查詢優化有助于生成內容緩存時提高性能,而且,在無法緩存這種最壞的情況下也有益處。

除了分析, MySQL 還有一個幫助識別慢查詢的選擇——慢查詢日志。慢查詢日志會記錄所有耗時超過指定時間的查詢,以及不使用索引的查詢(后者為可選項)。

您可以在?my.cnf?中使用以下配置啟用日志。

[mysqld] log_slow_queries =/var/log/mysql/mysql-slow.log? long_query_time =1 log-queries-not-using-indexes

任何查詢如果慢于?long_query_time?(以秒為單位),該查詢就會記錄到日志文件log_slow_queries?中。默認值是10秒,最低1秒。

此外,?log-queries-not-using-indexes?選項可以將任何不使用索引的查詢捕獲到日志中。

之后我們可以用與 MySQL 捆綁在一起的?mysqldumpslow?命令檢查日志。

在 WordPress 安裝時使用這些選項 ,主頁加載完成并運行后得到如下數據:?

$ mysqldumpslow -g "wp_" /var/log/mysql/mysql-slow.logReading mysql slow query log from /var/log/mysql/mysql-slow.logCount: 1??Time=0.00s (0s) Lock=0.00s (0s) Rows=358.0(358), user[user]@[host] SELECT option\_name, option\_value FROM wp_options WHERE autoload ='S'Count: 1 Time=0.00s (0s) Lock=0.00s (0s) Rows=41.0(41), user[user]@[host] SELECT user\_id, meta_key, meta_value FROM wp_usermeta WHERE user_id IN (N)

首先,注意所有字符串值都以?S?表示,數字則以?N?表示。你可以添加?-a?標志來顯示這些值。?

接下來,請注意,這兩個查詢均耗時 0.00 s,這意味著他們的耗時在 1 秒的閾值以下,且沒有使用索引。

在 MySQL 控制臺 使用 EXPLAIN,可以檢查性能下降的原因:

????mysql> EXPLAIN SELECT option_name, option_value FROM wp_options WHERE autoload = 'S'\G*************************** 1. row ***************************id: 1select_type: SIMPLEtable: wp_optionstype: ALLpossible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: 433Extra: Using where

此處,我們看到?possible_keys?是 NULL,從而確認未使用索引。

EXPLAIN?是對優化 MySQL 查詢非常強大的工具,更多信息可以在?這里?找到。

PostgreSQL 同樣也包括一個 EXPLAIN (該 EXPLAIN 與 MySQL 的差別很大),而 MongoDB 有$explain 元 操作符。

代碼優化

通常只有當你不再受到 PHP 本身限制(通過使用 OpCode 緩存),緩存了盡可能多的內容,優化了查詢之后,才可以開始調整代碼。

代碼和查詢優化帶來足夠的性能提升才能創建其他緩存;代碼在最糟糕的環境(沒有緩存)下性能越高,應用就越穩定,重建緩存的速度也就越快。

讓我們看看如何(潛在地)優化我們的 WordPress 安裝。

首先,讓我們看看最慢的函數:?

令我驚訝的是,列表中的第一項?不是?MySQL (事實上?mysql_query()?是第四),而是apply_filter()?函數。

WordPress 代碼庫的特點是,通過基于事件的過濾系統執行多種數據轉換,執行次序按照數據經內核、插件添加或回調的順序。

apply_filter()?函數是這些回調應用的地方。

首先,你可能會注意到,函數被調用 4194 次。如果我們點擊查看更多細節,就可以按照“調用次數”降序排列“父函數”,從而發現?translate()?調用了apply_filter()?函數 778 次。

這很有趣,因為實際上我不使用任何翻譯。我(并懷疑大多數用戶)在使用 WordPress 軟件時都設置為本土語言:英語。

因此,讓我們點擊查看細節,進一步查看該?translate()?函數在做什么。

在這里,我們看到兩間有趣的事。首先,在父函數中,有一個被調用了773次:__()。

查看該函數的源代碼后,我們發現它是?translate()?的包裝器。

????<?php/***?Retrieves the translation of $text. If there is no translation, or*?the domain isn't loaded, the original text is returned.**?@see translate() An alias of translate()*?@since 2.1.0**?@param string $text Text to translate*?@param string $domain Optional. Domain to retrieve the translated text*?@return string Translated text*/function __( $text, $domain = 'default' ) {return translate( $text, $domain );}?>

根據經驗法則,函數調用代價昂貴,應該盡量避免?,F在我們總是調用 __() 而不是translate()?,我們應該把別名改為?translate()?來保持向后兼容性,而 __() 則不再調用非必要的函數。

然而,實際上,這種改變不會帶來多大的差異,只是微觀的優化罷了——但它的確提高了代碼可讀性,簡化了調用圖。

繼續前進,讓我們看看子函數:

現在,深入該函數,我們看到有 3 個 函數或方法被調用,每個 778 次:

  • get_translations_for_domain()
  • NOOP_Translations::translate()
  • apply_filters()

按照包容性實際運行時間降序排列,我們看到?apply_filter()?是目前為止耗時最長的調用。

查看代碼:

????<?phpfunction translate( $text, $domain = 'default' ) {$translations = get_translations_for_domain( $domain );return apply_filters( 'gettext', $translations->translate( $text ), $text, $domain );}?>

這段代碼的作用是檢索一個翻譯對象,然后將 $translations->translate() 的結果傳給apply_filter()?。我們發現 $translations 是?NOOP_Translations?類的一個實例。

僅根據名稱(NOOP),再經代碼中的注釋證實,我們發現翻譯器實際上沒有任何動作!

????<?php/***?Provides the same interface as Translations, but doesn't do anything*/class NOOP_Translations {?>

因此,也許我們完全可以避免這種代碼!

通過在代碼上進行小規模調試,我們看到當前使用的是默認的域,我們可以修改代碼以忽略翻譯器:

????<?phpfunction translate( $text, $domain = 'default' ) {if ($domain == 'default') {return apply_filters( 'gettext', $text, $text, $domain );}$translations = get_translations_for_domain( $domain );return apply_filters( 'gettext', $translations->translate( $text ), $text, $domain );}?>

接下來,我們再次分析,確保要運行至少兩次——確保所有緩存都建立,才是公平的對比!

這次運行的確更快!但是,快多少?為什么?

使用 XHGui 的比較運行這一特性就能找到答案。回到我們最初的運行,點擊右上角的 “比較此處運行” 按鈕,并從列表中選擇新的運行。

我們發現,函數調用的次數減少了3% ,包容性實際運行時間減少 9% ,包容性CPU時間減少12%!?

之后,可以按調用次數降序排列細節頁,這證實(如同我們的預期)get_translations_for_domain()?和?NOOP_Translations::translate()?函數的調用次數減少。同樣,可以確認沒有預料之外的變化發生。

30 分鐘的工作帶來9 - 12% 的性能提升,這非??上?。這就意味著真實世界的性能收益,即便是在應用了 opcache 之后。

現在我們可以對其函數重復這個過程,直到找不到更多優化點。

注意:此更改已提交到 WordPress.org 并已獲更新。你可以在?WordPress Bug Tracker跟蹤討論,查看實踐過程。此更新計劃包含在 WordPress 4.1 版本中。

其他工具

除了出色的 XHProf/XHGui,還有一些很好的工具。

New Relic & OneAPM

New Relic?與?OneAPM? 均提供前后端性能分析;洞察后臺堆棧訊息,包括 SQL 查詢與代碼分析,前端 DOM 與 CSS 呈現,以及 Javascript 語句。OneAPM?更多功能請移步 (OneAPM 在線DEMO)?

uprofiler

uprofiler?是目前還未發布的 Facebook XHProf 分支,該分支計劃刪除 Facebook 所需的 CLA。目前,兩者具備相同的特性,只有一些部分重命名了。

XHProf.io

XHProf.io?是 XHProf 的另一種用戶界面。XHProf.io 在配置文件存儲使用 MySQL ,用戶友好性方面不及 XHGui。

Xdebug

在 XHProf 出現之前,Xdebug?早已存在——Xdebug 是一種主動的性能分析器,這意味著它不應該用于生產環境,但可以深入了解代碼。

然而,它必須與另一個工具配合使用以讀取分析器的輸出 , 比如?KCachegrind。但是 KCachegrind 很難安裝在非 linux 機器上。另一個選擇是?Webgrind。

Webgrind 無法提供 KCachegrind 的那些特性,但它是一個 PHP Web 應用程序,在任何環境都易于安裝。

若搭配 KCachegrind ,你可以輕易探索并發現性能問題。(事實上,這是我最喜歡的剖析工具!)

結語

分析和性能調優是非常復雜的工程。有了對的工具,并理解如何善用這些工具,我們可以很大程度地提高代碼質量——即使是對我們不熟悉的代碼庫。

花時間去探索和學習這些工具是絕對值得的。



總結

以上是生活随笔為你收集整理的PHP 性能分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。