
本文改编自Owen Garrett的网络研讨会,由Andrew Alexeev作开场介绍。
目录
简介
0:00 简介1:22 关于本次网络研讨会2:17 内容缓存的基本原理2:35 基本原理3:59 HTTP缓存机制7:46 NGINX缓存哪些内容?
内容缓存与NGINX
9:55 NGINX运行实况10:06 NGINX配置11:14 缓存过程15:32 缓存并非仅适用于HTTP17:10 如何了解当前状况17:38 缓存监测19:08 缓存监测(续)20:09 缓存状态21:57 NGINX中的内容缓存机制22:40 工作原理23:53 缓存内容如何存储?26:36 从磁盘加载缓存28:07 管理磁盘缓存29:22 从磁盘清除内容
控制缓存
31:27 控制缓存32:30 延迟缓存34:45 控制缓存时间36:18 缓存或不缓存37:25 多个缓存39:07 快速回顾:为什么要缓存?39:44 页面速度为何重要?40:46 Google更改了规则41:28 性能不佳的代价43:00 NGINX缓存助您实现更多功能45:21 总结
问答
47:20 字节范围请求49:13 代理缓存重新验证50:07 在同等磁盘间分布缓存50:50 Vary标头51:25 缓存原语51:52 上游标头和数据52:13 *‑Encoding标头52:56 SPDY53:15 Vary标头,第 2 轮53:45 PageSpeed54:00 其他缓存
0:00 简介

Andrew Alexeev:欢迎参加我们最新一期的网络研讨会,我是Andrew。NGINX由Igor Sysoev开发,旨在帮助全球网站提高运行速度和响应能力,并轻松扩展。如今,NGINX为超过30%的热门网站以及互联网上超过20%的网站提供支持。[编者注:这些统计数据为2014年5月举办本次网络研讨会时的数据;当前数据请参见此处。]希望本次网络研讨会的内容对您有所帮助,并可应用于现有或规划中的NGINX环境。
下面请允许我介绍Owen Garrett。Owen负责NGINX的产品开发。今天,他将讲解如何利用NGINX强大的缓存机制,让应用无需反复生成重复内容。
1:22 关于本次网络研讨会

Owen Garrett:谢谢Andrew,也非常感谢大家参加接下来45或50分钟的分享。我将介绍NGINX在内容缓存方面的工作原理,探讨一些提升性能的方法,并深入讲解内容缓存的实际工作机制,帮助大家调试和诊断NGINX内部的运行情况。最后,我会分享一些实用的提示和技巧,帮助大家精细控制NGINX处理可缓存内容的方式。
所有这些都服务于Andrew所说的同一个核心目标:减轻上游服务器重复生成内容的负担,使其能够专注运行企业真正需要的应用。通过扩展到这些服务器之外,为最终用户提供更好的服务,并在互联网流量激增以及上游服务器可能发生故障时,提高整体服务的可靠性。
2:17 内容缓存的基本原理

在介绍NGINX的实施配置之前,我想先快速回顾一下内容缓存的基本工作原理,确保大家对核心信息有一致的理解。
2:35 基本原理

内容缓存的基本原理是减轻上游服务器的重复工作负担。当第一位用户请求网站上的某项内容时(如蓝色图标和蓝色线条所示),其HTTP请求会先转发到NGINX,再由NGINX转发到右侧灰色的上游服务器。
响应会转发回远程用户,但如果该响应可缓存(稍后会介绍具体含义),NGINX便会存储该响应的副本。当另一位用户(图中橙色图标所示)请求相同内容时,NGINX可以直接从本地缓存提供该内容,而无需向上游服务器发出请求。
这种存储可缓存且不变内容的基本原理广泛应用于Web浏览器、CDN、使用CDN的访问站点,以及其他设备上的NGINX。NGINX充当反向代理缓存,通常部署在数据中心或云端,靠近托管Web内容和Web应用的源服务器。
3:59 HTTP缓存机制

