利用NGINX充分提升PHP 7性能,第1部分:Web服务与缓存

NGINX | 2016年2月26日

简介:NGINX 如何与 PHP 配合使用

PHP是创建服务器端Web应用程序的主流方式,约占80%的市场份额。(ASP.net位居第二,但与PHP差距较大;Java位居第三,差距更为明显。)

PHP生态系统包含众多PHP框架,其中较为流行的包括Laravel、Phalcon和Symfony 2。PHP也是许多常用内容管理系统(CMS)的基础,例如WordPress和Drupal。(最新的Drupal版本Drupal 8与Symfony 2进行了深度集成。

现在,PHP团队发布了新版本PHP 7。此时距PHP 5推出已过去十多年。在此期间,Web使用量和网站需求均呈指数级增长。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应用会遇到瓶颈?原因与任何应用服务器软件遇到瓶颈相同。当用户请求到达时,PHP及其所依赖的Web服务器软件必须执行多项操作:

  • 解析请求。首先,Web服务器软件需要启动进程,随后PHP也需要启动进程,以接收、解析并处理请求。例如,Apache HTTP Server会分配资源来处理每个数据请求,无论请求是简单的(检索JPEG文件),还是复杂的(处理嵌套的CSS请求)。这些操作都需要时间、系统资源和内存分配。如果操作系统、PHP或两者在开始处理请求之前需要加载多个库,所需内存可能会相当大。
  • 处理支持协议。如果使用SSL/TLS和/或HTTP/2,Web服务器软件必须解码请求,这一过程可能较为耗时。
  • 处理请求。PHP必须整合处理请求所需的资源。这可能需要多次调用数据库、通过互联网调用外部服务,以及执行复杂的内部处理。
  • 响应请求。PHP必须将结果返回给Web服务器软件,再由其以HTTP响应的形式传回请求方。请注意,从最初接收到最终确认,Web服务器软件和PHP都会为每个请求运行一个活跃的专用线程。

对于物理服务器、虚拟机或云服务器实例而言,每个请求都要处理如此多的任务,负担十分沉重。当服务器(无论是物理服务器还是虚拟服务器)的物理内存耗尽时,性能往往会显著下降。此时,随着新请求不断传入,服务器会开始将当前会话换页到磁盘。等待文件请求完成也会产生等待状态,进一步加剧换页。超过某个很低的临界点后,换页操作和数据请求会挤占处理资源,性能随之陷入恶性循环,导致用户长时间等待,甚至会话直接终止。

解决性能问题

克服PHP的性能瓶颈完全可行,但需要采取多个相辅相成的步骤。这些步骤可以组合使用,大致包括:

  • 用硬件解决问题。增加内存、增加内存、使用更快的磁盘、部署独立的数据库服务器和内容分发网络、提高吞吐能力,以及采用其他机械式解决方案,都是快速但粗放地解决性能问题的方法。这些方案或许能维持系统正常运行,或使性能随资源投入呈线性扩展。
  • 改进PHP和应用程序代码。新版PHP、新框架和经过改进的应用程序代码可以显著提升性能,甚至可能使性能提升至原来的2倍或4倍,而且无需额外购置新硬件。
  • 改进服务器软件。大多数Web服务器和PHP会为每个正在处理的开放请求分配专用资源。NGINX服务器软件会在请求到达时进行处理,无需占用专用资源,从而尽可能减少服务器资源占用。
  • 多服务器实施。可以部署反向代理服务器来处理互联网请求,并将请求分配到一个或多个应用服务器(即负载均衡)。反向代理服务器还可以处理文件缓存、SSL/TLS和HTTP/2等协议的终止,以及多台应用服务器的管理。即使只有一台应用服务器,也能卸载其大部分工作负载。随着服务器数量增加,负载均衡可确保任何服务器都不会因承担超出其应有份额的负载而不堪重负。

无需按特定顺序实施这些步骤。例如,即使继续使用Apache作为Web服务器,并且不将应用服务器升级到PHP 7,只需在现有服务器“前端”部署NGINX作为反向代理,即可提升性能,并支持并行部署多个应用服务器。

无论采用哪种方式,都要牢记一个关键事实:只需对当前应用程序代码进行少量更改,甚至无需更改,就能将性能提升数倍,容量甚至可提升一个数量级。继续阅读,了解其他人如何已经实现或正在实现这些显著的性能提升。

注意:这些博文不会详细讨论多服务器优化。使用独立的数据库服务器和内容分发网络(CDN),可以减轻应用服务器的负载并显著提升性能;这类更改与本文所述的应用和实现改进相互独立,可并行实施。

技巧 1:升级到 PHP 7

尽早升级到PHP 7的主要原因很简单:应用速度(内存占用减少显著提升了速度)。据称,PHP 7的速度是旧版PHP的两倍,而且内存占用大幅减少。(实际速度和内存占用情况无疑会有所不同。)

简而言之,响应时间对Web应用至关重要。速度更快的Web应用占用的内存也更少,可降低发生页面交换及由此引发性能问题的可能性,并带来三方面的成效:

  1. 提升用户满意度,使其更愿意访问您的网站并完成任务,例如阅读文章、获取产品信息、叫车、租用闲置房间或购物。这正是您最初创建该网站或应用的目的。
  2. 使指定服务器能够支持更多用户,而不必担心用户增加导致服务器变慢甚至崩溃。能推迟灾难总是好事。
  3. 降低服务器遭受黑客攻击的可能性。这类攻击会使服务器过载,导致其停止提供服务。如今,任何服务器都可能遭到攻击,但防护薄弱的服务器遭受攻击的次数更多,攻击也更猛烈。因此,降低脆弱性可能会带来显著提升。

这些都是升级的充分理由;综合来看,升级似乎势在必行。而且,即使性能提升并不明显,“升级到最新版本”通常也是解决许多问题时首先给出的建议。那么,为什么大家不立即升级呢?

xkcd 眼中的更新

原因很简单:人们不愿折腾旧代码,而且这并非没有道理。如果旧应用运行得还不错,而开发人员创建新应用比升级旧应用更有成效,那么旧应用可能会长期保持原样,继续运行。(有关如何在不更改现有Web服务器和应用的情况下使用NGINX提升应用性能的信息,请参阅本系列的第2篇博客文章。)

但如果条件允许,更高效的做法是先升级到PHP 7,以提升性能。不过,请确保有足够的时间完成升级后再开始,尤其不能缩减测试环节。

下面来看看升级到PHP 7需要做哪些准备:

  • 表达式求值的变化。您可能需要更改某些表达式的写法,使其在PHP 7中正确求值。(如果您非常谨慎,不打算一次性升级所有PHP服务器,则需要使这些表达式在PHP 5.6和PHP 7中都能正确求值。)如果代码中使用了可变变量或可变属性,则需要修改代码,使其在两个PHP版本中的求值方式保持一致。
  • 语法变更。PHP 7不支持ASP标签或script标签。switch不能包含多个default分支。(这里暂且不讨论相关争议,即应使用switch还是if-then-else。)
  • 移除已弃用的功能。各种功能曾在PHP 5.x的多个版本中被弃用,如今已经彻底失效,就像一只死鹦鹉。这些功能在PHP 7中根本无法使用。如果代码中包含这些功能,而您尝试将其全部移除却未能成功,那么购物车代码必定会在“网络星期一”前一晚23:59失效。
  • 新功能。PHP 7新增了多项功能,对升级旧代码的开发者颇具吸引力,但在清理代码时应谨慎添加新功能。新功能通常很实用,否则也不会被加入;但随着PHP进一步升级,它们也很容易引入错误(无论是您自己的还是他人的),并可能需要日后修改。
  • 常规代码审查。每次接触代码时,甚至只是打开代码文件,却不确定是否做过更改时,都需要审查其中的所有内容,尤其是可能更改过的部分。
  • 测试。所有内容都需要持续测试。进行任何更改后,都需要重新测试所有内容,但即便如此,也不意味着能发现所有缺陷。完善实施的DevOps环境或许能让这类测试相对轻松,但目前只有少数人具备这样的理想环境。

Engine Yard上的这篇博客提供了很好的示例,说明了其中大多数问题。

如果决定升级到PHP 7,建议充分利用PHP 7的新功能,对代码进行全面的性能审查和修订,或至少审查和修订其中的关键功能。这是提升您和团队技能的有效方式,而现在所做、审查和测试的更改很可能在未来多年持续发挥作用。这样也能充分发挥本博文中其他性能建议的效果,因为经过优化的代码在经过优化的环境中运行时会显著受益。

因此,尽管网站通常会部署NGINX,以便在不改动应用程序代码的情况下提升性能,但我们仍建议您下定决心,积极推进升级。您可以找到大量相关帮助来完成迁移,也可以直接着手自行完成。PHP官方网站提供了PHP 7迁移指南,O’Reilly也出版了PHP 7升级操作指南。

技巧 2:选择 NGINX Open Source 或 NGINX Plus

超过1.4亿个网站使用NGINX软件,其中包括10,000个访问量较大的网站中的一半。(这些测量会检测单服务器网站的Web服务器,以及多服务器网站的反向代理服务器。)作为Web服务器,NGINX Open Source和NGINX Plus都能立即提升性能;在某些情况下,运行其他软件的服务器因过载而频繁进行内存与磁盘交换,性能提升可达10倍。作为反向代理服务器,两者都支持使用多台专用服务器,根据需要大规模横向扩展部署。

PHP和Apache都会为每个打开的请求分配资源;如果其中一个或两者都必须加载多个库,每个请求的启动时间和内存占用可能会相当可观。改用NGINX作为Web服务器软件,可以在服务器层面消除这一问题。利用NGINX的功能,将工作卸载到Web服务器(例如提供静态文件)或反向代理服务器(执行各种缓存、协议终止、负载均衡等任务),可以尽量减少PHP需要处理的工作,从而简化并加快应用处理。

如果网站使用自定义或专有的Apache模块,则在替换这些模块之前,可能无法用NGINX取代Apache。请咨询NGINX,了解是否有简便的解决方法;如果没有,请评估完成此项更改所需的时间和工作量。

决定采用NGINX后,可以选择NGINX Open Source或NGINX Plus。与NGINX Open Source相比,NGINX Plus的一些主要功能包括:

  • 预编译代码。NGINX Plus以编译形式分发,其中包括常用库以及可随时添加和移除的动态模块。(NGINX Open Source同时提供已编译和未编译代码。)无需重启服务器,即可进行多种配置更改,。
  • 支持服务。NGINX Plus包含支持服务包,可让您直接联系NGINX工程师。
  • 监控和管理。适合DevOps的工具可帮助服务器保持正常运行,以满足服务级别协议(SLA)的要求。

作为反向代理服务器,NGINX Plus还具有以下优势:

  • 负载均衡。两个版本的NGINX均支持基本的HTTP负载均衡,但NGINX Plus还提供更复杂的算法和TCP负载均衡。
  • 会话持久性。除负载均衡外,NGINX Plus还提供更高级的会话持久性,这通常与PHP应用服务器密切相关。
  • 监控和管理。在多服务器部署中,可以充分发挥NGINX Plus监控和管理的各项功能;在更复杂的实施中,预编译代码和支持也能发挥更大价值。

NGINX Open Source和NGINX Plus均支持内容缓存和微缓存(也称为“应用缓存”)。在Web服务器场景中,缓存有助于减轻应用服务器的负载,但这两项功能仍共享同一台物理机或同一个虚拟机实例。在反向代理服务器上,缓存可以显著减轻应用服务器设备的工作负载,从而带来更大的性能优势。

可直接从nginx.org下载NGINX Open Source软件,还可在该网站获取社区支持。如需订阅单个NGINX Plus实例,请注册30天免费试用或在线购买。如需多实例套餐,请联系NGINX销售团队。

技巧 3:将 Apache 配置转换为 NGINX 语法

将Web服务器软件从Apache迁移到NGINX时,需要进行一些更改。有关详情,请参阅文章,发布于sitepoint.com:

  • 创建或转换配置文件。修改配置代码,指定NGINX(不再是Apache)应使用哪些文件进行配置。
  • 更改读写权限。为您的账户添加权限,以便对网站根目录中的文件执行CRUD操作(创建、读取、更新、删除)。
  • 指定有效的搜索模式。添加location块,指定NGINX在处理请求时可以和不可以尝试的模式。
  • 替换.htaccess配置代码。Apache的配置详细信息通常位于.htaccess文件或静态配置文件中(例如mod_rewrite指令)。请在NGINX配置文件中使用相关配置规范替换这些内容。有关示例,请参阅我们的博客。

进行这些更改有助于您熟悉NGINX,并为优化更复杂的网站做好准备,具体内容将在本博文第2部分中介绍。不过,如果这些配置更改会给网站运营带来难以接受的工作量或风险,也不必担心。无需将核心Web服务器软件从Apache升级,即可实施第2部分所述的多服务器架构,因此也无需更改Web服务器配置文件。

技巧4:实施静态文件缓存

静态文件就是不经常发生变化的文件,至少从Web服务器的角度来看是这样。静态文件通常包括JPEG和PNG等图像文件,以及CSS和JavaScript等代码文件。如果将这些文件放在应用服务器或单独的数据库服务器上,对这些文件的请求就必须由应用程序代码处理,并产生发起和完成请求所需的全部开销。这会“分散”应用服务器处理更重要工作的资源,并可能使其更接近物理内存过载的临界点,导致新请求触发当前请求的数据换出到磁盘。

静态文件缓存是NGINX的一项核心功能。可以在Web服务器或反向代理服务器上实现静态文件缓存:

  • 在NGINX Web服务器上,静态文件缓存可减轻应用服务器的负载,加快文件检索速度,并显著降低内存开销。但是,文件检索仍由同一物理服务器或虚拟服务器实例处理,因此服务器的处理器除了运行应用外,仍需处理其他任务。
  • NGINX反向代理服务器与Web服务器运行在不同的计算机或实例上,因此缓存静态文件不会占用应用服务器的资源。应用服务器可以专注于运行应用。

在NGINX上实现静态文件缓存总体分为三个步骤:

  • 指定搜索的根目录。
  • <ul><li>处理请求。</li></ul>
  • 优化响应速度。

在不涉及反向代理服务器的NGINX Web服务器上,并不会进行通常意义上的缓存。只需使用X-Accel-Redirect标头,将静态文件请求重定向到Web服务器。应用服务器不会收到该请求,因此可将全部资源用于处理应用请求。使用反向代理服务器时,则会使用静态文件缓存;运行应用的物理服务器或虚拟服务器实例无需参与响应静态文件请求。

以下配置片段展示了如何优化响应速度。它使NGINX能够使用操作系统的sendfile系统调用,无需将文件复制到中间缓冲区,从而减少一个文件传输步骤:

location /mp3 {    sendfile           on;
    sendfile_max_chunk 1m;
    # ...
}

有关配置NGINX进行静态文件缓存的详细信息,请参阅《NGINX Plus Admin Guide》。

技巧5:实施微缓存

容易让人混淆的是,微缓存有多种叫法,其中包括“应用缓存”,以及简称的“缓存”。在NGINX,我们使用“微缓存”一词,以强调此类文件的有效期很短。

假设有一个支持用户评论的博客文章页面。每当新访客进入该页面,或现有用户刷新页面以查看自己或他人的新评论时,您都希望页面显示最新的精彩评论。在这种情况下,每次有人访问时重新生成页面似乎是个不错的做法。

然而,“每次”都重新生成页面可能会带来沉重负担。如果某个页面每秒只有一次访问,那么每次访问时重新生成页面是合理的。但如果该页面每秒有10次、100次甚至1,000次访问,再加上网站其他所有页面的访问,应用服务器就可能不堪重负。这样一来,为用户提供最新内容的目标反而会导致所有人都无法快速获取任何内容。

微缓存是指生成一次页面,并将其缓存版本标记为在短时间内有效,例如1秒或几秒。缓存版本过期后,下一个请求会触发生成新页面,紧随其后的请求则会获取该页面的缓存版本。这与静态文件的处理方式相同,但时间周期要短得多。

此图指出了可在网站中的哪些位置查找适合进行微缓存的内容。此图出自F5的Owen Garrett撰写的一篇微缓存博客文章。

许多动态内容都适合进行微缓存

微缓存非常实用,因为它能在应用服务器最需要减轻负载时减少其工作量,同时对用户体验几乎没有影响,甚至完全没有影响。正因如此,一些系统已将其内置。Drupal认为其强大的内置微缓存功能至关重要,因此在Drupal生态中,微缓存直接称为“缓存”。

但Drupal的解决方案仍有不足,其他类似方案也是如此。应用服务器的工作量虽然有所减少,但配置、实施和文件提供仍需由Drupal(更广义地说,是PHP)负责。使用NGINX进行微缓存后,应用服务器只需按微缓存指定的频率生成新页面,其他工作均可卸载。它甚至不会收到其他请求,更不必为缓存命中存储或检索任何内容。

可以使用NGINX Plus或其他工具监控站点,确定哪些页面适合使用微缓存。以下配置片段为状态码为200的OK响应设置了1秒的缓存时间。

proxy_cache_path /tmp/cache keys_zone=cache:10m levels=1:2 inactive=600s max_size=100m;server {
    proxy_cache cache;
    proxy_cache_valid 200 1s;
    # ...
}

第1部分总结

这篇PHP博客文章的第1部分重点介绍单服务器解决方案和缓存。缓存在单服务器实施中很有效,而与反向代理服务器结合使用时效果更佳。第2部分介绍围绕PHP应用部署反向代理服务器和多服务器实施的优势。

如需试用NGINX Plus,可立即开始30天免费试用,或联系我们,讨论您的用例。


分享

关于作者

相关博客文章

NGINX Plus R26 正式发布
NGINX | 2022/02/15

NGINX Plus R26 正式发布

NGINX Plus R26通过缓存JSON Web密钥集加快JWT验证,并强化TLS握手,从而提升安全性。NGINX JavaScript的新功能包括增强对异步函数的支持,以及实现WebCrypto API。

使用NGINX App Protect DoS保护gRPC应用,抵御严重的DoS攻击
NGINX | 2022/02/10

使用NGINX App Protect DoS保护gRPC应用,抵御严重的DoS攻击

gRPC具备开发人员设计和部署现代应用所需的速度与灵活性,但其开放性也使其极易受到第7层DoS攻击。NGINX App Protect DoS可保护gRPC应用免受此类破坏性攻击。

Ingress Controller 选型指南(第 2 部分):风险与面向未来的规划
NGINX | 2021/09/13

Ingress Controller 选型指南(第 2 部分):风险与面向未来的规划

了解选择错误的Ingress控制器可能带来的风险,以及如何从关键方面着手,让您的选择更好地适应未来需求。

NGINX Plus R19 正式发布
NGINX | 2019/09/03

NGINX Plus R19 正式发布

NGINX Plus R19扩展了监控功能,不仅提供更多指标,还新增了指标分析方式;增加试运行模式,用于测试限速效果;增强键值存储,以支持IP地址范围;并使限速更加动态。

NGINX现已正式加入F5
NGINX | 2019/05/09

NGINX现已正式加入F5

NGINX现已正式成为F5的一部分。Gus Robertson现任F5 NGINX业务部门负责人。他阐述了两家公司在人才、文化和愿景方面融合的价值,以及双方将如何携手增强NGINX的开源产品和商业产品。

使用NGINX和NGINX Plus实现高性能缓存
NGINX | 2016/08/24

使用NGINX和NGINX Plus实现高性能缓存

我将介绍NGINX在内容缓存和性能方面的工作原理,并分享一些控制NGINX内容缓存方式的技巧。