让PHP应用性能维持在更高水平

默认情况下安装的PHP类似于在百货商店中购买的常规软件包,但它非常合适,但并不完美。调优的PHP就像是量身定制的装备。但是,应该注意的是,调优PHP只是提高PHP性能和效率的一种手段,它与不良的代码和无响应的API调用无关。

php.ini文件

PHP 解释器在 php.ini 文件中配置和调优,此文件的位置在不同的操作系统中是不同的,并且常规命令行对应 php.ini 和 PHP-FPM 对应的 php.ini 文件是分开的。在这里,我们假设配置PHP-FPM 对应于php.ini,但是下面讲的优化措施适用于所有 php.ini。

注:我们首先应该使用 PHP Iniscan 工具扫描 php.ini,检查使用了安全方面的最佳实践。


内存

运行 PHP 时需要关心每个 PHP 进程要使用多少内存,php.ini 中的 memory_limit 设置用于设定单个 PHP 进程可以使用的系统内存最大值。

此设置的默认值为128M,这可能适用于大多数中小型PHP应用程序。但是,如果您正在运行微型PHP应用程序,则可以降低此值以节省系统资源。另一方面,如果您正在运行内存密集型的PHP应用程序,则可以增加该值。此值的大小由可用的系统内存确定,确定为PHP分配多少值是一门艺术。

决定给 PHP 分配多少内存,以及能负担起多少个 PHP-FPM 进程时,可以根据以下维度信息进行判断:

  • 一共可以分配给 PHP 多少内存?以一个 2G 内存的 VPS 为例,这台设备中可能还运行了其他进程,如 MySQL、Nginx 等,那么留 512M 给 PHP 是合适的。
  • 每个 PHP 进程平均耗费多少内存?这个要监控进程的内存使用量,可以使用命令行命令 top,也可以在 PHP 脚本中调用 memory_get_peak_usage() 函数,不管使用哪种方式,都要多次运行同一个脚本,然后取内存消耗的平均值。
  • 能负担起多少个 PHP-FPM 进程?假设我给 PHP 分配了 512M 内存,每个 PHP 进程平均耗费 15M 内存,那么可以负担起 34 个 PHP-FPM 进程。
  • 有足够的系统资源吗?最后还需要确认有足够的系统资源运行 PHP 应用并处理预期的流量。
注:我们应该使用 Apache Bench 或 Siege 在类似生产环境的条件下对 PHP 应用做压力测试,以确定生产环境是否有足够的资源可用。

Zend OPcache

确定要分配多少内存后,就可以配置 PHP 的 Zend OPcache 扩展

PHP 5.5.0+ 内置了这个扩展,下面是在 php.ini 文件中配置和优化 Zend OPcache 扩展所用的设置:

  • opcache.memory_consumption = 64:为操作码缓存分配的内存量(以MB为单位)。分配的内存量应能够存储应用程序中所有PHP脚本编译的操作码。该值可以根据应用程序的大小设置为不同的值。
  • opcache.interned_strings_buffer = 16:用于存储常驻字符串的内存量(以MB为单位)。什么是驻留字符串? PHP解释器将在其后找到同一字符串的多个实例,并将此字符串保存在内存中。如果再次使用相同的字符串,PHP解释器将使用指针,以节省内存。默认情况下,PHP驻留字符串在每个PHP进程中都是隔离的。此设置允许PHP-FPM进程池将所有进程驻留字符串存储在共享缓冲区中,以便可以将其存储在PHP-FPM进程池中。在多个进程之间引用常驻字符串,从而节省了更多内存。
  • opcache.max_accelerated_files = 4000:可以存储在操作码缓存中的PHP脚本的最大数量。取值范围是2000〜100,000。此值必须大于PHP应用程序中的文件数。
  • opcache.validate_timestamps = 1:当此设置的值为1时,一段时间后,PHP将检查PHP脚本的内容是否已更改,并检查间隔由 opcache.revalidate_freq 设置指定。如果此设置的值为0,则PHP将不会检查PHP脚本的内容是否有更改,并且我们必须自己清除缓存的操作码。建议在开发环境中将其设置为1,在生产环境中将其设置为0。
  • opcache.revalidate_freq = 0:设置多久(单位是秒)检查一次 PHP 脚本内容是否有变化。设置为0秒的含义是仅当opcache.validate_timestamps 设置为1时,每次请求PHP文件时都会重新验证它们,因此,每次在开发环境中而不是在生产环境中都会重新验证PHP文件。
  • opcache.fast_shutdown = 1:此设置允许操作码使用更快的停机时间,将对象破坏和内存释放留给Zend Engine的内存管理器。


