我们都知道应用程序和网站的性能是他们成功的关键因素。但是,使您的应用程序或网站表现更好的过程并不总是很清楚。代码质量和基础架构当然至关重要,但在许多情况下,您可以通过专注于一些非常基本的应用程序的交付技术,对应用程序的最终用户体验进行大量改进。其中一个例子是在应用程序栈中实现和优化缓存。在教程中介绍的技术可以帮助新手和高级用户使用NGINX中包含的内容缓存功能,从而获得更好的性能。

概览

内容缓存位于客户端和“源服务器(upstream)”之间,并保存它看到的所有内容的副本。如果客户端请求缓存已存储的内容,则它会直接返回内容而不连接源服务器。这提高了性能,因为内容缓存更靠近客户端,并且更有效地使用应用程序服务器,因为它们不必每次都从头开始生成页面。

Web浏览器和应用程序服务器之间可能存在多个缓存:客户端的浏览器缓存,中间缓存,内容交付网络(CDN)以及位于应用程序服务器前面的负载平衡器或反向代理。即使在反向代理/负载均衡器级别,缓存也可以极大地提高性能。

这里举一个例子,比如我的站点使用Next.js服务器端口渲染,由于服务器性能比较差,当然$5的服务器,并不能期望好到那里去,能用就已经非常了不起,能进入这个局域网就好了,别期望太多,每次打开页面将近花费7秒左右,当这其中包含网络延迟,但当我直接在服务器端(127.0.0.1)发起请求时,时间接近5秒,然后再排除从数据库获取数据时间,服务器端渲染时间用了4.5秒,实在太慢,此时我能想到最快解决问题答案就是缓存,但在那里加入缓存,从每一步时间看来,在Nginx加入缓存最快解决问题

NGINX通常作为应用程序堆栈中的反向代理或负载平衡器部署,并具有一整套缓存功能。下一节将讨论如何使用NGINX配置基本缓存。

如何设置和配置基本缓存

只需要两个指令即可启用基本缓存:proxy_cache_pathproxy_cacheproxy_cache_path指令设置缓存的路径和配置,proxy_cache 用来指令激活它。

proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g 
                 inactive=60m use_temp_path=off;

server {
    # ...
    location / {
        proxy_cache my_cache;
        proxy_pass http://my_upstream;
    }
}

proxy_cache_path指令的参数定义了以下设置:

  • 缓存的本地磁盘目录称为 /path/to/cache/
  • levels在/path/to/cache/下设置一个两级目录层次结构。在单个目录中包含大量文件会降低文件访问速度,因此我们建议对大多数部署使用两级目录层次结构。如果levels未包含该参数,NGINX会将所有文件放在同一目录中。
  • keys_zone设置共享内存区域,用于存储缓存键和元数据,例如使用计时器。拥有内存中的密钥副本,NGINX可以快速确定请求是否是一个HITMISS不必转到磁盘,从而大大加快了检查速度。1 MB区域可以存储大约8,000个密钥的数据,因此示例中配置的10 MB区域可以存储大约80,000个密钥的数据。
  • max_size设置缓存大小的上限(在本例中为10千兆字节)。它是可选的; 不指定值允许缓存增长以使用所有可用磁盘空间。当缓存大小达到限制时,一个称为缓存管理器的进程将删除最近最少使用的缓存,将大小恢复到限制之下的文件。
  • inactive指定项目在未被访问的情况下可以保留在缓存中的时间长度。在此示例中,缓存管理器进程会自动从缓存中删除60分钟未请求的文件,无论其是否已过期。默认值为10分钟(10m)。非活动内容与过期内容不同。NGINX不会自动删除缓存header定义为已过期内容(例如 Cache-Control:max-age=120)。过期(陈旧)内容仅在指定时间内未被访问时被删除。访问过期内容时,NGINX会从原始服务器刷新它并重置inactive计时器。
  • NGINX首先将发往高速缓​​存的文件写入临时存储区域,use_temp_path=off指令指示NGINX将它们写入将被高速缓存的相同目录。我们建议您将此参数设置off为避免在文件系统之间进行不必要的数据复制。use_temp_path在NGINX 1.7.10中引入。

最后,该proxy_cache指令激活与父location块的URL匹配的所有内容的缓存(在示例中为/)。您还可以在server块中包含proxy_cache指令; 它适用于没有自己的location 指令的服务器的所有块。

当上游服务器关闭()时提供缓存内容

NGINX 内容缓存的一个强大功能是,NGINX可以配置为在无法从原始服务器获取新内容时从缓存中提供已缓存的内容。如果缓存资源的所有源服务器都已关闭或暂时占用,则会发生这种情况。NGINX不是将错误传递给客户端,而是从缓存中提供文件的陈旧版本。这为NGINX代理的服务器提供了额外的容错能力,并确保在服务器故障或流量高峰时的正常运行时间。要启用此功能,请包含proxy_cache_use_stale指令:

location / {
    # ...
    proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
}

使用此示例配置,如果NGINX 从原始服务器收到一个errortimeout或任何指定的5xx错误,并且在其缓存中具有所请求文件的过时版本,则它会传递过时文件,而不是将错误转发到客户端。

如何提高缓存性能

NGINX具有丰富的可选设置,可用于微调缓存的性能。这是一个激活其中一些的例子:

proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g 
                 inactive=60m use_temp_path=off;

server {
    # ...
    location / {
        proxy_cache my_cache;
        proxy_cache_revalidate on;
        proxy_cache_min_uses 3;
        proxy_cache_use_stale error timeout updating http_500 http_502
                              http_503 http_504;
        proxy_cache_background_update on;
        proxy_cache_lock on;

        proxy_pass http://my_upstream;
    }
}

这些指令配置以下行为:

  • proxy_cache_revalidate指示NGINX在使用GET条件请求时,从源服务器刷新内容。如果客户端请求缓存但是由缓存控制头定义的过期的内容,则NGINX将If-Modified-Since字段包含在GET请求的标头中将它发送到源服务器。因为服务器只有在NGINX最初缓存它时自附加到文件的标题Last-Modified中记录的时间以来修改了整个项目。
  • proxy_cache_min_uses设置客户端在NGINX缓存之前必须请求多少次才被缓存。如果缓存不断填满,这将非常有用,因为它可确保只将最常访问的项添加到缓存中。默认proxy_cache_min_uses设置为1。
  • 指令updating参数proxy_cache_use_stale与启用proxy_cache_background_update指令相结合,指示当客户端请求已过期或正在从原始服务器更新的项目时,NGINX会传递过时的内容。所有更新都将在后台完成。在完全下载更新的文件之前,将为所有请求返回陈旧文件。
  • proxy_cache_lock启用,如果多个客户端请求的文件不在缓存(MISS),只有第一个这些请求是通过原始服务器的。其余请求等待满足该请求,然后从缓存中提取文件。如果 proxy_cache_lock 未启用,会导致缓存未命中的所有请求都将直接发送到源服务器。

跨多个硬盘拆分缓存

如果您有多个硬盘驱动器,可以使用NGINX在它们之间拆分缓存。以下示例根据请求URI将客户端均匀分布在两个硬盘驱动器上:

proxy_cache_path /path/to/hdd1 levels=1:2 keys_zone=my_cache_hdd1:10m
                 max_size=10g inactive=60m use_temp_path=off;
proxy_cache_path /path/to/hdd2 levels=1:2 keys_zone=my_cache_hdd2:10m
                 max_size=10g inactive=60m use_temp_path=off;

split_clients $request_uri $my_cache {
              50%          “my_cache_hdd1”;
              50%          “my_cache_hdd2”;
}

server {
    # ...
    location / {
        proxy_cache $my_cache;
        proxy_pass http://my_upstream;
    }
}

这两个proxy_cache_path指令在两个不同的硬盘驱动器上定义了两个缓存(my_cache_hdd1my_cache_hdd2)。的split_clients配置块指定从一半的请求(结果50%)被缓存在my_cache_hdd1与另一半中my_cache_hdd2。基于$request_uri变量的哈希(请求URI)确定每个请求使用哪个缓存,结果是对给定URI的请求总是缓存在同一缓存中。

请注意,此方法不能替代RAID硬盘设置。如果存在硬盘驱动器故障,则可能导致系统出现不可预测的行为,包括用户看到针对故障硬盘驱动器的请求的500响应代码。适当的RAID硬盘设置可以处理硬盘故障。

如何对Nginx Cache进行检测

可以在响应头中加入$upstream_cache_status变量以进行检测

add_header X-Cache-Status $upstream_cache_status;

此示例X-Cache-Status在响应客户端时添加HTTP标头。以下是可能的值$upstream_cache_status

  • MISS - 在缓存中找不到响应,因此从原始服务器获取响应。然后缓存响应。
  • BYPASS- 响应是从原始服务器获取的,而不是从缓存中提供的,因为请求与proxy_cache_bypass指令匹配
  • EXPIRED - 缓存中的条目已过期。响应包含来自原始服务器的新内容。
  • STALE- 内容过时,因为源服务器未正确响应但proxy_cache_use_stale已配置。
  • UPDATING- 内容过时,因为条目当前正在更新以响应先前的请求,并且proxy_cache_use_stale updating已配置。
  • REVALIDATED- proxy_cache_revalidate指令已启用,NGINX验证当前缓存的内容是否仍然有效通过(If-Modified-SinceIf-None-Match)。
  • HIT - 响应直接来自有效的缓存

Nginx如何确定是否要缓存响应

默认情况下,NGINX尊重Cache-Control源服务器的标头。它不缓存响应Cache-Control设置为PrivateNo-CacheNo-StoreSet-Cookie在响应头。NGINX只缓存GETHEAD客户端请求。您可以按照以下答案中的说明覆盖这些默认值。

如果proxy_buffering设置为off,NGINX不会缓存响应。on默认的。

Nginx是否可以忽略Cache-Control

使用proxy_ignore_headers指令可以忽略Cache-Control

location /images/ {
    proxy_cache my_cache;
    proxy_ignore_headers Cache-Control;
    proxy_cache_valid any 30m;
    # ...
}

NGINX忽略/ images /Cache-Control下所有内容的标题。该指令强制缓存数据到期,如果忽略标头则需要。NGINX不会缓存没有过期的文件。proxy_cache_validCache-Control

使用proxy_ignore_headers指令即可

Nginx如何缓存POST请求

使用 proxy_cache_methods指令:

proxy_cache_methods GET HEAD POST;

此示例启用了POST请求的缓存。

Nginx如何缓存动态内容

只要Cache-Control 标头允许。即使在很短的时间内缓存动态内容也可以减少原始服务器和数据库的负载,从而缩短第一个字节的时间,因为不必为每个请求重新生成页面。

如何不使用Nginx缓存

proxy_cache_bypass指令

location / {
    proxy_cache_bypass $cookie_nocache $arg_nocache;
    # ...
}

该指令定义了NGINX立即从源服务器请求内容的请求类型,而不是首先尝试在缓存中找到它。这有时被称为通过缓存“打孔”。

NGINX使用什么缓存密钥

NGINX生成的密钥的默认形式类似于以下NGINX变量的MD5哈希:$scheme$proxy_host$request_uri; 使用的实际算法稍微复杂一些。

proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g
                 inactive=60m use_temp_path=off;

server {
    # ...
    location / {
        proxy_cache my_cache;
        proxy_pass http://my_upstream;
    }
}

对于此示例配置,缓存密钥for http://www.example.org/my_image.jpg计算为md5(“http://my_upstream:80/my_image.jpg”)

请注意,$proxy_host变量用于散列值而不是实际主机名(www.example.com)。$proxy_host定义为proxy_pass指令中指定的代理服务器的名称和端口。

要更改用作密钥基础的变量,请使用该 proxy_cache_key指令(另请参阅以下问题)。

缓存键可以配置为任意值,例如:

proxy_cache_key $proxy_host$request_uri$cookie_jessionid;

此示例将JSESSIONIDcookie 的值合并到缓存键中。具有相同URI但JSESSIONID值不同的项目将作为唯一项目单独缓存。

NGINX使用ETag标头

在NGINX 1.7.3及更高版本中,ETag标头完全支持If-None-Match

NGINX如何处理字节范围请求

如果文件在高速缓存中是最新的,则NGINX遵循字节范围请求并仅向项目客户端提供项目的指定字节。如果文件未缓存,或者文件过时,NGINX会从原始服务器下载整个文件。如果请求是针对单个字节范围的,则NGINX会在下载流中遇到该范围后立即将该范围发送到客户端。如果请求在同一文件中指定了多个字节范围,则NGINX会在下载完成时将整个文件传送到客户端。

下载完成后,NGINX会将整个资源移动到缓存中,以便从缓存中立即满足所有未来的字节范围请求,无论是单个范围还是多个范围。

请注意,upstream服务器必须支持NGINX的字节范围请求,以支持对该upstream服务器的字节范围请求。

NGINX如何处理Pragma标头

Pragma:no-cache报头由客户加入到绕过所有中间缓存,直接进入到源服务器的请求的内容。Pragma默认情况下,NGINX不支持标头,但您可以使用以下proxy_cache_bypass指令配置该功能:

location /images/ {
    proxy_cache my_cache;
    proxy_cache_bypass $http_pragma;
    # ...
}

NGINX是否支持标头stale-while-revalidate和stale-if-error以及扩展的Cache-Control

NGINX 1.11.10及更高版本中支持。这些扩展做了什么:

  • 如果当前正在更新stale-while-revalidateCache-ControlHTTP标头的扩展允许使用陈旧的缓存响应。

HTTP标头的stale-if-error扩展Cache-Control允许在发生错误时使用陈旧的缓存响应。

这些头具有比低优先级proxy_cache_use_stale指令如上所述。

NGINX是否支持Vary标头

NGINX 1.7.7及更高版本中。这是一个关于Vary 很好的概述

结论

至此,您应该很好地理解nginx 代理缓存的工作原理以及如何正确配置Nginx代理缓存。如果您有任何问题或反馈,请随时发表评论

如果你喜欢我们的内容可以选择在下方二维码中捐赠我们,或者点击广告予以支持,感谢你的支持