性能

3.4 版本
维护中的版本

Symfony极其之快。当然了,如果你真正需要速度,还有许多能让你令Symfony变得更快的方法。本章,你将探索一些方法,来让Symfony程序快上加快。

使用Byte Code缓存(如OPcache) 

改善性能时你应该做的第一件事是使用一种“byte code cache”。这些缓存存储了编译后的PHP文件以避免在每次请求时重复编译它们。

有很多 byte code caches 可以利用,其中的一些还是开源的。截止到PHP 5.5, PHP内置了 OPcache 。老版本中最广泛使用的byte code cache是 APC

使用byte code cache有百利而无一害,Symfony被打造成“可以在这种类型的环境中表现极佳”。

监控源文件的改变 

多数byte code cache监控着源文件的改变。这可确保如果文件源代码发生改变,byte code将被自动编译。这非常方便,但有些过载。

因此,一些byte code caches提供了一个选项来关闭这些检查。例如,要在APC中关闭检查,直接添加 apc.stat=0 到你的 php.ini 配置文件中。

当关闭这些检查时,将由服务器管理员来负责“确保缓存在任何源文件发生改变时被清除”。否则,你的更新将不会在程序中被看到。

同理,byte code缓存必须在部署程序时被清除 (例如,使用APC时通过调用 apc_clear_cache() PHP函数,以及,使用Opcache时通过 opcache_reset())。

在PHP中,命令行以及web进程并不共享相同的OPcache。这意味着你不能通过执行终端中的某些命令来清除web服务器上的OPcache。你可以重启服务器或者通过web服务器调用 apc_clear_cache()opcache_reset() 函数(如,在执行web脚本时包容它们)。

优化全部Symfony使用的文件 

默认时,PHP的OPcache在byte code缓存中存了2000个文件。这个数字对于一般的Symfony程序来说还是太小,因此你必须设置 opcache.max_accelerated_files 配置选项为更高的值:

1
2
; php.ini
opcache.max_accelerated_files = 20000

配置PHP realpath缓存 

PHP使用了一个内部缓存来存储“类文件路径”映射到“文件系统真实路径”的结果。这提高了Symfony这种“开启许多PHP文件”的程序之性能,特别是在Windows平台上。

默认时PHP设置了一个 16Krealpath_cache_size,这对Symfony来说实在太小。将这个值更新到至少 4096K。此外,缓存路径默认时只保存 120 秒,同样考虑通过 realpath_cache_ttl 选项来更新此值:

1
2
3
; php.ini
realpath_cache_size=4096K
realpath_cache_ttl=600

使用Composer的类映射功能 

默认时,Symfony标准版使用的是 autoload.php 文件中的Composer自动加载器(autoloader)。这个加载器很容易使用,因为它自动寻找任何“你在已注册目录中放置了”的新类。

不幸的是,这有使用成本,因为类加载器要遍历全部已配置的命名空间,以便找到一个特定文件,发起 file_exists() 的调用直到最终找到它想要的文件为止。

最简单的方案是告诉Composer构建一个优化过的"class map"(类映射),这是一个所有类所在位置的大数组,并且存放在 vendor/composer/autoload_classmap.php 中。

这个类映射可以由命令行生成,可能会成为你部署过程的一部分。

1
$  composer dump-autoload --optimize --no-dev --classmap-authoritative
--optimize
剥离你程序中的每一个兼容PSR-0 和 PSR-4 的类。
--no-dev
排除那些你只在开发环境下使用的类(如tests)。
--classmap-authoritative
防止Composer在文件系统中寻找那些没有出现在类映射中的类。

用APC缓存Autoloader 

另一个方案是在类被首次定位之再来缓存其位置。Symfony自带了一个类 - ApcClassLoader - 专门用来干这个。要使用它,只需适配你的前端控制器文件。如果你使用了标准版框架,可作出以下改变:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// app.php
// ...
 
use Symfony\Component\ClassLoader\ApcClassLoader;
 
$loader = require __DIR__.'/../app/autoload.php';
include_once __DIR__.'/../app/bootstrap.php.cache';
 
// Use APC for autoloading to improve performance
// Change 'sf2' by the prefix you want in order
// to prevent key conflict with another application
// 使用APC自动加载以提升性能,改变'sf2'为你希望的前缀,
// 以防止同其他程序发生key冲突
$loader = new ApcClassLoader('sf2', $loader);
$loader->register(true);
 
// ...

更多细节,参考 对Class Loader进行缓存 一文。

当使用APC autoloader时,如果你添加了新类,它们将被自动找到,所有东西的运作一如往常(即,并无必要“清除”缓存)。但是,如果你改变了某个特定命名空间或前缀的位置,你就需要flush你的APC缓存。否则,自动加载器仍将在那个命名空间的旧位置来寻找所有的类。

使用Bootstrap文件 

为确保弹性优化和代码复用,Symfony程序利用了多样化的类和第三方组件。但在每次请求中从分散位置加载全部这些类会导致一定程度的过载。为减轻负责,Symfony提供了一个脚本来生成一个被称为 bootstrap file 文件,考量的是在单一文件中加载多个类定义。通过包容这个文件 (它包含了各种核心类的拷贝),Symfony不再需要包容任何“含有那些类”的源文件。这将减少不少的硬盘吞吐(disc IO)。

如果你正在使用Symfony标准版,那你应该已经使用了这个bootstrap启动文件。为确保使用,打开你的前端控制器(通常是 app.php),然后检查以下代码行确实存在:

1
include_once __DIR__.'/../var/bootstrap.php.cache';

注意,当使用bootstrap文件时有两个不利点:

  • 此文件会在任意原始资源发生改变时重新生成 (如,当你更新了Symfony的src代码或vendor三方类库时);
  • 调试时,开发者需要在bootstrap文件中设置断点。

如果你使用的是Symfony标准版,启动文件将在vendor类库更新之后,透过 composer install 命令来自动重建(译注:指composer.json中的post脚本等,也可手动执行)

Bootstrap文件和Byte Code缓存 

即便使用了一种byte code缓存,在使用bootstrap文件时仍会提高性能,这是因为需要监控“发生改变”的文件变少了。当然这个功能如果在byte code cache中被关闭的话 (即在APC中设置 apc.stat=0),就再无理由使用bootstrap文件。

本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。

登录symfonychina 发表评论或留下问题(我们会尽量回复)