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

Debian Nginx访问变慢如何判断资源瓶颈?联动CPU、内存与磁盘I/O

发布人:Minchunlin 发布时间:2026-10-04 11:35 阅读量:2

单看 CPU、内存或磁盘中的任何一个指标,都可能把 Debian Nginx 的访问变慢归因错误。更可靠的判断方式是建立同一时间窗口,把请求耗时、错误率、CPU 运行队列、内存回收、磁盘延迟、网络队列以及上游响应时间放在一起观察:CPU 使用率高且运行队列持续堆积,才更像 CPU 瓶颈;内存可用量下降并伴随换入换出,才支持内存不足;磁盘 await、队列和 iowait 同时上升,才应优先检查磁盘 I/O。若主机资源正常但 $upstream_response_time 持续升高,则应转向应用或数据库,而不是继续调整 Nginx worker 数量。

实际操作中,可以先在访问变慢的 5~10 分钟内记录 Nginx 请求时间,再同步采集 vmstat、iostat、sar、ss 和进程数据。之后按照“请求耗时变化 → 系统指标联动 → 排除替代解释 → 得出瓶颈类型 → 复测”的顺序判断。下面的数值和监控结果均为解释机制用的典型示例,不代表某台服务器的实测结果。

先建立统一的观察窗口配图

先建立统一的观察窗口

记录请求端到端耗时

如果只执行一次 curl,结果可能受到网络抖动、缓存命中和请求内容差异影响。应选定一个稳定的 URL、请求方法和测试参数,在业务允许的范围内重复观察,不要在生产高峰随意进行高并发压测。

curl -sS -o /dev/null \
  -w 'code=%{http_code} dns=%{time_namelookup} connect=%{time_connect} start=%{time_starttransfer} total=%{time_total} size=%{size_download}\n' \
  --max-time 15 \
  https://example.com/health

重点关注以下变化:

  • time_starttransfer 较高,说明等待服务端开始返回数据的时间变长,应用、数据库、上游连接或服务器排队都可能参与其中。
  • time_total 较高但 time_starttransfer 正常,可能是响应体传输慢、客户端接收慢或网络拥塞。
  • HTTP 状态码从 2xx 变为 499、502、504 或 5xx 时,应将错误率和耗时放在同一窗口观察。
  • 访问单个 URL 变慢,不一定表示整台服务器资源不足,也可能只是该接口的查询、锁等待或业务逻辑发生变化。

同时采集系统指标

Debian 常见的 vmstat、iostat 和 sar 分别用于观察运行队列与内存、块设备 I/O、网络及 TCP 状态。如果系统没有 iostat 或 sar,可以安装 sysstat;安装前应确认服务器允许更新软件包索引,生产环境最好在维护窗口执行。

sudo apt-get update
sudo apt-get install -y sysstat

故障发生时,可以先进行一组短时采样:

date '+%F %T'
uptime
free -h
vmstat 1 10
iostat -xz 1 10
sar -n DEV,TCP,ETCP 1 10
ss -s
ps -eo pid,ppid,stat,comm,%cpu,%mem --sort=-%cpu | head -n 15

短时采样只能帮助确认现场。若访问变慢持续数分钟,应让采样覆盖完整故障窗口,并记下每条命令的时间。vmstat 中的 r、b、si、so、wa,以及 iostat 中的 await、队列、%util,需要和 Nginx 日志中的请求时间对齐,而不能拿不同时间段的数据进行比较。

先把 Nginx 请求时间拆开

使用上游时间区分 Nginx、应用和客户端

如果 Nginx 当前日志没有记录请求耗时,可以临时增加一套性能日志。配置变更前先备份 Nginx 配置;额外日志会增加写盘量,在磁盘已经接近饱和时不宜立即启用。

在 /etc/nginx/nginx.conf 的 http 配置块中增加唯一名称的日志格式:

log_format perf
    '$time_iso8601 request="$request" '
    'status=$status upstream_status=$upstream_status '
    'request_time=$request_time '
    'upstream_connect_time=$upstream_connect_time '
    'upstream_header_time=$upstream_header_time '
    'upstream_response_time=$upstream_response_time '
    'bytes_sent=$bytes_sent';

