上一篇 下一篇 分享链接 返回 返回顶部

日本服务器部署Web服务如何优化:从静态缓存、压缩到上游超时设置

发布人:Minchunlin 发布时间:1 天前 阅读量:6
日本服务器部署Web服务如何优化:从静态缓存、压缩到上游超时设置

在日本服务器上部署 Web 服务时,页面慢、偶发 504 和静态文件更新不生效,往往不是同一个问题。判断时不要先盲目增加超时时间:如果静态文件的首字节响应很快但下载时间长,优先检查压缩和缓存;如果动态请求的 upstream_response_time 持续升高,重点应放在上游应用处理;如果大量请求停留在连接阶段,则需要查看连接复用、文件描述符和监听状态。

现场排查可以按这个顺序进行:先区分静态请求与动态请求,再检查连接和响应计时;随后核对静态缓存头,确认压缩是否只作用于适合压缩的文本内容;最后根据上游连接、发送、读取三个阶段分别调整超时。每次只改一类参数,使用 nginx -t 校验后平滑加载,并通过响应头、访问日志和重复请求验证结果。

先从现象判断故障范围

下面的判断适用于常见的 Nginx 反向代理场景。实际判断应以访问日志中的时间字段和响应头为准,而不是只看浏览器体感。

现象优先怀疑的原因首个核验点
CSS、JavaScript、字体每次都重新下载缺少 Cache-Control、资源 URL 未版本化、缓存头被上游覆盖curl -I 查看缓存头和 ETag
静态文件首字节很快,但文件下载时间较长文本资源未压缩、压缩级别过高或客户端未发送压缩能力查看 Content-Encoding、Vary 和实际下载大小
动态请求返回 502上游端口不可达、上游进程提前断开或配置的上游地址错误查看 upstream_status、upstream_connect_time 和 Nginx 错误日志
动态请求返回 504上游连接或读取阶段超过设定时间区分 connect_time、header_time、response_time
只有慢客户端请求容易中断客户端发送或接收速度低,send_timeout 等参数过短对比 request_time 与 upstream_response_time
修改了资源但用户仍看到旧内容URL 未变化且浏览器或中间缓存仍按旧的长期缓存策略处理检查 URL 指纹、响应头和强制重新验证结果

这里的“超时”不是一个统一参数。proxy_connect_timeout 控制 Nginx 建立上游连接的等待时间,proxy_send_timeout 控制向上游发送请求时相邻写操作之间的等待时间,proxy_read_timeout 控制读取上游响应时相邻读操作之间的等待时间,send_timeout 则作用于向客户端发送响应的阶段。把它们全部调大,可能只是让故障更晚暴露。

修改前先拿到可对比的数据

确认软件和配置位置

以下命令适用于使用 systemd 管理 Nginx 的 Linux 系统。命令本身只读取状态,不会修改服务:

nginx -V 2>&1 | head -n 5
systemctl status nginx --no-pager
nginx -t

如果服务名称不是 nginx,先通过系统已有的服务列表确认实际名称,不要直接猜测。修改前应备份实际生效的配置文件或独立配置片段。备份路径和配置路径必须以 nginx -V 输出的 --conf-path 为准。

配置变更的基本回滚方式是:恢复变更前的备份文件,先执行 nginx -t,确认语法通过后再执行平滑加载。恢复前应保留当前文件,避免把一次错误覆盖变成无法追溯的状态。配置加载失败时,不要直接重启服务,先修正语法或恢复上一版。

分别测试静态和动态请求

使用实际域名和实际资源路径替换示例中的占位符:

curl -sS -D - -o /dev/null \
  --compressed \
  'https://你的域名/assets/app.版本号.js'
curl -sS -o /dev/null \
  -w 'code=%{http_code}\nconnect=%{time_connect}\nstarttransfer=%{time_starttransfer}\ntotal=%{time_total}\nsize=%{size_download}\n' \
  'https://你的域名/动态请求路径'