源服务器使用一个或多个广为人知且含义明确的HTTP响应标头,声明内容是否可缓存。当然,缓存服务器可以选择忽略、覆盖或更改此行为。但要了解如何配置内容缓存,首先需要充分理解源服务器如何指明内容可缓存、不会发生变化,以及[缓存]副本具有特定的有效期。
内容缓存最初使用一个名为Expires的简单HTTP响应标头。源服务器提供内容,并声明该内容在Expires标头中指定的日期之前有效。这种方法很快被一种更有效、更灵活的方法所取代,即Cache-Control标头。
Expires的使用有些繁琐,效率也不高。日期需要采用正确的格式并进行解析,而Cache-Control则更加简洁,更符合内容缓存对功能和速度的要求。Cache-Control会将内容声明为公开或私有;如果是公开内容,还会声明max-age,即内容可缓存的秒数,超过该时间后,缓存对象需要重新请求该内容。
第3个直接控制缓存的标头是X-Accel-Expires。此标头是NGINX专用标头,只有NGINX能够识别。如果需要覆盖上述标头的行为,并直接明确告知NGINX某项内容应缓存多长时间,可以使用此标头。
在某些情况下,您可能希望Web浏览器长时间缓存内容,但让代理缓存(位于源服务器前端的NGINX)仅缓存较短时间。这样,内容变更可以更快生效并推送给新客户端,而旧客户端无需在没有必要时反复请求内容。
不过,也可以使用最后两个标头来实现该方法。源服务器可以声明某项内容的最后修改时间,还可以声明一个称为ETag(实体标签)的值,即用于标识该内容的不透明字符串,通常为哈希值。
然后,客户端可以使用条件GET发出请求。请求中可以包含If-Modified-Since或If-None-Match标头。这样,客户端就会声明自己拥有该内容的缓存版本,并提供其上次修改日期或特定的ETag。如果服务器保存的最新版本与客户端拥有的版本相匹配,服务器只需返回304 Not Modified。这种响应速度快,可节省网络带宽,并让客户端在方便时检查内容的缓存副本是否仍然有效。
从源服务器的角度来看,这五个标头定义了内容的缓存方式,包括内容的有效性、新鲜度,以及通过ETag定义的内容本身的详细信息。
7:46 NGINX缓存哪些内容?

NGINX等代理缓存可以相对灵活地决定遵循这些标头的严格程度。显然,它们不应缓存不可缓存的内容;但即使源服务器指明某些内容可缓存,它们也没有义务一定要缓存。
NGINX的基本行为是缓存源服务器指示为可缓存的所有GET和HEAD请求,前提是响应中不包含Set-Cookie标头。这是因为Set-Cookie标头通常包含每个请求特有的数据,默认情况下不适合缓存该值。
NGINX使用特定的键(即缓存键)缓存每个资源。生成相同缓存键的所有请求都将获得同一资源。默认情况下,缓存映射到原始URL;在配置中,则映射到本幻灯片所示的字符串[$scheme$proxy_host$uri$is_args$args]。NGINX缓存内容时,[有效期]按以下优先顺序确定:如果存在X-Accel-Expires标头,则由该标头确定;否则由Cache-Control标头确定;再否则由旧版Expires标头确定。
可以调整NGINX,使其忽略其中某些标头,或改为设置固定的缓存时间,而完全不受源服务器响应的影响。有关HTTP代理缓存的预期行为,请参阅RFC 2616。
以上简要介绍了缓存的普遍适用性,以及NGINX缓存通常可安全缓存的内容时所采用的基本默认行为,从而帮助提升网站速度并减轻源服务器的负载。
9:55 NGINX实际运行

现在来看看NGINX的实际运行情况。配置NGINX以启用内容缓存非常简单。
10:06 NGINX配置

只需在NGINX配置文件中添加几行内容。第一行用于在磁盘上创建缓存,并通过一组参数指定文件的存放方式、[该缓存中对象的]过期时间以及缓存大小。第二行是proxy_cache指令,它与NGINX代理关联,用于指示代理将内容(结果、响应)缓存到指定名称的缓存中。
这里,我创建了一个名为“one”的缓存;内存中用于存储元数据的空间为10 MB,而磁盘上用于存储缓存内容的空间不受限制。内容缓存后,如果60分钟内未被访问,就会被清除。名为“one”的缓存由默认服务器使用。以下两个指令:proxy_cache_path和proxy_cache,足以为NGINX中的代理服务器启用可靠且一致的缓存。
11:14 缓存过程