文件上传

如果您的应用程序允许上传文件,则最好设置可以上传的最大文件大小。另外,最好设置一次可以上传多少个文件:

file_uploads = 1
upload_max_filesize = 10M
max_file_uploads = 3

默认情况下,PHP允许在单个请求中上传20个文件。 上传的最大文件为2MB。在这里,我将其设置为在单个请求中最多上传3个文件,每个文件的最大大小为10MB。也不要设置此值。很大,否则会发生超时。

注:如果非要上传大文件,Web 服务器的配置也要做相应调整。除了在 php.ini 中设置之外,还要调整 Nginx 虚拟主机配置中的 client_max_body_size 设置。

最长执行时间

php.ini 文件中的 max_execution_time 用于设置单个PHP进程在终止之前可以运行的最长时间。此设置默认为30秒,建议将其设置为5秒:

max_execution_time = 5


注:在 PHP 脚本中可以调用 set_limit_time() 函数覆盖这个设置。

假设我们要生成报告并将结果生成为PDF文件。该任务可能需要10分钟才能完成,并且我们当然不希望等待PHP请求10分钟。我们应该编写一个单独的PHP文件,并将其放在单独的背景中。在该流程中执行后,Web应用程序可以在几毫秒内生成一个单独的后台流程,然后返回HTTP响应:

<?php
exec('echo "create-report.php" | at now');
echo 'report pending...';


create-report.php 在单独的后台进程中运行。运行之后,您可以更新数据库或将报告通过电子邮件发送给收件人。但是,这种用法很少见。通常,我们通过异步使用队列来实现类似的功能。无论在安全性,可伸缩性和可维护性方面,效果都更好。相关组件具有轻量级消息队列PHPResque等。

处理会话

PHP的默认会话处理程序减慢了大型应用程序的速度,因为该处理程序将会话数据存储在硬盘上,从而造成不必要的磁盘I / O并浪费时间。我们应该将会话数据保留在内存中,例如使用Memcached或Redis。这还有一个额外的好处-将来更容易扩展。如果会话数据存储在硬盘上,则添加其他服务器不方便。如果会话数据存储在Memcached或Redis中,则任何分布式PHP-FPM服务器都可以访问会话数据。

如果想把会话数据保存在 Memcached 中,需要做如下配置:

session.save_handler = 'memcached'
session.save_path = '127.0.0.1:11211'


缓冲输出

如果在更少的块中发送更多的数据,而不是在更多的块中发送更少的数据,则网络将更加高效,也就是说,以更少的片段浏览器传递内容以进行访问,这可以减少HTTP请求的总数。

因此,我们必须让PHP缓冲输出。默认情况下,PHP已启用输出缓冲功能,并且PHP将在缓冲4096字节的输出后将内容发送到Web服务器。

output_buffering = 4096
implicit_flush = false


注:如果想要修改输出缓冲区的大小,确保使用的值是4(32位系统)或8(64位系统)的倍数。


真实路径缓存

PHP 会缓存应用使用的文件路径,这样每次包含或导入文件时就无需不断搜索包含路径了,这个缓存叫真实路径缓存(realpath cache),如果运行的是大型的 PHP 文件(如 Composer 组件),使用了大量文件,增加 PHP 真实路径缓存的大小能得到更好的性能。

真实路径缓存的默认大小为16K。此缓存所需的确切大小不易确定,但可以使用一些技巧:首先,增加实际路径高速缓存的大小并将其设置为特别大的值,例如256K。最后在php脚本末尾添加上 print_r(realpath_cache_size());,输出真实路径缓存的真正大小,最后,把真实路径缓存的大小改为这个真正的值。我们可以在 php.ini 文件中设置真实路径缓存的大小:

realpath_cache_size = 64K


让PHP应用性能维持在更高水平

您可能还会对下面的文章感兴趣: