使用Nginx进行基本缓存:提升响应时间

通过缓存区域、TTL、绕过规则、状态头及测试步骤,安全配置基本的Nginx代理缓存。

使用Nginx进行基本缓存:提升响应时间

使用Nginx进行基本缓存可以通过保存上游响应的副本,并在每次请求时不再询问应用程序,从而提升响应时间。谨慎使用时,缓存能减少后端负载,平滑流量峰值,并使重复请求感觉更快。

缓存不仅适用于大型网站。即使是一个小型应用,当页面、API响应或静态文件被频繁请求且不会每秒变化时,也能从中受益。

Nginx可以缓存什么

当Nginx作为反向代理时,它可以缓存来自上游服务器的响应。这与普通的浏览器缓存不同。浏览器缓存将文件存储在用户设备上。而Nginx代理缓存将响应存储在服务器上,这样许多用户都可以从同一缓存副本中受益。

一个简单的代理缓存设置包含两部分。首先,在http块中定义一个缓存区域:

proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=app_cache:10m
    max_size=1g inactive=60m use_temp_path=off;

然后在serverlocation块中启用该缓存:

location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_cache app_cache;
    proxy_cache_valid 200 10m;
    proxy_cache_valid 404 1m;
    add_header X-Cache-Status $upstream_cache_status;
}

proxy_cache_path指令创建缓存存储区域。keys_zone定义用于缓存键和元数据的共享内存。max_size限制磁盘使用量。inactive会移除一段时间内未被访问的项。

proxy_cache_valid指令决定某些响应代码的缓存时长。在示例中,成功响应缓存10分钟,而404响应缓存1分钟。

X-Cache-Status头在测试期间非常有用。它可以显示诸如MISSHITBYPASSEXPIRED等值,具体取决于发生的情况。

对于同时使用Nginx作为反向代理的网站,这与反向代理设置自然搭配。

决定应该缓存什么

Nginx缓存最困难的部分不是编写指令,而是决定哪些内容可以安全重用。

适合缓存的候选包括:

  • 公开营销页面。
  • 公开文档页面。
  • 按可预测计划更新的产品列表页面。
  • 匿名API响应。
  • 对许多用户相同的昂贵上游响应。

不适合缓存的候选包括:

  • 账户页面。
  • 购物车。
  • 管理界面。
  • 包含私人用户数据的响应。
  • 基于Cookie或授权头变化的页面。

如果每个用户的响应都不同,除非有非常清晰的缓存键策略,否则不要缓存。意外地将一个用户的私人响应提供给另一个用户是一个严重的错误。

当请求包含会话或授权数据时,可以绕过缓存:

proxy_cache_bypass $http_authorization;
proxy_no_cache $http_authorization;

对于基于Cookie的会话,可以使用类似的模式:

proxy_cache_bypass $cookie_session;
proxy_no_cache $cookie_session;

确切的Cookie名称取决于您的应用程序。不要盲目复制此代码而不检查您的应用程序如何处理会话。

一个实际场景:您的公共博客首页由应用程序生成,在繁忙时可能需要300毫秒。如果您将该页面缓存5分钟,大多数访问者会快速收到缓存的副本,而应用程序只需偶尔重新生成它。这是一个强有力的用例,因为首页是公开的且不针对特定用户。

缓存键、头信息和清除

Nginx使用缓存键来决定两个请求是否应共享相同的缓存响应。默认缓存键通常基于协议、方法、主机和URI。对于许多网站来说,这已经足够了。

如果查询字符串改变响应,请确保它们成为键的一部分。如果查询字符串只是跟踪参数,您可能希望在应用程序或CDN层规范化它们,而不是让每个utm_source都创建单独的缓存条目。

上游缓存头也很重要。您的应用程序可以发送诸如:

Cache-Control: public, max-age=600

或:

Cache-Control: private, no-store

Nginx可以配置为尊重或覆盖这些头,但您应该选择一种明确的策略。如果应用程序开发者期望Cache-Control: no-store阻止缓存,那么在Nginx覆盖该行为可能会产生混乱且有风险的结果。

清除是另一个操作问题。开源Nginx不像某些商业或第三方模块那样包含简单的内置缓存清除端点。许多团队通过使用短缓存持续时间、版本化URL或在受控发布期间清除缓存目录的部署脚本来处理这个问题。

短TTL通常就足够了。在繁忙的端点上设置60秒缓存仍然可以消除大量后端流量,同时保持内容相对新鲜。

测试缓存行为

启用缓存后,多次请求相同的URL并检查响应头:

curl -I https://example.com/

如果您添加了X-Cache-Status,第一次请求可能显示MISS,后续请求应显示HIT。如果每次请求都是MISS,请检查响应头、缓存绕过规则、请求Cookie以及缓存目录是否对Nginx工作进程可写。

同时测试登录和未登录行为。这是许多缓存错误出现的地方。打开一个隐私浏览器窗口,以测试用户身份登录,并确认私人页面没有被公开缓存。

还要监控磁盘使用情况。没有实际限制的缓存可能会填满文件系统。使用max_size,尽可能将缓存存储与关键系统分区分开,并在磁盘压力时发出警报。

何时寻求帮助

如果缓存内容出现在错误的用户下,或者调整后缓存命中率仍然很低,或者缓存文件意外填满磁盘,请请一位经验丰富的Nginx或平台工程师介入。缓存问题可能看起来简单,但隐藏着特定于应用程序的行为。

在缓存经过身份验证的API、多租户仪表板或支付相关流程之前,您也应该寻求帮助。这些领域需要仔细设计。

使用Nginx进行基本缓存的最佳实践是从公共、可重复的响应和短缓存持续时间开始。在测试期间添加可见的缓存状态头,尊重私有内容的边界,并测量响应时间和后端负载。做好缓存,用户将获得更快的页面,而您的应用程序将有更多喘息空间。