NGINX收到请求并查询缓存时的处理流程如下。首先读取请求(本幻灯片左上角的方框),然后根据原始URI和其他参数生成缓存键,用于标识与该请求对应的资源。接下来,通过访问内存中的元数据来检查磁盘缓存,确认是否存在该请求响应的有效且未过期副本。
如果有,则视为缓存命中。随后,NGINX可以直接从缓存响应。NGINX从缓存响应时,会从磁盘提供内容,方式与提供静态内容完全相同。因此,可以获得NGINX设计所支持的性能、可靠性和可扩展性水平。通过NGINX内容缓存提供内容时,可以获得与提供静态内容完全相同的[性能]水平。
另一方面,检查缓存时,可能会出现缓存未命中。这意味着缓存中没有相应内容,或者缓存内容已过期,需要刷新。在最简单的情况下,缓存未命中后,NGINX会向源服务器请求该内容,接收响应,并检查响应是否可缓存。
如果可以缓存,我们会将响应以流式方式写入磁盘,就像NGINX处理代理模式下的任何大型响应一样。响应以流式方式写入磁盘后,我们会将其复制到缓存中,并直接从缓存返回响应。这种方法面临的一个挑战是,NGINX可能会同时收到针对同一内容的多个请求,而这些请求都发生缓存未命中。
NGINX通常会将所有这些请求转发到源服务器,这可能会导致源服务器过载,尤其是对于需要较长时间才能生成响应的请求。因此,可以使用缓存锁。proxy_cache_lock指令可确保在刷新某项内容时,每次只向上游服务器发送一个请求。
因此,在上述场景中,第一个请求会发送到上游服务器,而针对同一内容的其余请求将被暂缓,直到响应已返回并写入缓存(此时即可满足所有请求),或者达到由 proxy_cache_lock_timeout 指令设置的超时时间。达到超时时间意味着NGINX等待服务器返回内容的时间已足够长,此时,被暂缓的请求将转发到源服务器。
因此,proxy_cache_lock和超时设置提供了强大的控制能力,可确保在繁忙站点收到大量针对同一内容的请求时,即使该内容在缓存中过期,也不会因多个请求突然涌入而导致源服务器过载。
NGINX缓存过程中还有一个要素不太适合直接放入此流程图,因为它几乎涵盖了图中的每个阶段。这项功能通过proxy_cache_use_stale指令进行配置。在任何时候,如果其中某个阶段因某种原因失败,例如更新内容时发生超时、收到上游服务器的错误响应或遇到其他类型的错误,都可以选择直接使用缓存进行响应,即使缓存的内容已过期。
当上游服务器因流量过大而不堪重负,或因维护或灾难性错误而发生故障时,这项工具非常实用。它可确保NGINX继续使用缓存中的过期内容提供服务,而不是向客户端返回错误消息。
15:32 缓存并非仅适用于HTTP

NGINX中的缓存并非仅适用于HTTP。NGINX也不只是将请求转发到上游Web服务器的HTTP代理。通常,这些上游Web服务器用于与FastCGI或SCGI等API交互。NGINX可以直接以与HTTP代理非常相似的方式代理这些API。
NGINX可将其缓存技术用于HTTP代理、FastCGI代理、uWSGI代理和SCGI代理。这些代理的工作方式与HTTP代理大致相同:缓存存储在磁盘上,并可直接响应请求,无需将请求代理到这些上游服务。
NGINX还可以与memcached服务器对接,这是一种略有不同的缓存方式。在这种情况下,NGINX不直接存储内容,而是将memcached用作代理,并依靠外部代理程序将所需内容填充到memcached中。这也可以成为一种实用工具;如有必要,可通过多种方式从外部站点向memcached填充内容。因此,如果业务有此需求,可以将其视为一种为NGINX预填充缓存的方式。
17:10 如何了解当前状况

如果您的大型基础设施包含多个层级,其中有些层级执行缓存,有些不执行;有些生成内容,有些不生成,那么缓存可能会变得非常复杂。要跟踪系统的运行情况和内容来源,并诊断和调试遇到的任何问题,可能颇具挑战性。NGINX会尽可能简化这些工作。
17:38 缓存监测

借助一些先进的检测工具,可以动态控制检测过程,跟踪内容的来源、内容在缓存中的存储位置及其缓存状态。
第一步是使用$upstream_cache_status变量。无论响应是否来自缓存,NGINX都会为其响应的每个请求计算该变量。然后,使用add_header指令持续将该变量的值添加到响应中。通常,我们会将该值放入响应的X-Cache-Status标头中。该变量有7种不同的取值,用于说明相应内容的提供方式,例如是否绕过缓存、是否来自重新验证,或是否命中缓存。
这是了解响应来源的第一步。响应是来自本地NGINX缓存,还是来自上游服务器?您可以通过多种方式检查该响应标头,例如在命令行中使用curl等工具,或使用Web浏览器中常见的交互式调试器。
当然,您可能不希望向所有最终用户公开该值。因此,应有选择地决定何时将该值插入响应标头。
19:08 缓存检测(续)

NGINX的配置语言让您可以灵活地选择性处理。这只是众多实现方式中的一种。在此示例中,我们获取远程地址;如果该地址恰好是localhost,则将$upstream_cache_status存入临时变量($cache_status)。最后,在返回响应时,将该临时变量放入响应中。
这样,只有来自指定IP地址的请求才能看到$upstream_cache_status变量的值。还可以执行许多其他操作。接下来,我们将了解内容如何存储在磁盘上。可以将用于计算磁盘存储位置的键添加到响应中,也可以在响应中添加各种参数,以便在缓存运行时进行诊断。
20:09 缓存状态

NGINX Plus是NGINX的商业版本,提供多项附加功能,可支持缓存等使用场景。NGINX Plus是由我们位于莫斯科的工程团队构建并提供商业支持的NGINX版本,经过全面的回归测试,以确保正常运行。
NGINX Plus还提供多项功能,面向希望将NGINX用作反向代理和负载均衡器的企业,包括负载均衡、运行状况检查和高级视频流功能。此外,还提供扩展状态、更完善的诊断功能,以及NGINX运行状况的可视化功能。
[编辑注:上方幻灯片和以下段落已更新为引用NGINX Plus API。该API取代了此处原先讨论的独立状态模块,后者现已弃用。]
如需查看演示,可以访问demo.nginx.com/dashboard.html。该网页会显示NGINX Plus通过NGINX Plus API发布的状态数据。如果运行所示的curl命令,还会看到直接从NGINX Plus二进制文件获取的原始JSON数据(此处通过管道将其传递给jq实用工具,使每个元素单独成行并按层级缩进)。
在这些JSON数据中,可以找到NGINX Plus部署中每个缓存的实时状态数据。结合$upstream_cache_status变量及其他缓存监测方式,可以全面了解NGINX如何缓存内容,还可深入分析单个请求,确定该请求是否来自缓存及其当前缓存状态。
21:57 NGINX中的内容缓存如何运作

了解如何从外部检查内容缓存后,现在让我们从内部看看它。它在NGINX中如何运作?如前所述,NGINX内容缓存的运作方式与处理磁盘文件大致相同。通过内容缓存提供内容时,可以获得与提供静态内容时相同的性能、可靠性和操作系统优化,也就是NGINX广受认可的性能。
22:40 工作原理

内容缓存以持久缓存的形式存储在磁盘上。我们与操作系统协同,将磁盘缓存换入内存,并向操作系统的页面缓存提示应将哪些内容存储在内存中。因此,需要从缓存提供内容时,可以非常快速地完成。
缓存的相关元数据(包括缓存中的内容及其过期时间)单独存储在所有NGINX进程共享的内存区域中,并始终驻留在内存中。因此,NGINX可以极快地查询和搜索缓存;只有在需要提取响应并将其返回给最终用户时,才会访问页缓存。
我们将介绍内容如何存储在缓存中、启动时如何将持久缓存加载到空的NGINX工作进程中,以及NGINX自动执行的一些缓存维护操作。最后,我们将说明如何在特定情况下手动清理缓存中的内容。
23:53 缓存内容如何存储?

您可能还记得,内容缓存使用名为“proxy_cache_path”的指令进行声明。此指令指定多个参数:缓存存储在文件系统中的位置、缓存名称、用于存储元数据的内存缓存大小,以及磁盘缓存大小。在本例中,磁盘缓存大小为40 MB。
要了解内容的存储位置,关键在于理解缓存键,即NGINX为每个可缓存资源分配的唯一标识符。默认情况下,该标识符由请求的基本参数组成:协议、Host标头、URI以及所有字符串参数。
不过,也可以根据需要扩展缓存键,例如加入Cookie值、身份验证标头,甚至运行时计算出的值。例如,您可能希望为英国用户和美国用户存储不同的版本。通过配置proxy_cache_key指令,即可实现这些需求。
NGINX处理请求时,会计算proxy_cache_key,然后根据该值计算MD5校验和。您可以使用幻灯片下方所示的命令行示例自行重现这一过程。我们将缓存键httplocalhost:8002/time.php传递给md5sum。请注意,从shell执行此操作时,不要同时传入换行符。
这将计算出与该可缓存内容对应的MD5哈希值。NGINX使用该哈希值计算内容在磁盘上的存储位置。可以看到,我们在proxy_cache_path中指定了两级缓存,依次使用一个字符和两个字符作为目录名。我们从字符串末尾提取这些字符,创建名为4的目录及名为9b的子目录,然后将缓存内容(以及标头和少量元数据)写入磁盘上的文件。
可以测试内容缓存。可将缓存键作为响应标头之一输出,然后通过md5sum计算该值对应的哈希值。接着,可以检查磁盘上的值,确认其确实存在,并查看NGINX缓存的标头,从而了解整个过程如何协同工作。
26:36 从磁盘加载缓存