access_log /var/log/nginx/perf_access.log perf;

修改后先检查语法,再平滑加载:

sudo nginx -t
sudo systemctl reload nginx

nginx -t 失败时不会执行 reload,应根据报错修正配置。若新日志导致写盘压力增加,或需要恢复原有日志格式,应使用修改前的备份文件恢复,重新执行 nginx -t,确认通过后再 reload。不要直接覆盖配置而不保留回滚副本。

这些字段可以这样理解:

指标主要含义适合验证的问题
request_timeNginx 处理该请求的总耗时用户感知的服务端请求时间
upstream_connect_time与上游建立连接所用时间上游连接、网络、连接队列是否异常
upstream_header_time从连接上游到收到响应头的时间应用处理、数据库查询、锁等待是否变慢
upstream_response_time从连接上游到接收完整响应的时间上游整体处理和响应传输时间
statusNginx 返回给客户端的状态码499、5xx 是否随延迟增加
upstream_status上游返回的状态码应用服务是否主动报错

例如,request_time 从 0.2 秒升到 3 秒,同时 upstream_response_time 也接近 2.8 秒,通常应先调查应用或数据库。若 upstream_response_time 只有 0.1 秒,但 request_time 达到 3 秒,则要检查客户端接收、网络发送队列、响应体大小以及 Nginx 所在主机的 I/O。

判断 CPU 是否真的成为瓶颈

CPU 瓶颈不是“CPU 使用率超过某个数字”这么简单,而是请求变慢时,处理器繁忙、运行队列堆积和相关进程耗时同时出现。

在 vmstat 中:

  • us 表示用户态 CPU 时间,应用计算、脚本执行、压缩等可能使它升高。
  • sy 表示内核态 CPU 时间,网络处理、系统调用和 I/O 相关内核工作可能使它升高。
  • id 是空闲比例。
  • r 是等待运行的任务数,持续高于可用 CPU 核数时,说明存在运行队列压力。
  • wa 是 CPU 等待 I/O 的时间,不能简单当作 CPU 计算瓶颈。

典型的 CPU 瓶颈组合是:

request_time       持续升高
vmstat r           长时间接近或超过 vCPU 数量
vmstat us+sy       较高,id 较低
vmstat wa          不高
nginx 或应用进程   在 ps/pidstat 中持续占用较多 CPU

例如,8 vCPU 服务器在访问变慢期间持续出现 r=10、id=5%,同时 Nginx worker 或应用进程的 CPU 使用率很高,这比单独看到一次 95% CPU 更能支持“CPU 排队”的判断。

但以下情况不能直接归因于 CPU:

  • load average 很高,而 r 并不高、wa 很高。Linux 的 load average 也会包含处于不可中断 I/O 等待的任务。
  • CPU 总使用率不高,但某个单线程应用已经占满一个核心。应查看单进程或单线程分布,而不是只看总百分比。
  • Nginx CPU 较低,但上游应用响应时间很高。此时 Nginx 可能只是在等待应用返回。
  • CPU 短暂冲高,但请求耗时和错误率没有同步变化。短时任务不一定构成用户可感知的瓶颈。

虚拟机环境还可以关注 vmstat 的 st。如果 st 持续升高,说明虚拟 CPU 受到宿主机调度影响;这属于运行环境的 CPU 争用,不能通过单纯调整 Nginx 配置解决。

判断内存是否导致访问变慢

Debian 上使用 free -h 时,不要只看 free 一列。Linux 会将空闲内存用于文件缓存,因此 free 较小并不等于内存不足,应重点看 available,并结合换入换出和内存压力。

free -h
swapon --show
cat /proc/pressure/memory
vmstat 1 10

更有说服力的内存瓶颈组合通常包括:

  • available 持续下降,而不是瞬时变小;
  • vmstat 的 si、so 持续有数据,表明发生交换分入或分出;
  • memory PSI 中的 some 或 full 压力持续增加;
  • 请求耗时、磁盘读写延迟和进程响应时间同步变差;
  • 内核日志出现 OOM 或进程被终止记录。

