跳到內容

效能

編輯此頁面

Symfony 開箱即用就很快。但是,如果您按照以下效能檢查清單中的說明,最佳化您的伺服器和應用程式,您可以使其更快。

效能檢查清單

使用這些檢查清單來驗證您的應用程式和伺服器是否已設定為達到最佳效能

如果您的伺服器使用 APC,請安裝 APCu Polyfill

如果您的生產伺服器仍然使用舊版的 APC PHP 擴充功能而不是 OPcache,請在您的應用程式中安裝 APCu Polyfill 元件,以啟用與 APCu PHP 函數 的相容性,並解鎖對進階 Symfony 功能的支援,例如 APCu 快取適配器。

限制應用程式中啟用的語系數量

使用 framework.enabled_locales 選項,僅產生應用程式中實際使用的翻譯檔案。

將服務容器傾印到單一檔案中

Symfony 預設會將 服務容器 編譯成多個小型檔案。將此參數設定為 true,將整個容器編譯成單一檔案,這可以在 PHP 7.4 或更新版本中使用「類別預先載入」時提高效能

1
2
3
4
# config/services.yaml
parameters:
    # ...
    .container.dumper.inline_factories: true

提示

. 前綴表示僅在容器編譯期間使用的參數。請參閱 組態參數 以取得更多詳細資訊。

使用 OPcache 位元組碼快取

OPcache 儲存編譯後的 PHP 檔案,以避免在每次請求時都必須重新編譯它們。有一些可用的 位元組碼快取,但從 PHP 5.5 開始,PHP 內建了 OPcache。對於舊版本,最廣泛使用的位元組碼快取是 APC。

使用 OPcache 類別預先載入

從 PHP 7.4 開始,OPcache 可以在啟動時編譯和載入類別,並使其在伺服器重新啟動之前可供所有請求使用,從而顯著提高效能。

在容器編譯期間(例如,當執行 cache:clear 命令時),Symfony 會在 var/cache/ 目錄中產生一個包含要預先載入的類別清單的檔案。與其直接使用此檔案,不如使用 在您的專案中使用 Symfony Flex 時 建立的 config/preload.php 檔案

1
2
3
4
5
; php.ini
opcache.preload=/path/to/project/config/preload.php

; required for opcache.preload:
opcache.preload_user=www-data

如果此檔案遺失,請執行此命令來更新 Symfony Flex 配方:composer recipes:update symfony/framework-bundle

使用 container.preloadcontainer.no_preload 服務標籤,以定義哪些類別應該或不應該由 PHP 預先載入。

設定 OPcache 以達到最佳效能

預設的 OPcache 設定不適合 Symfony 應用程式,因此建議將這些設定變更如下

1
2
3
4
5
6
; php.ini
; maximum memory that OPcache can use to store compiled PHP files
opcache.memory_consumption=256

; maximum number of files that can be stored in the cache
opcache.max_accelerated_files=20000

不要檢查 PHP 檔案時間戳記

在生產伺服器中,除非部署新的應用程式版本,否則 PHP 檔案永遠不應變更。但是,預設情況下,OPcache 會檢查快取檔案的內容自快取以來是否已變更。此檢查會引入一些可以避免的額外負擔,如下所示

1
2
; php.ini
opcache.validate_timestamps=0

每次部署後,您都必須清空並重新產生 OPcache 的快取。否則,您將看不到應用程式中所做的更新。鑑於在 PHP 中,CLI 和 Web 程序不會共用相同的 OPcache,因此您無法透過在終端機中執行某些命令來清除 Web 伺服器 OPcache。以下是一些可能的解決方案

  1. 重新啟動 Web 伺服器;
  2. 透過 Web 伺服器呼叫 apc_clear_cache()opcache_reset() 函數(即,將這些函數放在您透過 Web 執行的腳本中);
  3. 使用 cachetool 公用程式,從 CLI 控制 APC 和 OPcache。

設定 PHP realpath 快取

當相對路徑轉換為其實際和絕對路徑時,PHP 會快取結果以提高效能。開啟許多 PHP 檔案的應用程式(例如 Symfony 專案)應至少使用這些值

1
2
3
4
5
6
; php.ini
; maximum memory allocated to store the results
realpath_cache_size=4096K

; save the results for 10 minutes (600 seconds)
realpath_cache_ttl=600

注意

當啟用 open_basedir 組態選項時,PHP 會停用 realpath 快取。

最佳化 Composer 自動載入器

在開發應用程式時使用的類別載入器經過最佳化,可以尋找新的和變更的類別。在生產伺服器中,除非部署新的應用程式版本,否則 PHP 檔案永遠不應變更。這就是為什麼您可以最佳化 Composer 的自動載入器,以掃描整個應用程式一次,並建置最佳化的「類別地圖」,這是一個包含所有類別位置的大型陣列,並儲存在 vendor/composer/autoload_classmap.php 中。

執行此命令以產生新的類別地圖(並使其成為您部署程序的一部分)