内容现已持久存储在磁盘上,因此NGINX启动时需要将其加载到内存中。更准确地说,NGINX需要遍历磁盘缓存,提取元数据,然后将元数据加载到各工作进程所用的共享内存段中。此操作由一个名为“缓存加载器”的进程完成。
缓存加载器会在启动时启动并运行一次,将磁盘中的元数据分批加载到内存:每次处理100个文件,处理时间限制为200 ms,随后暂停50 ms。此过程会不断重复,直至遍历整个缓存并填充共享内存段。
随后,缓存加载器会退出,无需再次运行,除非NGINX重启或重新配置,并且需要重新初始化共享内存段。您可以调整缓存加载器的运行参数。如果磁盘速度很快且负载较轻,这样做可能比较合适。您可以让它运行得更快;如果缓存中存储了大量文件且磁盘速度较慢,同时不希望缓存加载器在NGINX启动时占用过多CPU,也可以适当降低其运行速度。
28:07 管理磁盘缓存

缓存加载到内存且文件存储到磁盘后,从未被访问的缓存文件可能会一直保留下来。NGINX首次遇到这些文件时会将其存储起来,但如果某个文件不再收到请求,[该文件]就会一直留在磁盘上,直到有机制将其清理掉。
这个组件就是缓存管理器。它会定期运行,清除磁盘上在一定时间内未被访问的文件;如果缓存过大,超出声明的大小,也会删除文件。删除操作遵循最近最少使用原则。与配置缓存加载器一样,可以使用proxy_cache_path[指令]的参数配置此操作:
- 默认
inactive时间为10分钟。 - The
max-size参数默认没有限制。如果为缓存设置max-size限制,缓存有时可能会超出该限制,但缓存管理器运行时会清理最近最少使用的文件,使缓存大小降至该限制以内。
29:22 从磁盘中清除内容

最后,有时可能需要清除磁盘中的内容。此时需要找到并删除相应文件。如果掌握了前面介绍的技巧,这项操作相对简单,例如使用md5sum处理缓存键,或直接在整个文件系统中递归运行grep,尝试找出需要删除的一个或多个文件。
或者,如果使用NGINX Plus,可以使用该产品内置的缓存清除功能。借助缓存清除功能,可以从请求中提取特定参数;通常,我们使用名为“PURGE”的方法来标识缓存清除请求。
清除操作由一个特殊的NGINX Plus处理程序执行。该程序会检查URI,并从缓存中删除与该URI匹配的所有文件。可以在URI末尾添加星号,使其成为匹配前缀。在本例中,我们将使用清除功能,删除通过localhost主机的8001端口提供的所有文件;当然,也可以指定子目录。
无论使用哪种方法,都可以随时安全地删除磁盘缓存中的文件,甚至可以使用rm -rf删除整个缓存目录。NGINX不会中断运行,而是会继续检查磁盘上是否存在相应文件。如果文件不存在,就会产生缓存未命中。随后,NGINX会从源服务器重新获取内容,并将其存回磁盘缓存。因此,需要从缓存中清除单个文件时,这种操作始终安全、可靠且稳定。
31:27 控制缓存

我们已经了解了缓存的工作原理及其在NGINX中的实现,并深入探讨了NGINX如何将文件存储在磁盘上,以获得与静态内容相近的性能。接下来,我们将进一步了解如何更智能地使用缓存。
对于简单的网站,启用缓存通常就能按需运行,持续提供所需的性能水平和缓存行为。不过,缓存始终有优化空间,而且默认行为往往并不符合实际需求。
您的源服务器可能未设置正确的响应标头,或者您可能希望在NGINX中覆盖源服务器指定的设置。您可以通过多种方式配置NGINX,以精细调整缓存的运行方式。
32:30 延迟缓存

可以延迟缓存。如果有大量内容,其中许多内容每小时或每天只被访问一两次,这种情况很常见。例如,公司宣传册很少有人阅读,尝试缓存此类内容通常只会浪费时间。延迟缓存允许设置一个阈值。只有当内容的请求次数达到指定值时,才会存储其缓存版本。在达到proxy_cache_min_uses阈值之前,不会在缓存中存储该内容的版本。
这样可以更有针对性地选择要放入缓存的内容。缓存本身是一种有限资源,通常受服务器内存容量限制,因为需要尽可能确保缓存已调入内存。因此,通常需要限制某些类型的内容,只将热门请求放入缓存。
缓存重新验证是最近添加到NGINX Open Source和NGINX Plus的一项功能。它对If-Modified-Since功能进行了调整,因此,当NGINX需要刷新已缓存的值时,不会通过简单的GET请求获取该内容的新版本,而是发出条件GET请求,表明:“我有一个在此特定日期和时间修改的缓存版本。”
源服务器可以选择返回“304 Not Modified”,这实际上表示当前缓存的版本仍是最新版本。这样可以节省上游带宽,因为源服务器无需重新发送未发生变化的内容,同时还可能减少磁盘写入。NGINX无需将该内容流式写入磁盘,再将其替换到相应位置并覆盖旧版本。
34:45 控制缓存时间