参考判断可以是:如果可用内存降到总内存的约 10% 以下,同时 si/so 持续增长并伴随响应时间上升,应优先处理内存压力。但这个比例只是报警起点,不能替代现场验证。不同业务的缓存规模、连接数和内存峰值差异很大。

需要排除几个常见误判:

  • free 很低但 available 仍充足、没有 swap 活动,通常只是文件缓存较多。
  • swap 已启用不代表当前一定存在内存瓶颈,关键是观察 si/so 是否在故障窗口持续增长。
  • 主机内存充足,但 Nginx 或应用受到 systemd、容器或 cgroup 内存上限限制,进程仍可能被迫回收或 OOM。此时要同时检查服务或容器的资源限制。
  • 内存回收引起的磁盘读写会表现为 wa 和磁盘 await 上升,因此内存与磁盘问题可能同时出现,不能只归类为 I/O。

如果内存指标正常,swap 没有活动,PSI 也没有明显压力,那么访问变慢时应暂时降低“内存不足”的优先级,转而检查 CPU、磁盘、网络和上游响应。

判断磁盘 I/O 是否拖慢 Nginx

磁盘问题通常要同时观察设备延迟、队列、利用率和请求时间。执行:

iostat -xz 1 10
vmstat 1 10
df -h
df -i

iostat -xz 中不同版本的列名可能略有差异,常见关注项包括:

  • await:读写请求从提交到完成的平均等待时间,单位通常为毫秒。
  • r_await、w_await:读请求和写请求的等待时间。
  • aqu-sz 或 avgqu-sz:设备请求队列长度。
  • %util:设备忙碌比例。
  • rkB/s、wkB/s:实际读写速率。

较强的磁盘瓶颈证据通常是:请求变慢的同一时间段内,wa 上升,设备 await 从平时的个位数毫秒增加到几十甚至更高,队列变长,%util 长时间接近设备饱和,同时 Nginx 访问日志中的耗时也上升。

需要注意,%util 在不同存储设备上的解释并不完全相同。高速设备可能在较高吞吐下仍有较低延迟,机械盘或共享存储则可能较早出现排队。因此不要用“利用率达到某个数字”单独下结论,必须同时看 await、队列和请求时间。

Nginx 访问变慢与磁盘相关的常见场景包括:

  • 静态文件读取延迟升高;
  • access log、error log 或其他业务日志写入堆积;
  • 内存不足引发页面换入换出;
  • 应用或数据库在同一设备上进行大量读写;
  • 文件系统空间或 inode 用尽,导致写日志、创建临时文件失败。

如果只有磁盘 wkB/s 突然上升,而 Nginx 请求时间没有变化,可能是后台任务或其他进程造成的独立 I/O。可以结合进程级数据进一步确认:

pidstat -d 1 10

如果 Nginx 日志记录的 request_time 很高,但 upstream_response_time 很低,同时 Nginx worker 的磁盘写入明显增加,应检查日志写入和客户端响应过程;如果上游时间也很高,则磁盘可能位于应用或数据库所在路径,而不一定是 Nginx 自身。

排除网络和连接队列问题

网络瓶颈不能只看带宽。服务器网卡的收发速率、丢包和错误、TCP 重传、连接发送队列以及客户端接收速度,都可能造成访问变慢。

ip -br link
ip -s link show dev eth0
sar -n DEV,TCP,ETCP 1 10
ss -s
ss -lnt

其中 eth0 只是示例,应替换为 ip -br link 显示的实际接口名称。

可以重点观察:

  • rx、tx 速率是否接近已知的接口容量;
  • 网卡错误、丢包计数是否在故障窗口增长;
  • TCP 重传是否增加;
  • 监听 socket 的 Recv-Q 是否长期堆积;
  • 已建立连接的 Send-Q 是否持续增长;
  • Nginx 的 request_time 是否明显高于 upstream_response_time。

网络瓶颈的一个典型表现是:上游在 100 毫秒内已经生成响应,但 Nginx 到客户端的总耗时达到数秒,期间发送队列、重传或网卡丢包增加。这时继续优化应用查询可能不会立即改善用户体验。

