PHP 是创建服务器端 Web应用最流行的方式,占有大约80% 的市场份额。 (ASP.net 位居第二,而 Java 位居第三,差距更小。)
PHP 世界包含大量 PHP 框架;最受欢迎的包括 Laravel、Phalcon 和 Symfony 2。 PHP 也是流行内容管理系统 (CMS)(例如WordPress和Drupal )的基础。 (Drupal 的最新版本 Drupal 8 包含重要的Symfony 2集成。
现在,PHP 团队发布了新版本PHP 7——距离 PHP 5 推出已有十多年了。 在此期间,网络的使用量和网站的需求都呈指数级增长。 PHP 为这种快速增长做出了贡献 - 但其所实现的增长也凸显了 PHP 的局限性。
PHP 通常被认为功能强大且灵活,但是存在性能问题。 基于 PHP 的网站在流量数量增加几次之后就很容易“陷入困境”。 当一个网站开始实现其业务或运营目标时,只要流量增加,它就会开始崩溃。
对于成千上万个基于 PHP 的应用,一些相对简单的更改就足以提高性能。 这些包括使用memcached
等工具进行缓存、调整数据库以及使用NGINX Open Source和NGINX Plus进行反向代理和负载均衡。 NGINX 极大地提高了应用程序的响应能力,支持用户和流量数量级的增加。
这篇博客文章是关于最大限度提高使用 PHP 7 的网站性能的两部分系列文章中的第一篇。 在这里我们专注于升级到 PHP 7,实现 NGINX Open Source 或 NGINX Plus 作为您的 Web 服务器软件,重写 URL(正确处理请求所必需),缓存静态文件,以及缓存动态文件(也称为应用缓存或微缓存)。
在下一篇博文中,我们将重点介绍使用附加服务器可以采取的步骤:添加反向代理服务器、移动到多台应用服务器、在多台服务器之间进行负载均衡、在负载均衡的同时支持会话持久性以及终止安全协议,例如 SSL/TLS 和相关的 HTTP/2 协议。
PHP应用为何会遇到障碍? 由于同样的原因,任何应用服务器软件都会遇到困难。 当用户请求到达时,PHP 及其运行的 Web 服务器软件必须执行以下几件事:
对于物理服务器、虚拟机或云服务器实例来说,处理每个请求都需要做很多工作。 当服务器上的物理内存(无论是物理的还是虚拟的)耗尽时,性能就会下降。 然后,当新的请求到达时,服务器就开始将当前会话分页到磁盘。 等待文件请求完成也会引入导致分页的等待状态。 超过某个(非常有限的)点,分页操作和数据请求就会压倒处理操作,性能就会进入死亡螺旋,导致用户长时间等待或彻底终止会话。
克服 PHP 的性能障碍当然是可能的,并且需要几个互补的步骤。 每个步骤都可以与其他步骤相结合。 大致包括:
您不必按照任何特定顺序执行这些步骤;例如,即使您保留 Apache 作为您的 Web 服务器并且不将您的应用服务器升级到 PHP 7,只需在现有服务器“前面”实现 NGINX 作为反向代理就可以提高性能并使您能够并行实现多个应用服务器。
不管您如何做,要记住的关键事实是,您可以获得多个提高性能的因素,甚至在容量上提高一个数量级,而几乎不需要对当前的应用代码进行任何更改。 请继续阅读,了解人们如何已经实现或正在实现这些非凡的绩效提升。
笔记: 在这些博客文章中我们会忽略多服务器优化。 独立的数据库服务器和内容分发网络 (CDN) 可以减轻应用服务器的负担并大大提高性能;这些类型的变化与此处描述的应用和实施改进是分开的、并行的。
尽早升级到 PHP 7 的主要原因很简单:应用速度(显著节省内存)。 据称,PHP 7 的速度比以前版本的 PHP快两倍,并且占用的内存也少得多。 (在这两个方面,您的里程无疑会有所不同。)
简单来说,响应时间对于 Web应用来说至关重要。 速度更快的网络应用(同时占用更少的内存,从而降低页面交换的可能性以及由此导致的性能问题)可实现以下三个目标:
这些都是升级的极好理由;综合起来,升级的理由似乎势不可挡。 即使没有明显的性能优势,“升级到最新版本”始终是解决许多问题的首要建议。 那么为什么大家不立即升级呢?
很简单:人们讨厌弄乱旧代码,这是有充分理由的。 如果旧应用程序运行良好,并且开发人员从创建新应用程序中获得的结果比升级旧应用程序更好,那么旧应用程序就可以在很长一段时间内保持不变。 (有关如何使用 NGINX 来提高应用程序性能而无需对当前 Web 服务器和应用程序进行任何更改的信息,请参阅本系列的第二篇博客文章。)
但如果可能的话,更有效的做法是通过升级到 PHP 7 来开始追求更高的性能。 不过,除非你有足够的时间完成,否则不要开始,尤其是在不吝惜测试的情况下。
让我们看看升级到 PHP 7 需要做什么:
switch
与if-then-else
之间的争议。) Engine Yard 上的这个博客对大部分这些问题都有很好的例子。
如果您决定继续升级到 PHP 7,请考虑对您的代码(或至少是其关键功能)进行全面的性能审查和修订,以利用 PHP 7 中的新功能。 对于您和您的团队来说,没有比这更好的方式来提升技能,并且您今天做出、审查和测试的改变可能会在未来许多年里为您服务。 您还将从本篇博文中的其他性能建议中获得最大收益,因为优化代码在优化环境中运行时将受益匪浅。
因此,尽管网站经常部署 NGINX 以在不触及应用代码的情况下获得更好的性能,但我们还是建议您咬紧牙关,勇往直前。 有很多人可以帮助你完成这一举动,或者你也可以自己撸起袖子,自己动手。 官方 PHP 网站上有PHP 7 迁移指南,O'Reilly 也有PHP 7 升级指南。
NGINX 是运行超过 1.4 亿个网站的软件,其中包括10,000 个最繁忙网站的一半。 (这些测量检测单服务器站点的 Web 服务器和多服务器站点的反向代理服务器。) 作为 Web 服务器,两者都能立即提升性能 — — 在某些情况下,运行其他软件的服务器超载和抖动的次数最多可达 10 倍。 作为反向代理服务器,两者都允许使用多个专用服务器来根据需要广泛扩展部署。
PHP 和 Apache 都会为每个打开的请求分配资源;如果其中一个或两个都必须加载多个库,则每个请求的启动时间和内存占用量可能会非常大。 将 NGINX 用作 Web 服务器软件可在服务器级别消除此问题。 使用 NGINX 的功能将工作卸载到 Web 服务器(例如提供静态文件)或反向代理服务器(各种缓存、协议终止、负载均衡等),可最大限度地减少 PHP 需要做的事情,简化和加快应用处理。
如果您的网站有自定义或专有的 Apache 模块,您可能无法用 NGINX 替换 Apache,除非您替换这些模块。 检查 NGINX 是否有简单的解决方法;如果没有,则估算进行更改所需的时间和精力。
一旦您决定使用 NGINX,您就可以在 NGINX Open Source 和 NGINX Plus 之间进行选择。 NGINX Plus 相对于 NGINX 开源的一些最突出的特点包括:
作为反向代理服务器,NGINX Plus 还有以下优势:
NGINX Open Source 和 NGINX Plus 都支持内容缓存和微缓存(也称为应用缓存)。 缓存在 Web 服务器环境中很有用,因为它可以卸载应用服务器,但两个功能仍然共享单台机器或虚拟机实例。 在反向代理服务器上,缓存可以从应用服务器设备卸载大量工作,从而提供更大的性能优势。
您可以直接从nginx.org下载 NGINX开源软件,在那里您还可以找到社区支持。 要开始单个 NGINX Plus 订阅,请注册30 天免费试用版或在线购买。 对于多实例包,请联系NGINX 销售。
当你从 Apache 迁移到 NGINX 作为你的 Web 服务器软件时,你需要进行一些更改 - 详细信息请参阅sitepoint.com上的一篇优秀文章:
mod_rewrite
指令)中。 用NGINX配置文件中的相关配置规范替换这些。 有关一些示例,请参阅我们的博客。进行这些更改可以让您熟悉 NGINX 并使您能够优化更复杂的网站,正如我们在本博文的第 2 部分中所述。 但是,如果进行这些配置更改会给您的网站运营带来不可接受的工作量或风险程度,请不要担心 - 您可以实现第 2 部分中描述的多服务器架构,而无需从 Apache 升级核心 Web 服务器软件,因此也无需更改您的 Web 服务器配置文件。
静态文件就是不经常改变的文件,至少从网络服务器的角度来看是这样。 静态文件通常包括图形文件(例如 JPEG 和 PNG)和代码文件(例如 CSS 和 JavaScript 文件)。 如果将这些文件放在应用服务器上或单独的数据库服务器上,则对它们的请求必须由应用程序代码处理,并且会产生发出和满足请求所需的所有开销。 这会“分散”应用服务器对更重要的工作的注意力,并使其更接近物理内存过载的程度,而新的请求会导致当前请求分页到磁盘。
静态文件缓存是 NGINX 的核心功能。您可以在 Web 服务器或反向代理服务器上实现它:
在 NGINX 上实现静态文件缓存总体分为三个步骤:
在没有反向代理服务器参与的 NGINX Web 服务器上,您不会进行通常意义上的缓存。 您只需使用X-Accel-Redirect
标头将对静态文件的查询重定向到 Web 服务器。 应用服务器永远看不到该请求,并且可以将所有资源用于应用请求。 使用反向代理服务器,您确实使用静态文件缓存 - 并且运行应用的物理服务器或虚拟服务器实例不参与响应静态文件请求。
作为优化响应速度的示例,以下配置片段使 NGINX 能够使用操作系统的sendfile
系统调用,通过不将文件复制到中间缓冲区,从而节省了文件传输中的一步:
位置 /mp3 { sendfile on;
sendfile_max_chunk 1m;
# ...
}
有关配置 NGINX 进行静态文件缓存的详细信息,请参阅NGINX Plus 管理指南。
令人困惑的是,微缓存有许多名称,其中还包括应用缓存和普通缓存。 在 NGINX 中,我们使用术语“微缓存”来强调此类文件有效的短暂时间。
假设您有一个博客文章页面,提供用户评论机制。 您希望在新访问者访问页面时,或者现有用户刷新页面查看自己或其他人的新评论时,包含最新、最精彩的评论。 在这种情况下,每次有人访问时重新生成页面似乎是个好主意。
然而,“每次”都会成为负担。 如果某个页面每秒只获得一次访问,则每次访问都重新生成该页面是有意义的。 但是,如果该页面每秒的访问量达到十次、一百次或一千次,并且网站上的所有其他页面也都达到这一水平,则应用服务器可能会超载。 要实现向人们提供新鲜内容的目标,就意味着没有人能快速获得任何内容。
微缓存意味着一旦将缓存版本标记为在短时间内有效(比如一秒或几秒),就会生成一个页面。 当缓存版本过期时,下一个请求将提示生成一个新页面,并在获取其缓存版本后立即请求。 这与静态文件的行为相同,但时间范围要短得多。
此图像指示在您的网站上哪里可以查找可以进行微缓存的内容。 它来自我们自己的 Owen Garrett 的一篇微缓存博客文章。
微缓存非常棒,因为它在最需要的时候从应用服务器中删除工作,并且对用户的损害很小甚至没有损害。 它非常棒,甚至被内置到某些系统中。 Drupal 认为其强大的内置微缓存功能非常重要,因此在 Drupal 世界中,微缓存被简称为“缓存”。
但是 Drupal 解决方案有点欠缺,任何类似的解决方案也是如此。 应用服务器的工作较少,但仍然是 Drupal(或者更一般地说是 PHP)需要管理配置、实施和文件服务。 通过使用 NGINX 进行微缓存,应用服务器可以完全卸载任何内容,只需按照微缓存指定的频率生成新页面即可。 它甚至看不到其他请求,更不用说存储或检索任何缓存命中的内容。
使用 NGINX Plus 或其他工具,您可以监控您的网站并查看哪些页面将从微缓存中受益。 以下配置片段实现了 1 秒的响应缓存期,200
正常
状态代码。
proxy_cache_path /tmp/cache keys_zone=cache:10m levels=1:2 inactive=600s max_size=100m;server {
proxy_cache 缓存;
proxy_cache_valid 200 1s;
# ...
}
我们的 PHP 博客文章的第一部分重点介绍单服务器解决方案以及缓存,这在单服务器实现中非常有效 - 但在混合使用反向代理服务器时更为有效。 第 2 部分描述了反向代理服务器以及围绕 PHP应用的多服务器实现的好处。
“这篇博文可能引用了不再可用和/或不再支持的产品。 有关 F5 NGINX 产品和解决方案的最新信息,请探索我们的NGINX 产品系列。 NGINX 现在是 F5 的一部分。 所有之前的 NGINX.com 链接都将重定向至 F5.com 上的类似 NGINX 内容。”