您可以精细控制内容的缓存时长。通常,源服务器提供内容时会附带适合浏览器的缓存标头,即采用长期缓存,同时以相对较高的频率请求刷新内容。不过,您可能希望直接位于源服务器前端的NGINX代理更频繁地刷新文件,以便更快获取变更。
如果将浏览器的缓存超时时间从60秒缩短到10秒,负载会大幅增加;但如果将NGINX中的缓存超时时间从60秒缩短到10秒,负载只会略有增加。对于每项请求,这会使源服务器每分钟多收到5次请求;而对于远程客户端,负载则取决于有多少客户端正在访问网站上的类似内容。
因此,您可以覆盖源服务器指定的逻辑和意图,也可以屏蔽某些标头或让NGINX忽略这些标头:X-Accel-Expires、Cache-Control或Expires。还可以在NGINX配置中使用proxy_cache_valid指令设置默认缓存时间。
36:18 缓存或不缓存

有时,您可能不希望缓存源服务器标记为可缓存的内容,或者希望确保绕过NGINX中存储的内容版本。proxy_cache_bypass和proxy_no_cache指令可提供这种控制能力。
您可以使用这些指令来简化配置:如果指定的一组请求标头中有任何一个已设置(例如HTTP授权标头),或者请求中包含某个参数,则绕过缓存。此时,可以自动更新NGINX中的缓存,也可以完全跳过缓存,始终从源服务器检索内容。
通常,这些操作用于处理较为复杂的缓存决策。您可以根据Cookie和授权标头的值进行精细判断,从而控制哪些内容应缓存、哪些内容应始终从源服务器获取,以及哪些内容绝不能存储在NGINX缓存中。
37:25 多个缓存

最后,对于超大规模部署,出于以下几个原因,您可能需要考虑在单个NGINX实例中使用多个缓存。您可以根据网站的性质及其性能的重要程度,为NGINX代理上的不同租户设置不同的缓存策略。在共享托管环境中,甚至还可以根据每个租户订购的具体套餐来设置。
或者,NGINX主机中可能有多个磁盘,此时在每个磁盘上分别部署一个缓存效率更高。基本原则是尽量减少磁盘之间的数据复制。为此,可将每个缓存固定到相应磁盘,并将使用该缓存的各个代理的临时文件固定到正确的磁盘。
标准操作流程是:当NGINX从上游代理接收内容时,除非内容足够小、可以存入内存,否则会将内容以流式方式写入磁盘。内容写入磁盘后,再移入缓存。如果临时文件的存储位置(即存储临时文件的磁盘)与缓存所在的磁盘相同,此操作的效率会高得多。
39:07 快速回顾:为什么要使用缓存?

我们已经介绍了缓存、NGINX采用的方法、NGINX内部的实现方式,以及如何进行调优。接近尾声时,我们来快速回顾一下,为什么首先需要缓存内容。全球有1.14亿个网站部署了NGINX,其中许多用户选择NGINX,是因为它具备Web加速和内容缓存功能。[编者注:此统计数据适用于2014年5月举办本次网络研讨会时的情况。]
39:44 为什么页面速度很重要?

这些功能可以提升网站速度,为最终用户带来更好的体验,而网页速度确实非常重要。多年来,分析师一直在监测用户行为,并由此总结出俗称的“N秒法则”。它指的是普通用户愿意等待页面加载和呈现的时长;超过这一时长,用户就会感到厌烦和不耐烦,转而访问其他网站,例如竞争对手的网站。
随着标准不断提高,用户的期望也越来越高,他们愿意等待的时间则越来越短。按照一种不太严谨的算法推算,甚至可以得出这样的结论:到2016年左右,用户的耐心将降至负数。
40:46 Google 改变了规则

但事实上,技术的发展已经超出了我们的预期。几年前,Google 在推出 Google Instant Search 时直观地展示了这一点。如今使用 Google 时,只要在搜索框中输入搜索词,还没输完,Google 就会显示候选搜索结果。这反映出现代互联网用户的期望发生了巨大变化。正如 Google 所说:“如今,用户希望网页能像翻动书页一样迅速、顺畅、自然地响应。”
41:28 性能不佳的代价