也要区分服务器网络和客户端网络:

  • 如果只有个别客户端慢,服务器整体请求时间、错误率和网卡指标正常,可能是客户端链路或局部网络问题。
  • 如果大量客户端同时变慢,服务器发送队列、重传和错误率同步增加,才更支持服务端网络或出口拥塞。
  • 如果 Recv-Q 持续增长,可能是应用处理不及时、连接接受能力不足或上游排队;它本身不能单独证明网卡带宽不足。

对于 HTTP 状态码,499 通常表示客户端在 Nginx 返回前主动关闭连接。它可能由客户端超时引起,也可能是服务端响应太慢导致客户端放弃,因此应与 request_time、网络重传和上游耗时一起判断,而不是直接当成 Nginx 故障。

区分应用瓶颈与数据库瓶颈

当 Nginx 作为反向代理时,应用和数据库问题往往都会表现为“上游响应慢”。因此,Nginx 能够确认的是上游延迟,不能仅凭本机日志直接证明数据库是根因。

可以先按以下模式缩小范围:

现象组合更可能的方向下一步验证
upstream_connect_time 升高上游连接建立、网络、连接接受队列查看应用监听状态、连接数和 TCP 队列
upstream_header_time 升高应用处理、数据库查询或锁等待查看应用处理日志、数据库活动会话和慢查询
upstream_header_time 正常,但完整 upstream_response_time 较高上游响应体生成或传输较慢检查响应大小、应用输出和网络发送
Nginx CPU、内存、磁盘均正常,上游时间持续升高应用或数据库优先级较高分别查看应用队列、连接池、数据库查询和锁
只有某个接口变慢,静态文件和其他接口正常路由逻辑、特定查询或接口依赖对比该接口的参数、缓存和 SQL 耗时
5xx、502、504 与上游耗时同时增加上游过载、崩溃或超时查看应用错误日志、进程状态和上游服务可用性

应用侧应关注请求排队时间、工作线程或协程数量、连接池等待、接口处理耗时和错误日志。数据库侧则需要查看活动连接数、连接池等待、慢查询、锁等待、事务堆积及数据库自身的 CPU、内存和磁盘指标。

如果只能看到 Nginx 日志,比较稳妥的表述是“上游服务响应变慢”,不要直接写成“数据库导致”。只有当应用日志显示请求在等待数据库,且数据库侧同时出现慢查询、锁等待或资源压力时,才能把判断进一步收敛到数据库。

用联动数据形成判断

下面是一组模拟监控结果,用于说明如何排除替代解释。

示例一:不是 CPU,而是应用或数据库等待

在 8 vCPU 主机上,某接口的指标从正常到异常变化如下:

用联动数据形成判断配图

指标正常窗口变慢窗口
request_time0.22 秒2.90 秒
upstream_response_time0.16 秒2.75 秒
vmstat r1~32~4
CPU id65%~75%55%~68%
CPU wa2%~5%3%~6%
磁盘 await3~6 毫秒4~8 毫秒
swap si/so00

请求总耗时和上游耗时几乎同步增加,但运行队列没有超过 CPU 数量,磁盘延迟、换入换出也正常。此时 CPU、内存和磁盘都缺乏支持证据,应优先检查应用线程、连接池、接口内部查询和数据库等待。

示例二:更像磁盘 I/O

另一时间窗口中,数据表现为:

  • request_time 从 0.3 秒升至 2.6 秒;
  • upstream_response_time 仍在 0.2 秒左右;
  • vmstat wa 从 4% 升至 35%;
  • 某数据盘 await 从 5 毫秒升至 90 毫秒;
  • aqu-sz 持续增长,%util 长时间接近高位;
  • Nginx 或其他进程的日志写入量明显增加。

此时请求主要卡在 Nginx 到客户端的处理或本地 I/O,不能仅凭应用响应很快就认为整条链路正常。应进一步确认日志、静态文件、临时目录或同一设备上的其他进程是否制造了队列。

示例三:更像网络或客户端接收问题

如果:

  • upstream_response_time 约为 0.1 秒;
  • request_time 升至 3 秒;
  • CPU、内存和磁盘指标基本稳定;
  • Send-Q 增长,TCP 重传计数同步增加;
  • 大响应接口比小响应接口更明显;

