日期:2012-01-22  浏览次数:20522 次

简介

Wikipedia、Facebook 和 Yahoo! 等主要 web 属性使用 LAMP 架构来为每天数百万的请求提供服务,而 Wordpress、Joomla、Drupal 和 SugarCRM 等 web 应用程序软件使用其架构来让组织轻松部署基于 web 的应用程序。

该架构的优势在于其简单性。而 .NET 这样的堆栈和 Java™ 技术可能使用大量硬件、昂贵的软件栈和复杂的性能调优,LAMP 堆栈可以运行于商品硬件之上,使用开源软件栈。由于软件栈是一个松散的组件集,而非一个整体堆栈,性能调优是一大挑战,因为需要分析和调优每个组件。

然而,这有几个个简单性能任务会对任何规模的网站的性能产生巨大的影响。在本文中,我们将探讨旨在优化 LAMP 应用程序性能的 5 个这样的任务。这些项目应当很少需要对您的应用程序进行架构更改,使其成为最大化您的 web 应用程序所需的响应能力和硬件需求的安全、便捷的选择。

使用操作码缓存

提高任何 PHP 应用程序(当然是 LAMP 中的 “P”)的性能的最简单方式是利用一个操作码缓存。对于我使用的任何网站,它是我确保存在的一项内容,因为性能影响很大(很多时候有了操作码缓存,响应时间可减少一半)。但是对 PHP 不熟悉的大部分人的一个很大的疑问是,为何改进会如此之大。答案在于 PHP 如何处理 web 请求。图 1 概览了 PHP 请求的流程。


图 1. PHP 请求
图表展示 PHP 请求的流程,从 PHP 脚本到解析到最后的输出

由于 PHP 是一种解释语言,而非 C 或 Java 等编译语言,对每个请求执行了 “解析-编译-执行” 的整个步骤。您可以看到为何这会耗时、耗资源,特别是当脚本在请求之间很少变化时。解析和编译脚本之后,脚本作为一系列操作码处于机器可解析状态。这是操作码缓存发挥效用的地方。它作为一系列操作码缓存这些编译脚本,以避免为解析和编译每个请求步骤。您将在图 2 中看到这样的工作流是如何运作的。

图 2. PHP 请求使用操作码缓存
流程图展示逻辑流如何检查缓存的操作码并跳过解析和编译步骤(如果有的话)

因此当 PHP 脚本的缓存操作码存在时,我们可以跳过 PHP 请求流程的解析和编译步骤,直接执行缓存操作码并输出结果。检查算法负责处理您可能对脚本文件进行了更改的情况,因此在已变更脚本的第一个请求后,会为随后的请求自动重新编译和缓存操作码,替换缓存的脚本。

操作码缓存对于 PHP 流行已久,其中早期的一些要追溯到 PHP V4 的全盛期。目前有一些流行选项正在积极开发和使用中:

  • 替代 PHP 缓存(APC)可能是 PHP 最流行的操作码缓存(参见 参考资料)。它由若干核心 PHP 开发人员所开发,做出了很大贡献,Facebook 和 Yahoo! 的工程师赋予了其速度和稳定性。它还支持用于处理 PHP 请求的若干其他速度改进,包括一个用户缓存组件,这将在本文后面探讨。
  • Wincache 是主要由 Microsoft® 的 Internet Information Services (IIS) 团队积极开发的一个操作码缓存,仅供在使用 IIS web 服务器的 Windows® 上使用(参见 参考资料)。开发它的主要动力在于使 PHP 成为 Windows-IIS-PHP 堆栈上的一流开发平台,因为据知 APC 在该堆栈上运作的不是很好。它在功能上非常类似于 APC,且支持一个用户缓存组件,以及一个内置会话处理程序,以将 Wincache 作为一个会话处理程序直接加以利用。
  • eAccelerator 是原始 PHP 缓存之一 Turck MMCache 操作码缓存(参见 参考资料)的一个派生。不同于 APC 和 Wincache,它仅是一个操作码缓存和优化器,因此它不包含用户缓存组件。它在 UNIX® 和 Windows 堆栈上完全兼容,且对于不打算利用 APC 或 Wincache 提供的其他功能的站点很流行。如果您要使用 memcache 这样的解决方案来为多 web 服务器环境提供一个单独的用户缓存服务器,那么这就是常见情况。

毫无疑问,一个操作码缓存是通过在每次请求后消除解析和编译脚本的需要来加速 PHP 的第一步。完成第一步之后,您应当看到响应时间和服务器负载方面的改进。但是优化 PHP 可以做的不止这些,我们接下来将加以讨论。

优化您的 PHP 设置

虽然实现操作码缓存是性能改进的一大创举,不过也有大量其他优化选项可供您基于 php.ini 文件中的设置优化您的 PHP 设置。这些设置更适合于生产实例;在开发或测试实例上,您可能不希望做这些变更,因为它会使得应用程序问题的调试变得更难。

让我们看一下对于性能提升很重要的一些项目。

应当禁用的选项

有若干 php.ini 设置应当予以禁用,因为它们常用作向后兼容性:

  • register_globals — 在 PHP V4.2 之前该功能常常是默认值,其中传入的请求变量被自动赋给普通 PHP 变量。这样做除了引起重大安全问题之外(使未过滤的传入请求数据与普通 PHP 变量内容相混),对每一个请求这样做还会产生开销。因此禁用这一设置使您的应用程序更安全且能提高性能。
  • magic_quotes_* — 这是 PHP V4 的另一遗留项,其中传入的数据会自动避开有风险的表单数据。它旨在作为一个安全特性,在将传入的数据发送到数据库之前对其进行整理,但不是很有效,因为它不能帮助用户预防常见的 SQL 注入攻击。由于大部分数据库层支持能更好地处理该风险的准备语句,禁用该设置会再次消除这个烦人的性能问题。
  • always_populate_raw_post_data — 这仅当您出于某些原因需要查看传入的未过滤 POST 数据的整个负载时才需要。否则,它仅在内存中存储 POST 数据的一个副本,而这没有必要。

然而,在遗留代码上禁用这些选项会有风险,因为它们可能取决于其设置来实现正确执行。不应当基于被设置的这些选项来开发任何新代码,而且可能的话,您应当寻求方法来重构您的现有代码,避免使用它们。

应当禁用或调整设置的选项

您可以启用 php.ini 文件的一些优秀性能选项,来提升您的脚本速度:

  • output_buffering — 您应当确保启用该选项,因为它会以块为单位将输出刷回到浏览器,而非以每个 echoprint 语句为单位,而后者会大大减缓您的请求响应时间。
  • variables_order — 这个指令控制传入请求的 EGPCS(EnvironmentGetPostCookieServer)变量解析顺序。如果您没有使用某种超全局变量(比如环境变量),您可以安全地删除它们来获得一点加速,从而避免在每一个请求上解析它们。
  • date.timezone