如果无法达到这一性能水平,可能会对网站或Web服务的相关KPI产生重大影响。例如,在广告点击率方面,Google发现,当其搜索页面的加载时间延长半秒时,广告点击率下降了20%。在收入方面,为研究网页加载缓慢的影响,Amazon特意以100 ms为增量延长页面加载时间,结果发现,加载时间每增加100 ms,受影响客户带来的收入通常会下降1%。
许多其他分析师、网站和研究人员也报告了类似情况,即网站的页面停留时间、跳出率等指标会受到影响。最近,Google开始在计算搜索结果中的网页排名时考虑页面速度。影响排名的似乎是首字节时间。页面加载时收到首字节所需的时间越长,网页排名受到的负面影响就越大。网站可能会因为出现在Google搜索结果的第3页、第4页或第5页而无人访问。
43:00 NGINX缓存可帮助您

NGINX的缓存功能可缩短首字节响应时间,让Web内容加载更快、响应更灵敏,从而改善最终用户体验。
NGINX可帮助您整合并简化Web基础设施。NGINX不仅是独立的Web缓存,还包括Web源站服务器以及通往FastCGI等API的直接网关。NGINX Plus还具备构建功能完善、可供企业使用的负载均衡器和应用交付控制器的能力。因此,您可以将Web基础设施中的多个不同网络组件整合为单一组件,即NGINX或NGINX Plus,从而获得更可靠、更易于调试且速度更快的解决方案。
NGINX可通过分担上游服务器的重复性任务来提升服务器容量。事实上,即使内容看似无法缓存(例如博客网站的首页),在NGINX代理上仅缓存1秒也能带来益处。
当100名用户在同一秒内请求相同内容时,NGINX会将其合并为对源服务器的一次请求,并从缓存中向这些用户提供内容,确保内容的延迟不超过1秒。对于博客或类似网站,这通常已绰绰有余,同时还能显著提升性能,既可减轻上游服务器的负载,也可降低管理和部署充足容量所需的成本。
最后,不要忽视NGINX的一项战略用途:通过代理缓存的“使用过期内容”功能,降低上游服务器故障带来的影响。如果上游服务器运行缓慢、返回错误或出现某种故障,NGINX可以回退到本地缓存的内容版本,并持续使用该版本,直至上游服务器恢复。
45:21 总结