则网络发送、链路丢包或客户端接收速度应优先排查。若只有一小部分客户端出现该现象,服务器整体资源正常,则不能据此认定 Nginx 主机网络已经饱和。

一套低风险的现场判断步骤

  1. 确认现象范围。 记录变慢的 URL、请求方法、状态码、响应大小和发生时间,区分是所有请求变慢,还是某个接口、某种响应体或某批客户端变慢。
  2. 建立时间基线。 在同一时间窗口保存 curl 耗时、Nginx access log、vmstat、iostat、sar 和 ss 输出,不要拿故障后的资源数据解释故障前的延迟。
  3. 先看请求时间拆分。 比较 request_time 和 upstream_response_time,再看 upstream_connect_time、upstream_header_time,确定等待发生在 Nginx、连接、应用处理还是响应传输阶段。
  4. 检查 CPU 与运行队列。 同时观察 us、sy、id、wa 和 r,确认是否为持续排队,而不是一次性 CPU 峰值。
  5. 检查内存与交换。 关注 available、si/so 和 PSI;仅凭 free 较小不要下结论。
  6. 检查磁盘延迟和队列。 将 await、%util、队列长度与 wa、日志写入和请求耗时对齐。
  7. 检查网络队列和重传。 查看接口错误、TCP 重传、监听队列及已建立连接的 Send-Q,判断是否存在服务器侧传输阻塞。
  8. 进入应用和数据库验证。 只有当上游耗时升高且主机基础资源无法解释时,才把排查重点转向应用队列、连接池、慢查询和锁等待。
  9. 一次只改变一个因素后复测。 例如先暂停一个非必要的日志写入任务或处理明确的资源异常,再用相同 URL、相同请求参数和相近并发量复测。若同时修改 Nginx、应用和数据库配置,就无法判断哪项变化产生了效果。

常见误判和适用边界

单个阈值不能替代关联判断

CPU 90%、磁盘 %util 90% 或内存使用率 90%都只能作为告警线索。短时峰值可能是正常任务,持续时间、队列长度、请求耗时和错误率的同步变化才决定它是否构成用户侧瓶颈。

load average 不等于 CPU 使用率

load average 高可能来自 CPU 排队,也可能来自等待磁盘的任务。需要用 vmstat 的 r 和 wa 分开观察,再结合 iostat 判断。

主机资源正常不代表应用正常

应用可能受线程池、连接池、锁、内部队列或超时策略限制。此时主机 CPU 甚至很空闲,但接口仍然会逐渐堆积请求。

Nginx 日志时间不是完整链路监控

request_time 能反映 Nginx 处理请求的时间,但不能单独说明客户端到服务器之间的每一段网络质量,也不能直接给出数据库 SQL 耗时。要确认数据库瓶颈,必须补充应用和数据库侧证据。

容器或资源配额会改变判断方式

如果 Nginx 运行在容器或受 systemd 资源限制的服务中,主机整体还有空闲资源,并不代表该服务没有达到自己的 CPU 或内存上限。应同时核对服务、容器或 cgroup 的配额,再解释 CPU、内存和 OOM 指标。

下一次故障要一起看什么

为了减少单点误判,下一次遇到 Debian Nginx 访问变慢时,至少保留下面这组同时间指标:

  • 请求层: request_time、upstream_connect_time、upstream_header_time、upstream_response_time、状态码和响应大小;
  • CPU 层: us、sy、id、wa、运行队列 r、高消耗进程;
  • 内存层: available、swap 使用与 si/so、内存 PSI;
  • 磁盘层: await、读写队列、%util、读写速率和进程级 I/O;
  • 网络层: 收发速率、错误丢包、TCP 重传、监听队列和连接 Send-Q;
  • 应用与数据库层: 上游错误、应用处理时间、连接池等待、慢查询和锁等待。

当这些指标位于同一个观察窗口内,判断就不再是“哪个数字最高”,而是能够回答“请求在哪个阶段开始排队、哪个资源与延迟同步变化、哪些替代原因已经被排除”。这才是监控系统资源并定位 Nginx 性能瓶颈的有效依据。

目录结构
全文