重点观察:

  • http_code:确认是否出现 4xx、502 或 504。
  • time_connect:客户端到 Web 服务入口建立连接的耗时。
  • time_starttransfer:收到首字节前的等待时间,通常包含入口处理和上游等待。
  • time_total:包括响应传输在内的总耗时。
  • size_download:结合是否启用压缩判断传输大小变化。

同一个请求至少重复测试几次,并分别测试静态资源、普通页面和确实会访问上游的动态接口。单次请求不能代表稳定状态,也不能据此直接提高全部超时参数。

先处理连接和响应阶段

连接参数的目标不是让连接保持得越久越好,而是在复用连接、连接占用和客户端体验之间取得平衡。

客户端连接复用

在 Nginx 的 http {} 配置上下文中,可以使用类似设置:

http {
    keepalive_timeout 15s;
    keepalive_requests 1000;
    send_timeout 30s;

    # 其他 http 级别配置
}

这组数值只是可用于测试的起点,不是适用于所有日本服务器的固定答案:

  • keepalive_timeout 过短,会增加重复建立连接的次数;过长,则会让大量空闲连接占用资源。
  • keepalive_requests 过低,连接复用次数有限;过高时应结合单个连接的请求量和资源占用观察。
  • send_timeout 不是整个响应的总耗时限制,而是向客户端发送数据时相邻写操作之间的等待限制。慢客户端较多时,设置过短可能导致传输中断;设置过长则可能积累长期占用的连接。

如果怀疑连接数或文件描述符不足,可先执行:

ss -s
ss -lnt

再查看 Nginx 错误日志中是否存在连接耗尽、打开文件失败或监听队列异常等信息。只有在日志和系统状态能够证明连接资源不足时,才考虑检查 worker_connections、进程文件描述符上限等参数。单纯提高 worker_connections 并不会提升上游应用的处理能力,还可能受到系统文件描述符限制。

区分入口连接慢和上游响应慢

建议在 Nginx 的 http {} 上下文中加入带时间字段的访问日志。已有日志格式时,应在备份后增加新格式,不要直接删除原有字段:

http {
    log_format timing
        '$remote_addr - $host [$time_local] '
        '"$request" $status $body_bytes_sent '
        'request_time=$request_time '
        'upstream_status=$upstream_status '
        'upstream_connect_time=$upstream_connect_time '
        'upstream_header_time=$upstream_header_time '
        'upstream_response_time=$upstream_response_time';

    access_log /var/log/nginx/access.log timing;
}

这些字段的含义如下:

  • request_time:Nginx 从接收请求到完成响应的总时间。
  • upstream_connect_time:建立上游连接所用的时间。
  • upstream_header_time:从连接上游到收到上游响应头的时间。
  • upstream_response_time:从连接上游到读取完上游响应的时间,具体格式可能因多个上游尝试而出现多个值。
  • upstream_status:上游返回的状态,若请求没有到达上游,可能为空。

如果 upstream_connect_time 很低,但 upstream_header_time 和 upstream_response_time 较高,问题更接近上游处理或上游等待。若上游时间很低但 request_time 明显更高,应继续检查响应发送、客户端接收速度和 Nginx 输出缓冲,而不是继续增加 proxy_read_timeout。

静态资源缓存要与更新方式匹配

缓存优化首先要解决“哪些资源可以长期缓存”,而不是给所有路径统一设置很长的有效期。

带版本号的资源使用长期缓存

如果 CSS、JavaScript、字体和图片的 URL 会随内容变化,例如:

/assets/app.8f31c.js
/assets/site.20260927.css

可以在 server {} 内使用独立的静态资源位置:

server {
    listen 80;
    server_name 你的域名;
    root /var/www/site/public;

    location ^~ /assets/ {
        try_files $uri =404;
        add_header Cache-Control "public, max-age=604800, immutable";
        etag on;
    }
}

这里的关键是资源内容变化时必须同步改变 URL。immutable 表示在有效期内客户端不必反复验证资源;如果部署时仍然覆盖同一个文件名,旧内容可能继续被使用,此时不应随意添加 immutable。