全球繁忙网站中有38%主要使用NGINX的Web加速和内容缓存功能。[编者注:此统计数据适用于2014年5月举办该网络研讨会时的情况;当前数据请参见此处。]如需了解更多解决方案和详细信息,请查看nginx.com上的博客和功能简介,其中介绍了NGINX和NGINX Plus的功能。还可查看我们的网络研讨会列表,其中不仅包括即将举办的网络研讨会,还将陆续添加本系列以往活动的网络研讨会。
如果想进一步了解这些功能,可以查阅nginx.org和nginx.com上的文档和解决方案,但更直接的方式是下载并亲自试用。开源产品可从nginx.org获取;如需商业支持版本及更多负载均衡、应用交付、管理和易用性功能,请访问nginx.com。
各位,非常感谢大家抽出时间聆听。希望这次关于NGINX内容缓存的演示和讲解能为大家带来帮助和启发。
问答
我们开始逐一回答这些问题,看看效果如何。
47:20 字节范围请求
我们有一个关于字节范围请求的问题。当客户端请求某项内容,但只需要其中一部分时,就会使用字节范围请求。例如,对于视频文件,客户端可能只需要其中一段。另一个很常见的例子是PDF文件:用户已读取包含PDF文件索引的文件头,而客户端只想下载指定的若干页面。这种请求在NGINX内容缓存中如何处理?
具体过程如下。当NGINX收到针对某个资源的字节范围请求,并且该资源已完整存储在缓存中时,NGINX会从缓存中返回客户端请求的字节范围。如果缓存中没有该资源,NGINX会向上游服务器请求完整资源,并将其存入缓存。目前,在这种情况下,NGINX不会按字节范围请求返回内容,而是将完整资源返回给客户端。在大多数情况下,这种行为是可以接受的。
例如,如果客户端下载PDF文档,首次请求无论如何都会获取整个文档。只有在以流式方式传输该文档时,客户端才会中止连接并开始发出字节范围请求。因此,对于已缓存的内容,NGINX会遵循字节范围请求。对于未缓存的内容,NGINX会从上游服务器检索全部内容,并在该次请求中将全部内容返回给客户端。
49:13 代理缓存重新验证
这是一个关于代理缓存重新验证功能的问题。借助此功能,NGINX可以向上游服务器发出条件GET请求,以检查内容是否已更改。问题是:
代理缓存重新验证是否会考虑ETag,还是仅考虑内容的If-Modified-Since日期?
答案是,它只检查内容的If-Modified-Since日期。实际使用中,通常建议始终在响应中包含If-Modified-Since,并将ETag视为可选项,因为其处理方式不如响应中的“最后修改”日期一致,应用范围也没有那么广。
50:07 将缓存分布到容量相同的磁盘上
NGINX能否在多个同等规格的磁盘之间对单个站点的缓存进行负载均衡,以优化性能?
可以,但需要进行一些额外设置。典型做法是部署多块不使用RAID的磁盘,然后分别部署缓存,并将每个缓存固定到一块磁盘上。这需要进行一些额外配置并对流量进行分区。如果需要配置方面的帮助,可以联系社区,我们会在那里协助处理您的具体请求;如果您使用的是NGINX Plus,也可以联系我们的支持团队,我们很乐意提供帮助。
50:50 Vary 标头
NGINX 在判断缓存命中或未命中时是否会考虑Vary标头?
不会,NGINX不会自动处理Vary标头。如果这会造成问题,可以轻松地将Vary标头添加到代理缓存键中,使存储响应所用的唯一键包含Vary标头的值。这样就可以存储多个不同版本。
51:25 缓存原语
是否遵循了所有缓存原语和指令?
总体而言,是的。但也有少数边缘情况,例如Vary标头不会得到遵循。在许多情况下,各类缓存对RFC要求的解读存在一定的灵活空间。我们尽可能采用可靠、一致且易于配置的实现方式。
51:52 上游标头和数据
上游标头和数据是否都已缓存?
是的,两者都会被缓存。如果收到来自缓存的响应,则响应头和响应正文都已被缓存。
52:13 *‑Encoding 标头
标头值和响应正文都会被缓存,因此……如果NGINX无法正确处理各种不同的Transfer-Encoding组合,我会相当惊讶。Accept-Encoding通常通过Vary标头实现,因此前文关于需要将Vary标头纳入缓存键的说明也适用于此(对于不支持该功能的客户端)。
52:56 SPDY
缓存是否适用于SPDY?
当然可以。可以将其视为NGINX的前端代理,但实际上,它与NGINX内核的集成非常深入。是的,SPDY支持缓存。
53:15 Vary 标头,第2轮
下面是另一个关于Vary标头的问题。需要确认的是,如果使用带Vary标头的响应和gzip压缩,请查看Trac或我们的社区网站上的相关讨论,了解相应的解决方案。最常见的方法是将Vary标头嵌入缓存键中。
53:45 PageSpeed
问:PageSpeed 使用 NGINX 缓存还是自身的缓存机制?
这个问题需要咨询PageSpeed开发人员。
54:00 其他缓存
问:其他内容缓存与NGINX相比如何?
CDN是非常有效的内容缓存解决方案。CDN以服务形式部署,因此对内容缓存方式及其过期机制的控制较为有限,但它能非常有效地将内容部署到更靠近最终用户的位置。NGINX可以有效提升Web应用的访问速度,通常会与CDN结合部署。对于Varnish等独立缓存,其功能同样强大,在许多方面的工作方式与NGINX相似。NGINX的一项优势是将源站服务、应用网关、缓存和负载均衡整合到一个解决方案中,从而简化并整合基础设施,使其更易于部署和管理,并在出现问题时更易于调试和诊断。
要观看本文所依据的网络研讨会,请点击此处。
要试用NGINX Plus,请立即开始30天免费试用,或联系我们讨论您的使用场景。
关于作者

相关博客文章
NGINX Plus R26 正式发布
NGINX Plus R26通过缓存JSON Web密钥集加快JWT验证,并强化TLS握手,从而提升安全性。NGINX JavaScript的新功能包括增强对异步函数的支持,以及实现WebCrypto API。
使用NGINX App Protect DoS保护gRPC应用,抵御严重的DoS攻击
gRPC具备开发人员设计和部署现代应用所需的速度与灵活性,但其开放性也使其极易受到第7层DoS攻击。NGINX App Protect DoS可保护gRPC应用免受此类破坏性攻击。
Ingress Controller 选型指南(第 2 部分):风险与面向未来的规划
了解选择错误的Ingress控制器可能带来的风险,以及如何从关键方面着手,让您的选择更好地适应未来需求。
NGINX Plus R19 正式发布
NGINX Plus R19扩展了监控功能,不仅提供更多指标,还新增了指标分析方式;增加试运行模式,用于测试限速效果;增强键值存储,以支持IP地址范围;并使限速更加动态。
NGINX现已正式加入F5
NGINX现已正式成为F5的一部分。Gus Robertson现任F5 NGINX业务部门负责人。他阐述了两家公司在人才、文化和愿景方面融合的价值,以及双方将如何携手增强NGINX的开源产品和商业产品。
