7.7.3 性能瓶颈识别:CPU、内存、I/O与网络

性能瓶颈识别的核心是将现象与资源维度对应起来:CPU 过载常伴随吞吐下降与响应时间抖动;内存压力导致频繁换页或缓存失效;I/O 瓶颈表现为请求堆积与磁盘队列升高;网络瓶颈多体现为连接积压与丢包重传。排查应以“指标→现象→定位点→验证手段”的流程推进,避免仅凭单一指标下结论。

文章图片

CPU 瓶颈识别
- 典型现象:QPS 降低、响应时间突增、请求排队,系统 load 高且 us/sy 占比偏高。
- 关键指标:CPU 使用率、上下文切换、系统态占比、运行队列长度。
- 常见原因:过多 worker/连接导致调度频繁;正则过重、复杂重写;Lua/OpenResty 逻辑耗时;TLS 握手与加密开销。
- 验证与定位示例(带命令解释):

# 1) 查看整体 CPU 与负载
top -o %CPU
# 关注: %us/%sy/load,判断是否 CPU 过载

# 2) 精确到 Nginx 进程与线程
PID=$(pidof nginx | awk '{print $1}')
pidstat -u -p "$PID" 1
# 关注: usr/sys 与上下文切换,定位是否 Nginx 自身耗 CPU

# 3) 确认是否为请求计算耗时
tail -n 5 /var/log/nginx/access.log
# 日志需包含 $request_time 与 $upstream_response_time

内存瓶颈识别
- 典型现象:访问延迟抖动、缓存命中率降低、系统频繁 swap,Nginx 连接被动关闭。
- 关键指标:可用内存、page fault、swap in/out、缓存区使用、Nginx 连接数与缓存占用。
- 常见原因:共享内存区不足或配置不合理;过大 buffer 或过多并发连接;日志过大导致文件缓存挤压。
- 验证与定位示例

# 1) 内存与 swap 观察
free -m
vmstat 1
# 关注: si/so(交换), free/buff/cache, r(运行队列)

# 2) 查看 Nginx 连接与内存配置
grep -nE 'worker_connections|client_body_buffer_size|proxy_buffers' /etc/nginx/nginx.conf
# 检查是否配置过大导致内存膨胀

I/O 瓶颈识别
- 典型现象:请求排队、静态文件加载变慢、日志写入阻塞,系统 iowait 升高。
- 关键指标:磁盘 IOPS、iowait、队列长度、平均等待时间。
- 常见原因:大量小文件读取、日志同步写入过频、缓存未命中导致频繁回源、磁盘带宽不足。
- 验证与定位示例

# 1) 查看磁盘队列与等待时间
iostat -x 1
# 关注: await/util,如果 util 接近 100% 且 await 高,I/O 为瓶颈

# 2) 观察块设备吞吐
sar -b 1 3
# 关注: tps/rd_sec/wr_sec

# 3) 检查 Nginx 是否启用高效 I/O
grep -nE 'sendfile|aio|open_file_cache' /etc/nginx/nginx.conf

网络瓶颈识别
- 典型现象:连接建立慢、上游响应延迟、502/504 增多、访问量上升但吞吐不增。
- 关键指标:带宽利用率、连接数、重传率、SYN 队列、TIME_WAIT 数量。
- 常见原因:带宽不足、NAT/防火墙限制、上游负载均衡不均、内核参数限制。
- 验证与定位示例

# 1) 连接状态与积压
ss -s
# 关注: TCP 连接状态分布,SYN-SENT/ESTAB/TIME-WAIT

# 2) 网卡吞吐与丢包
sar -n DEV 1 3
# 关注: rxpck/s txpck/s rxkB/s txkB/s

# 3) 内核队列参数
sysctl net.core.somaxconn net.ipv4.tcp_max_syn_backlog

日志与指标联动示例(带完整配置与预期效果)

# /etc/nginx/nginx.conf(片段)
http {
  log_format main '$remote_addr $request '
                  'rt=$request_time urt=$upstream_response_time '
                  'status=$status';
  access_log /var/log/nginx/access.log main;

  upstream app {
    server 10.0.0.10:8080;
  }
  server {
    listen 80;
    location / {
      proxy_pass http://app;
    }
  }
}
# 预期效果:日志中同时出现 request_time 与 upstream_response_time
tail -n 3 /var/log/nginx/access.log
# 例:rt=0.120 urt=0.030 说明 Nginx 自身或网络耗时更大

综合判断与交叉验证
- 先看整体指标(CPU/内存/IO/网络),再结合 Nginx 层指标(QPS、连接数、请求耗时分布)。
- 利用日志与监控的时间对齐:高峰时段是否与资源飙升一致。
- 将问题拆分为“接入层瓶颈”与“上游瓶颈”:若 $upstream_response_time 长而 $request_time 更长,优先定位上游或网络;若 $request_time 长而上游正常,优先定位 Nginx 自身或系统资源。
- 建议建立基线阈值与告警:CPU > 70%、iowait > 10%、丢包率上升、连接数接近上限等。

排错清单(快速定位)

# 1) 系统全局
top -o %CPU
free -m
iostat -x 1
ss -s

# 2) Nginx 自身
PID=$(pidof nginx | awk '{print $1}')
pidstat -u -p "$PID" 1
grep -nE 'worker_processes|worker_connections' /etc/nginx/nginx.conf

# 3) 上游延迟
awk '{print $0}' /var/log/nginx/access.log | tail -n 5

练习
1. 人为制造 CPU 压力(在测试环境):

# 安装压力工具(示例)
yum install -y stress || apt-get install -y stress
stress --cpu 2 --timeout 30
# 观察 top/pidstat 的变化,记录 rt/urt 是否同步上升
  1. 人为制造 I/O 压力(在测试环境):
dd if=/dev/zero of=/tmp/io.test bs=1M count=1024 oflag=direct
iostat -x 1
# 观察 await/util 是否显著上升
  1. 通过日志判断瓶颈位置:找出 rt 明显大于 urt 的请求并说明可能原因。