try_files $uri =404 可以避免静态资源不存在时被错误地转发到动态入口。对于资源路径,返回明确的 404 通常比让应用生成一个 HTML 页面更容易诊断,也避免把错误页面当作脚本或样式返回。

HTML 和用户相关内容不要照搬静态策略

页面入口和包含登录状态、权限信息或用户数据的响应,不应直接套用长期公共缓存。常见做法是:

  • 内容不应落入缓存:使用适合业务的 private 或 no-store 策略。
  • 内容允许缓存但必须先确认是否变化:使用 no-cache,它表示使用前重新验证,并不等于完全不缓存。
  • 内容可以按版本长期缓存:确保 URL、文件内容和发布流程严格绑定。

如果上游已经返回了 Cache-Control、ETag 或 Last-Modified,先确认 Nginx 是否重复添加了相互冲突的响应头。add_header 在不同配置层级存在继承规则,新增位置级别的 add_header 可能改变原有头部继承结果,不能只看配置片段而忽略最终响应。

验证缓存是否真的生效

检查响应头:

curl -sS -D - -o /dev/null \
  'https://你的域名/assets/app.版本号.js'

重点确认:

  • 是否存在预期的 Cache-Control。
  • 是否存在 ETag 或 Last-Modified。
  • 资源 URL 不变时,内容更新是否会导致旧缓存继续命中。
  • 首次请求和带条件请求的状态是否符合预期,例如客户端携带 If-None-Match 后是否返回 304。

如果修改了文件但内容没有变化,优先检查资源 URL 是否仍然相同、浏览器是否保留旧缓存、响应头是否被上游覆盖。不要仅通过清空服务器目录或强制重启服务来处理缓存问题,那通常不能解决客户端已经保存的旧响应。

压缩只作用于适合压缩的响应

文本类资源通常适合压缩,已经压缩过的图片、音频、视频和归档文件再次压缩,通常只会增加 CPU 消耗和处理时间。Nginx 的压缩配置可以放在 http {} 上下文:

http {
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_comp_level 5;

    gzip_types
        text/plain
        text/css
        application/javascript
        application/json
        application/xml
        image/svg+xml;
}

需要注意几个判断点:

  • gzip_vary on 会让响应带上 Vary: Accept-Encoding,使不同压缩能力的客户端得到正确版本。
  • gzip_min_length 用于避免对很小的响应增加压缩开销,具体阈值应根据实际资源分布调整。
  • gzip_comp_level 越高不代表页面一定更快,因为压缩端 CPU 消耗会增加。应通过 time_starttransfer、CPU 使用情况和响应大小共同判断。
  • gzip_types 按响应的 Content-Type 匹配,不是按文件扩展名猜测。上游错误设置 MIME 类型时,即使文件本身是文本,也可能没有压缩。
  • 浏览器或客户端未发送 Accept-Encoding 时,Nginx 不应强制返回压缩内容。

压缩测试应使用实际 GET 请求:

curl -sS --compressed \
  -D /tmp/headers.txt \
  -o /dev/null \
  'https://你的域名/assets/app.版本号.js'

grep -Ei '^(HTTP/|Content-Encoding:|Content-Length:|Transfer-Encoding:|Vary:)' \
  /tmp/headers.txt

如果出现 Content-Encoding: gzip,说明客户端和服务端完成了压缩协商。若没有该字段,应检查客户端请求头、响应 Content-Type、Nginx 配置上下文以及上游是否已经设置了不允许压缩的响应头。

对流式输出、长连接响应或需要尽快逐段发送的数据,不要全局套用相同的压缩策略。压缩可能改变数据发送节奏,应该为这类路径单独验证,而不是只看普通 HTML 或 JavaScript 的结果。

上游超时要按阶段设置

先确认上游是否真的可用

假设应用监听在本机某个端口,先查看监听状态:

ss -lntp

如果应用提供了明确的健康检查路径,可以从日本服务器本机发起请求:

curl -sS -D - -o /dev/null \
  'http://127.0.0.1:8080/实际健康检查路径'