1
$ composer dump-autoload --no-dev --classmap-authoritative
  • --no-dev 排除僅在開發環境中需要的類別(即 require-dev 依賴項和 autoload-dev 規則);
  • --classmap-authoritative 為應用程式中使用的 PSR-0 和 PSR-4 相容類別建立類別地圖,並防止 Composer 掃描檔案系統以尋找在類別地圖中找不到的類別。(請參閱:Composer 的自動載入器最佳化)。

在除錯模式中停用將容器傾印為 XML

除錯模式 中,Symfony 會產生一個 XML 檔案,其中包含所有 服務容器 資訊(服務、參數等)。此 XML 檔案供各種除錯命令使用,例如 debug:containerdebug:autowiring

當容器變得越來越大時,檔案大小和產生檔案所需的時間也會隨之增加。如果此 XML 檔案的好處不超過效能下降,您可以停止產生檔案,如下所示

1
2
3
4
# config/services.yaml
parameters:
    # ...
    debug.container.dump: false

分析 Symfony 應用程式效能

使用 Blackfire 分析效能

Blackfire 是在開發、測試和生產期間分析和最佳化 Symfony 應用程式效能的最佳工具。它是一項商業服務,但提供 功能完整的示範

使用 Symfony Stopwatch 分析效能

Symfony 在開發 組態環境 中提供基本效能分析器。按一下 Web 除錯工具列 的「時間面板」,即可查看 Symfony 花費在資料庫查詢和呈現範本等工作上的時間。

您可以測量您自己程式碼的執行時間和記憶體消耗量,並透過 Stopwatch 元件,在 Symfony 分析器中顯示結果。

當使用 自動裝配 時,使用 Stopwatch 類別類型提示任何控制器或服務參數,Symfony 將注入 debug.stopwatch 服務

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
use Symfony\Component\Stopwatch\Stopwatch;

class DataExporter
{
    public function __construct(
        private Stopwatch $stopwatch,
    ) {
    }

    public function export(): void
    {
        // the argument is the name of the "profiling event"
        $this->stopwatch->start('export-data');

        // ...do things to export data...

        // reset the stopwatch to delete all the data measured so far
        // $this->stopwatch->reset();

        $this->stopwatch->stop('export-data');
    }
}

如果請求在其執行期間呼叫此服務,您將在 Symfony 分析器中看到一個名為 export-data 的新事件。

start()stop()getEvent() 方法會傳回一個 StopwatchEvent 物件,該物件提供有關當前事件的資訊,即使事件仍在執行中。此物件可以轉換為字串以進行快速摘要

1
2
// ...
dump((string) $this->stopwatch->getEvent('export-data')); // dumps e.g. '4.50 MiB - 26 ms'

您也可以使用 stopwatch Twig 標籤 分析您的範本程式碼

1
2
3
4
5
{% stopwatch 'render-blog-posts' %}
    {% for post in blog_posts %}
        {# ... #}
    {% endfor %}
{% endstopwatch %}

分析類別

使用 start() 方法的第二個選用參數來定義事件的類別或標籤。這有助於按類型組織事件

1
$this->stopwatch->start('export-data', 'export');

分析期間

真實世界的碼錶 不僅包含開始/停止按鈕,還包含一個「計圈按鈕」來測量每個部分計圈。這正是 lap() 方法的作用,它停止一個事件,然後立即重新啟動它

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$this->stopwatch->start('process-data-records', 'export');

foreach ($records as $record) {
    // ... some code goes here
    $this->stopwatch->lap('process-data-records');
}

$event = $this->stopwatch->stop('process-data-records');
// $event->getDuration(), $event->getMemory(), etc.

// Lap information is stored as "periods" within the event:
// $event->getPeriods();

// Gets the last event period:
// $event->getLastPeriod();

7.2

getLastPeriod() 方法是在 Symfony 7.2 中引入的。

分析區段

區段是一種將分析時間軸分割成群組的方式。範例

1
2
3
4
5
6
7
8
9
10
$this->stopwatch->openSection();
$this->stopwatch->start('validating-file', 'validation');
$this->stopwatch->stopSection('parsing');

$events = $this->stopwatch->getSectionEvents('parsing');

// later you can reopen a section passing its name to the openSection() method
$this->stopwatch->openSection('parsing');
$this->stopwatch->start('processing-file');
$this->stopwatch->stopSection('parsing');

所有不屬於任何命名區段的事件都會新增至名為 __root__ 的特殊區段。這樣,您就可以取得所有碼錶事件,即使您不知道它們的名稱,如下所示

1
2
3
4
5
use Symfony\Component\Stopwatch\Stopwatch;

foreach($this->stopwatch->getSectionEvents(Stopwatch::ROOT) as $event) {
    echo (string) $event;
}

7.2

在 Symfony 7.2 中引入了 Stopwatch::ROOT 常數作為 __root__ 的捷徑。

本作品,包括程式碼範例,均根據 Creative Commons BY-SA 3.0 授權條款授權。
目錄
    版本