提高 Web 应用程序性能比以往任何时候都更加重要。在线经济活动的份额正在增长; 超过 5% 的发达世界经济现在在 Internet 上。我们永远在线、高度连接的现代世界意味着用户的期望比以往任何时候都高。如果您的网站没有立即响应,或者如果您的应用程序无法立即运行,用户会迅速转向您的竞争对手。
例如,亚马逊在将近 10 年前进行的一项研究证明,即便如此,页面加载时间减少 100 毫秒也会转化为收入增加 1%。 最近的另一项研究 强调了这样一个事实,即超过一半的受访网站所有者表示,由于应用程序性能不佳,他们失去了收入或客户。
网站需要多快?页面加载的每一秒, 大约有 4% 的用户放弃它。顶级电子商务网站提供从 1 到 3 秒的首次交互时间,这提供了最高的 转化率 。很明显,Web 应用程序性能的风险很高并且可能会增长。
想要提高成绩很容易,但真正看到效果却很难。为了帮助您踏上旅程,这篇博文为您提供了十个技巧,可帮助您将网站性能提高 10 倍之多。这是一系列详细介绍如何借助一些经过充分测试的优化技术以及 NGINX 的少量支持来提高应用程序性能的系列中的第一篇。本系列还概述了您在此过程中可以获得的潜在安全改进。
技巧 #1:使用反向代理服务器加速和保护应用程序
如果您的 Web 应用程序在一台机器上运行,性能问题的解决方案可能看起来很明显:只需获得一台速度更快的机器,配备更多处理器、更多 RAM、更快的磁盘阵列等等。然后新机器可以比以前更快地运行您的 WordPress 服务器、Node.js 应用程序、Java 应用程序等。 (如果您的应用程序访问数据库服务器,解决方案可能看起来仍然很简单:获得两台速度更快的机器,并在它们之间建立更快的连接)。
问题是,机器速度可能不是问题所在。 Web 应用程序通常运行缓慢,因为计算机在不同类型的任务之间切换:在数千个连接上与用户交互、从磁盘访问文件以及运行应用程序代码等等。应用程序服务器可能会出现抖动——内存不足,将内存块交换到磁盘,并使许多请求等待单个任务(如磁盘 I/O)。
您可以采用完全不同的方法,而不是升级您的硬件:添加一个反向代理服务器来卸载其中的一些任务。 反向代理服务器 位于运行应用程序的机器前面并处理 Internet 流量。只有反向代理服务器直接连接到互联网;与应用程序服务器的通信是通过一个快速的内部网络进行的。
使用反向代理服务器使应用程序服务器不必等待用户与 Web 应用程序交互,并让它专注于为反向代理服务器构建要通过 Internet 发送的页面。不再需要等待客户端响应的应用程序服务器可以以接近优化基准所达到的速度运行。
添加反向代理服务器还增加了 Web 服务器设置的灵活性。例如,如果给定类型的服务器过载,则可以轻松添加另一台相同类型的服务器;如果服务器出现故障,可以很容易地更换它。
由于它提供的灵活性,反向代理服务器也是许多其他性能提升功能的先决条件,例如:
- 负载均衡 (参见 技巧#2 )——负载均衡器在反向代理服务器上运行,以在多个应用程序服务器之间平均共享流量。有了负载均衡器,您就可以添加应用程序服务器而无需更改您的应用程序。
- 缓存静态文件 (参见 技巧#3 )——直接请求的文件,例如图像文件或代码文件,可以存储在反向代理服务器上并直接发送给客户端,从而更快地提供资产并卸载应用程序服务器,让应用程序运行得更快。
- 保护您的站点 – 反向代理服务器可以配置为高安全性并进行监控以快速识别和响应攻击,从而保护应用程序服务器。
NGINX 软件专门设计用作反向代理服务器,具有上述附加功能。 NGINX 使用事件驱动的处理方式,比传统服务器更高效。 NGINX Plus 添加了更多高级反向代理功能,例如应用程序 健康检查 、专用请求路由、高级缓存和支持。
技巧 #2:添加负载均衡器
添加 负载均衡器 是一个相对容易的更改,可以显着提高站点的性能和安全性。您可以使用负载均衡器在多个服务器之间分配流量,而不是让核心 Web 服务器变得更大、更强大。即使应用程序编写得不好,或者在扩展方面存在问题,负载均衡器也可以在不进行任何其他更改的情况下改善用户体验。
负载均衡器首先是一个反向代理服务器(请参阅 提示 #1 )——它接收 Internet 流量并将请求转发到另一台服务器。诀窍是负载平衡器支持两个或多个应用程序服务器,使用 算法选择 在服务器之间拆分请求。最简单的负载平衡方法是循环法,每个新请求都发送到列表中的下一个服务器。其他方法包括向活动连接最少的服务器发送请求。 NGINX Plus 具有在同一台服务器上继续给定用户会话的 功能 ,这称为会话持久性。
负载平衡器可以显着提高性能,因为它们可以防止一台服务器在其他服务器等待流量时过载。它们还可以轻松扩展您的 Web 服务器容量,因为您可以添加成本相对较低的服务器并确保它们得到充分利用。
可以负载均衡的协议包括 HTTP、HTTPS、SPDY、HTTP/2、WebSocket、 FastCGI 、SCGI、uwsgi、memcached 和其他几种应用程序类型,包括基于 TCP 的应用程序和其他第 4 层协议。分析您的 Web 应用程序以确定您使用的是哪个应用程序以及性能落后的地方。
用于负载平衡的同一台或多台服务器还可以处理其他几项任务,例如 SSL 终止、支持客户端使用 HTTP/1/x 和 HTTP/2 以及缓存静态文件。
NGINX 通常用于负载均衡;要了解更多信息,请参阅我们的 概述博文 、 配置博文 、 电子书 和相关 网络研讨会 以及 文档 。我们的商业版本 NGINX Plus 支持更专业的负载平衡功能,例如基于服务器响应时间的负载路由以及在 Microsoft 的 NTLM 协议上进行负载平衡的能力。
技巧 #3:缓存静态和动态内容
缓存通过更快地向客户端交付内容来提高 Web 应用程序的性能。缓存可能涉及多种策略:预处理内容以便在需要时快速交付、将内容存储在更快的设备上、将内容存储在更靠近客户端的位置,或组合使用。
有两种不同类型的缓存需要考虑:
- 缓存静态内容 。不经常更改的文件,例如图像文件(JPEG、PNG)和代码文件(CSS、JavaScript),可以存储在边缘服务器上,以便从内存或磁盘中快速检索。
- 缓存动态内容 。许多 Web 应用程序为每个页面请求生成新的 HTML。通过将生成的 HTML 的一份副本短暂缓存一段时间,您可以显着减少必须生成的页面总数,同时仍然提供足够新鲜的内容来满足您的要求。
例如,如果某个页面每秒获得 10 次浏览,并且您将其缓存一秒钟,则该页面 90% 的请求将来自缓存。如果您单独缓存静态内容,即使是新生成的页面版本也可能主要由缓存内容组成。
缓存 Web 应用程序生成的内容主要有三种技术:
- 使内容更贴近用户 。将内容的副本保持在离用户较近的位置可以减少其传输时间。
- 将内容移动到更快的机器上 。内容可以保存在更快的机器上,以便更快地检索。
- 将内容从过度使用的机器上移走 。机器在执行特定任务时有时会比其基准性能慢得多,因为它们正忙于其他任务。在不同的机器上缓存可以提高缓存资源和非缓存资源的性能,因为主机过载较少。
Web 应用程序的缓存可以从内部(Web 应用程序服务器)实现。首先,缓存用于动态内容,以减少应用服务器的负载。然后,缓存用于静态内容(包括动态内容的临时副本),进一步卸载应用程序服务器。然后将缓存从应用程序服务器转移到速度更快和/或更接近用户的机器上,从而减轻应用程序服务器的负担,并减少检索和传输时间。
改进的缓存可以极大地加快应用程序的速度。对于许多网页来说,静态数据(例如大图像文件)占了一半以上的内容。在没有缓存的情况下检索和传输此类数据可能需要几秒钟,但如果数据在本地缓存则只需几分之一秒。
作为在实践中如何使用缓存的示例,NGINX 和 NGINX Plus 使用两个指令来
设置缓存
:
proxy_cache_path
和
proxy_cache
。您指定缓存位置和大小、文件在缓存中保留的最长时间以及其他参数。使用第三个(也是非常流行的)指令
proxy_cache_use_stale
,您甚至可以在提供新内容的服务器繁忙或关闭时指示缓存提供陈旧内容,为客户端提供一些东西而不是什么都没有。从用户的角度来看,这可能会大大提高您的站点或应用程序的正常运行时间。
NGINX Plus 具有 高级缓存功能 ,包括支持 缓存清除 和在 仪表板上 可视化缓存状态以进行实时活动监控。
有关使用 NGINX 进行缓存的更多信息,请参阅 参考文档 和 NGINX Plus 管理指南中的 NGINX 内容缓存 。
注意 :缓存跨越了开发应用程序的人员、做出资本投资决策的人员以及实时运行网络的人员之间的组织界限。复杂的缓存策略,就像这里提到的那些,是 DevOps 视角 价值的一个很好的例子,其中应用程序开发人员、架构和操作视角被合并以帮助实现站点功能、响应时间、安全性和业务结果的目标,例如完成的交易或销售。
技巧 #4:压缩数据
压缩是一个巨大的潜在性能加速器。有针对照片(JPEG 和 PNG)、视频 (MPEG-4) 和音乐 (MP3) 等精心设计的高效压缩标准。这些标准中的每一个都将文件大小减少了一个数量级或更多。
文本数据——包括 HTML(包括纯文本和 HTML 标签)、CSS 和 JavaScript 等代码——通常在未压缩的情况下传输。压缩此数据会对感知性能产生不成比例的影响,尤其是对于移动连接速度慢或受限的客户端。
这是因为文本数据通常足以让用户与页面交互,而多媒体数据可能更具支持性或装饰性。智能内容压缩可以减少 HTML、Javascript、CSS 和其他基于文本的内容的带宽需求,通常减少 30% 或更多,同时相应地减少加载时间。
如果您使用 SSL,压缩会减少必须进行 SSL 编码的数据量,这会抵消压缩数据所需的部分 CPU 时间。
压缩文本数据的方法各不相同。例如,请参阅
有关 HTTP/2 的部分
,了解一种新颖的文本压缩方案,专门针对标头数据进行调整。作为文本压缩的另一个示例,您可以在 NGINX 中
打开
GZIP 压缩。在服务上
预压缩文本数据
后,可以使用
gzip_static
指令直接提供压缩的
.gz
版本。
提示 #5:优化 SSL/TLS
越来越多的网站正在使用安全套接字层 ( SSL ) 协议及其后继传输层安全 (TLS) 协议。 SSL/TLS 对从原始服务器传输到用户的数据进行加密,以帮助提高站点安全性。可能影响这一趋势的部分原因是谷歌现在使用 SSL/TLS 作为对搜索引擎排名的积极影响。
尽管越来越受欢迎,但 SSL/TLS 对性能的影响是许多网站的症结所在。 SSL/TLS 降低网站性能的原因有两个:
- 每当打开新连接时,建立加密密钥所需的初始握手。使用 HTTP/1.x 的浏览器为每个服务器建立多个连接的方式使命中率成倍增加。
- 在服务器上加密数据并在客户端解密数据的持续开销。
为了鼓励使用 SSL/TLS,HTTP/2 和 SPDY 的作者(在 下一节 中描述)设计了这些协议,以便浏览器在每个浏览器会话中只需要一个连接。这大大减少了 SSL 开销的两个主要来源之一。然而,今天可以做更多的工作来提高通过 SSL/TLS 交付的应用程序的性能。
优化 SSL/TLS 的机制因 Web 服务器而异。例如,NGINX 使用在标准商品硬件上运行的 OpenSSL 来提供类似于专用硬件解决方案的性能。 NGINX SSL 性能 有据可查,可最大限度地减少执行 SSL/TLS 加密和解密的时间和 CPU 损失。
此外,请参阅 此博客文章 以了解有关提高 SSL/TLS 性能的方法的详细信息。简而言之,这些技术是:
-
会话缓存
。使用
ssl_session_cache
指令缓存在使用 SSL/TLS 保护每个新连接时使用的参数。 - 会话票证或 ID 。这些将有关特定 SSL/TLS 会话的信息存储在票证或 ID 中,因此可以顺利地重用连接,而无需新的握手。
- OCSP 装订 。通过缓存 SSL/TLS 证书信息来缩短握手时间。
NGINX 和 NGINX Plus 可用于 SSL/TLS 终止——处理客户端流量的加密和解密,同时以明文形式与其他服务器通信。使用 这些步骤 设置 NGINX 或 NGINX Plus 来处理 SSL/TLS 终止。此外,这里是 NGINX Plus 与接受 TCP 连接的服务器一起使用时的 具体步骤 。
技巧 #6:实施 HTTP/2 或 SPDY
对于已经使用 SSL/TLS 的站点,HTTP/2 和 SPDY 很可能会提高性能,因为单一连接只需要一次握手。对于尚未使用 SSL/TLS 的站点,HTTP/2 和 SPDY 从响应性的角度来看,转向 SSL/TLS(通常会降低性能)是一种洗礼。
谷歌在 2012 年推出了 SPDY,作为在 HTTP/1.x 之上实现更快性能的一种方式。 HTTP/2 是最近批准的基于 SPDY 的 IETF 标准。 SPDY 得到广泛支持,但很快就会被弃用,取而代之的是 HTTP/2。
SPDY 和 HTTP/2 的关键特性是使用单个连接而不是多个连接。单个连接是多路复用的,因此它可以同时承载多个请求和响应。
通过充分利用一个连接,这些协议避免了设置和管理多个连接的开销,正如浏览器实现 HTTP/1.x 的方式所要求的那样。使用单一连接对 SSL 特别有用,因为它最大限度地减少了 SSL/TLS 建立安全连接所需的耗时握手。
SPDY 协议需要使用 SSL/TLS; HTTP/2 并未正式要求它,但目前所有支持 HTTP/2 的浏览器仅在启用 SSL/TLS 时才使用它。也就是说,只有当网站使用 SSL 并且其服务器接受 HTTP/2 流量时,支持 HTTP/2 的浏览器才会使用它。否则,浏览器通过 HTTP/1.x 进行通信。
当您实施 SPDY 或 HTTP/2 时,您不再需要典型的 HTTP 性能优化,例如域分片、资源合并和图像精灵。这些更改使您的代码和部署更简单、更易于管理。要详细了解 HTTP/2 带来的变化,请阅读我们的 白皮书 。
作为支持这些协议的一个例子,NGINX 从很早就开始支持 SPDY,现在 大多数使用 SPDY 的站点都 运行在 NGINX 上。 NGINX 还 率先支持 HTTP/2,截至 2015 年 9 月,NGINX 开源和 NGINX Plus 都 支持 HTTP/2。
随着时间的推移,我们 NGINX 期望大多数站点完全启用 SSL 并迁移到 HTTP/2。这将提高安全性,并且随着发现和实施新的优化,更简单的代码性能更好。
技巧 #7:更新软件版本
提高应用程序性能的一种简单方法是根据组件在稳定性和性能方面的声誉为您的软件堆栈选择组件。此外,由于高质量组件的开发人员可能会随着时间的推移追求性能增强和修复错误,因此使用最新稳定版本的软件是值得的。新版本受到开发人员和用户社区的更多关注。较新的版本还利用了新的编译器优化,包括针对新硬件的调整。
稳定的新版本通常比旧版本更兼容、性能更高。当您掌握软件更新时,也更容易掌握调整优化、错误修复和安全警报。
继续使用旧软件也会妨碍您利用新功能。例如,上面描述的 HTTP/2 目前需要 OpenSSL 1.0.1。从 2016 年年中开始,HTTP/2 将需要 2015 年 1 月发布的 OpenSSL 1.0.2。
NGINX 用户可以从迁移到 最新版本的 NGINX 开源软件 或 NGINX Plus 开始;它们包括新功能,如套接字分片和线程池(见下文),并且两者都在不断调整性能。然后在堆栈中更深入地查看软件,并尽可能移动到最新版本。
技巧 #8:调整 Linux 的性能
Linux 是当今大多数 Web 服务器实施的底层操作系统,作为基础架构的基础,Linux 代表了提高性能的重要机会。默认情况下,许多 Linux 系统被保守地调整为使用很少的资源并匹配典型的桌面工作负载。这意味着 Web 应用程序用例至少需要一定程度的调整才能获得最佳性能。
Linux 优化是特定于 Web 服务器的。以 NGINX 为例,以下是您可以考虑加速 Linux 的一些更改要点:
-
积压队列
。如果您的连接似乎停滞不前,请考虑增加
net.core.somaxconn
,这是可以排队等待 NGINX 关注的最大连接数。如果现有连接限制太小,您将看到错误消息,您可以逐渐增加此参数,直到错误消息停止。 -
文件描述符
。 NGINX 为每个连接最多使用两个文件描述符。如果您的系统提供大量连接,您可能需要增加
sys.fs.file_max
,即系统范围内的文件描述符限制,以及nofile
,即用户文件描述符限制,以支持增加的负载。 -
临时端口
。当用作代理时,NGINX 为每个上游服务器创建临时(“临时”)端口。您可以增加由
net.ipv4.ip_local_port_range
设置的端口值范围,以增加可用端口的数量。您还可以通过net.ipv4.tcp_fin_timeout
设置减少非活动端口重新使用之前的超时时间,从而加快周转速度。
对于 NGINX,请查看 NGINX 性能调优指南, 了解如何优化您的 Linux 系统,使其能够轻松应对大量网络流量!
技巧 #9:调整 Web 服务器的性能
无论您使用什么 Web 服务器,都需要对其性能进行调整。以下建议通常适用于任何 Web 服务器,但针对 NGINX 给出了特定设置。关键优化包括:
-
访问日志记录
。您可以在内存中缓冲条目并将它们作为一个组写入磁盘,而不是立即将每个请求的日志条目写入磁盘。对于 NGINX,将
buffer= size
参数添加到access_log
指令以在内存缓冲区填满时将日志条目写入磁盘。如果添加 flush= time 参数,缓冲区内容也会在指定时间后写入磁盘。 -
缓冲
。缓冲将部分响应保存在内存中,直到缓冲区填满,这可以提高与客户端的通信效率。不适合内存的响应将写入磁盘,这会降低性能。当 NGINX 缓冲
开启
时,您可以使用
proxy_buffer_size
和proxy_buffers
指令来管理它。 -
客户端保活
。 Keepalive 连接减少开销,尤其是在使用 SSL/TLS 时。对于 NGINX,您可以增加客户端可以通过给定连接发出的最大
keepalive_requests
数,默认值为 100,并且您可以增加keepalive_timeout
以允许 keepalive 连接保持打开的时间更长,从而使后续请求更快。 -
上游保活
。上游连接——与应用程序服务器、数据库服务器等的连接——也受益于保活连接。对于上游连接,您可以增加
keepalive
,即为每个工作进程保持打开状态的空闲 keepalive 连接数。这允许增加连接重用,减少打开全新连接的需要。有关保活的更多信息,请参阅此 博客文章 。 -
限制
。限制客户端使用的资源可以提高性能和安全性。对于 NGINX,
limit_conn
和limit_conn_zone
指令限制来自给定源的连接数,而limit_rate
限制带宽。这些设置可以阻止合法用户“霸占”资源,还有助于防止攻击。limit_req
和limit_req_zone
指令限制客户端请求。对于与上游服务器的连接,请将max_conns
参数用于上游配置块中的服务器指令。这限制了与上游服务器的连接,防止过载。关联的queue
指令创建一个队列,在达到max_conns
限制后,该队列在指定的时间长度内保存指定数量的请求。 -
工人进程
。工作进程负责处理请求。 NGINX 采用基于事件的模型和依赖于操作系统的机制来有效地在工作进程之间分发请求。建议将
worker_processes
的值设置为每个 CPU 一个。如果需要,可以在大多数系统上安全地提高worker_connections
的最大数量(默认为 512);尝试找到最适合您的系统的值。 -
套接字分片
。通常,单个套接字侦听器将新连接分发给所有工作进程。套接字分片为每个工作进程创建一个套接字侦听器,内核在套接字侦听器可用时将连接分配给它们。这可以减少锁争用并提高多核系统的性能。要启用
套接字分片
,请在
listen
指令中包含reuseport
参数。 -
线程池
。任何计算机进程都可能被一个缓慢的操作所阻碍。对于 Web 服务器软件,磁盘访问可以阻止许多更快的操作,例如在内存中计算或复制信息。当使用线程池时,慢速操作被分配给一组单独的任务,而主处理循环继续运行较快的操作。磁盘操作完成后,结果返回主处理循环。在 NGINX 中,两个操作
read()
系统调用和sendfile()
——被卸载到 线程池 。
提示 。更改任何操作系统或支持服务的设置时,一次更改一个设置,然后测试性能。如果更改导致问题,或者如果它不能使您的站点运行得更快,请将其更改回来。
有关调整 NGINX 的更多详细信息,请参阅此 博客文章 。
技巧 #10:监控实时活动以解决问题和瓶颈
应用程序开发和交付的高性能方法的关键是密切实时地观察应用程序的实际性能。您必须能够监控特定设备内和整个 Web 基础设施中的活动。
监控站点活动主要是被动的——它会告诉您发生了什么,然后让您发现问题并解决问题。
监控可以发现几种不同类型的问题。他们包括:
- 服务器已关闭。
- 服务器运行缓慢,正在断开连接。
- 服务器的高速缓存未命中率很高。
- 服务器未发送正确的内容。
New Relic 或 Dynatrace 等全局监控工具可帮助您从远程位置监控页面加载时间,而 NGINX 可帮助您监控应用程序交付端。性能数据告诉您何时您的优化对您的用户产生了真正的影响,以及您何时需要考虑增加基础设施容量以维持流量。
为了帮助快速识别和解决问题,NGINX Plus 添加了 应用程序感知健康检查 ——定期重复的合成事务,用于提醒您注意问题。 NGINX Plus 还具有 会话耗尽功能 ,可在现有任务完成时停止新连接,以及慢启动功能,允许恢复的服务器在负载均衡组中达到速度。如果使用得当,运行状况检查可以让您在问题严重影响用户体验之前发现问题,而会话耗尽和启动缓慢可以让您更换服务器并确保该过程不会对感知性能或正常运行时间产生负面影响。该图显示了带有服务器、TCP 连接和缓存的 Web 基础设施的内置 NGINX Plus 实时活动监控 仪表板。
结论:看到 10 倍的性能提升
可用于任何一个 Web 应用程序的性能改进差异很大,实际收益取决于您的预算、可以投入的时间以及现有实施中的差距。那么,您如何才能将自己的应用程序的性能提高 10 倍呢?
为了帮助指导您了解每项优化的潜在影响,以下是上述每项提示可能带来的改进的指示,尽管您的里程几乎肯定会有所不同:
- 反向代理服务器和负载平衡 。没有负载平衡,或负载平衡不佳,都可能导致性能极差。添加反向代理服务器(例如 NGINX)可以防止 Web 应用程序在内存和磁盘之间颠簸。负载平衡可以将处理从负担过重的服务器转移到可用的服务器上,并使扩展变得容易。这些变化可以带来显着的性能提升,与当前实施的最差时刻相比,可以轻松实现 10 倍的提升,并且整体性能可以获得较小但实质性的成就。
- 缓存动态和静态内容 。如果您有一个负担过重的 Web 服务器,它作为您的应用程序服务器加倍,那么仅通过缓存动态内容就可以将峰值时间性能提高 10 倍。缓存静态文件也可以提高个位数倍数的性能。
- 压缩数据 。使用媒体文件压缩,例如照片的 JPEG、图形的 PNG、电影的 MPEG-4 和音乐文件的 MP3 可以大大提高性能。一旦这些都被使用,压缩文本数据(代码和 HTML)可以将初始页面加载时间缩短两倍。
- 优化 SSL/TLS 。安全握手会对性能产生重大影响,因此优化它们可能会使初始响应速度提高 2 倍,尤其是对于文本密集型站点。在 SSL/TLS 下优化媒体文件传输可能只会产生很小的性能改进。
- 实施 HTTP/2 和 SPDY 。当与 SSL/TLS 一起使用时,这些协议可能会导致整体站点性能的增量改进。
- 调整 Linux 和网络服务器软件(例如 NGINX) 。优化缓冲、使用保持活动连接以及将时间密集型任务卸载到单独的线程池等修复可以显着提高性能;例如,线程池可以将磁盘密集型任务的速度提高 近一个数量级 。
我们希望您亲自尝试这些技巧。我们希望听到您能够实现的性能改进。在下面的评论中分享您的结果,或使用井号标签#NGINX 和#webperf 在推特上发布您的故事!