只有在该路径确实存在、端口和协议确认无误时,才使用这条命令。连接被拒绝通常意味着端口没有监听或监听地址不匹配;连接成功但响应迟缓,则应查看上游应用自身的处理日志。不要把“本机端口可连接”误判成“所有业务请求都正常”。

为不同阶段设置独立参数

在 server {} 的动态位置中,可以使用如下示例:

upstream app_backend {
    server 127.0.0.1:8080;
    keepalive 32;
}

server {
    listen 80;
    server_name 你的域名;

    location / {
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_connect_timeout 3s;
        proxy_send_timeout 30s;
        proxy_read_timeout 30s;
        send_timeout 30s;

        proxy_buffering on;
        proxy_pass http://app_backend;
    }
}

这段配置需要根据现有站点的监听方式、上游端口和域名替换占位符。示例中的时间值只适合作为初始验证值,不能当作业务 SLA,也不应未经测试直接用于所有接口。

各参数的调整依据如下:

  • proxy_connect_timeout 过期:优先查上游端口、监听地址、进程负载和连接资源。提高这个值不能修复端口错误或上游未启动。
  • proxy_send_timeout 过期:可能是向上游发送请求时对方读取缓慢,也可能是请求体较大或上游处理连接异常。需要结合请求大小和上游日志判断。
  • proxy_read_timeout 过期:常见于上游长时间没有返回数据。应先确认是业务计算确实需要较长时间,还是上游卡住、等待资源或发生阻塞。
  • send_timeout 过期:更接近向客户端发送响应时的问题,不代表上游一定慢。

如果只有某一个长耗时接口确实需要更长的等待时间,应为该接口单独设置更长的 proxy_read_timeout,不要全局放大所有动态请求的等待窗口。对于持续输出或流式接口,还要单独评估 proxy_buffering;关闭缓冲可能改变响应行为并增加连接占用,只能在确认接口特性后使用。

用状态码和时间字段区分 502、504

  • 502:重点检查上游地址、端口、协议、进程是否提前关闭连接,以及 Nginx 与上游之间的请求头或响应格式是否异常。
  • 504:重点对照 upstream_connect_time、upstream_header_time 和 upstream_response_time。连接阶段超时与应用处理阶段超时,修复方向不同。
  • 200 但页面仍慢:可能是上游已经快速返回,但响应体发送给客户端较慢,或者页面继续加载了大量未缓存、未压缩的资源。
  • 部分请求快、部分请求慢:不要只看平均值,应按照接口、资源路径和状态码分别检索日志,确认是否只有特定请求触发慢路径。

一次变更后的验证和回滚

配置修改后,先校验,再加载:

nginx -t
sudo systemctl reload nginx

reload 前应确认当前服务由该 systemd 单元管理,并已经完成配置备份。加载后马上检查错误日志和新请求的访问日志。如果 nginx -t 失败,不要执行 reload;如果 reload 后出现大量新错误,应恢复上一版配置,重新执行 nginx -t,确认通过后再加载。

建议按以下顺序验证:

  1. 先看状态码:确认静态资源没有从 200 变成 404,动态请求没有新增 502 或 504。
  2. 再看响应头:检查静态资源的 Cache-Control、ETag、Content-Encoding 和 Vary 是否符合预期。
  3. 再看计时字段:比较变更前后的 upstream_connect_time、upstream_header_time、upstream_response_time 和 request_time。
  4. 最后测重复请求:用相同 URL、相同请求头重复访问,确认缓存命中、条件请求和压缩协商没有互相冲突。
  5. 观察一段实际流量:确认错误不是只在测试请求中消失,而是没有出现连接数持续增长、上游排队增加或客户端传输中断。

最容易遗漏的是“配置已经改变,但实际响应没有改变”。这通常与配置没有加载、请求命中了另一个 server、位置匹配顺序不符合预期、上游覆盖了响应头,或客户端仍在使用旧缓存有关。最终应以 nginx -t、新产生的访问日志和真实响应头三者相互对应为准,而不是只看配置文件中是否出现了某个参数。

目录结构
全文