排查nginx缓冲区引发swap抖动,关键是确认工作集是否被换出:当proxy_buffers等总配额超物理内存且高并发时,rss接近memavailable、swapfree骤降、si/so持续非零即为典型表现。

排查 Nginx 缓冲区配置引发的内存交换(swap)抖动,关键不是看“用了多少内存”,而是确认“是否被迫把工作集换出到磁盘”——这通常发生在缓冲区总配额远超可用物理内存、且高并发触发批量分配时。抖动表现为响应延迟毛刺、P99 突增、系统级 si/so(swap in/out)值持续非零,free -h 显示可用内存充足但 swapon --show 有活跃交换。
查内存压力是否真实来自 Nginx 缓冲区
先隔离干扰:用 top -p $(pgrep nginx | head -n1) 查单个 worker 进程 RSS;再对比所有 worker 总 RSS 与系统空闲内存(free -h | awk '/^Mem:/ {print $7}')。若总 RSS 接近或超过可用内存(MemAvailable),且 cat /proc/meminfo | grep -E "(Swap|MemAvailable)" 显示 MemAvailable 持续低于 1GB、SwapTotal > 0 且 SwapFree 快速下降,基本可锁定为缓冲区内存过载。
- 重点盯 proxy_buffers + proxy_buffer_size 总和:例如 proxy_buffers 8 128k; proxy_buffer_size 4k → 单连接理论最大内存占用约 1MB;万级并发下理论峰值达 10GB,极易触发 swap
- 注意 proxy_busy_buffers_size 不当会放大压力:它必须 ≤ 总 buffer,但若设得过大(如 512k),会导致 busy 状态缓冲区长期滞留,无法释放,实际内存占用翻倍
- 检查是否误开 proxy_buffering off + 大 body 缓存:虽然关了 proxy_buffering,但若同时配了 client_body_buffer_size 128k 和 client_max_body_size 100m,大 POST 请求体仍会全量进内存(而非直写磁盘),造成隐性内存尖峰
验证 swap 是否由缓冲区分配触发
用 perf record -e 'syscalls:sys_enter_mmap' -p $(pgrep nginx | head -n1) sleep 30 抓 mmap 调用,再 perf script | grep -i "prot.*write" | head -20 看是否大量申请可写内存页;配合 vmstat 1 60 观察 si/so 是否与 Nginx 请求洪峰同步跳升。若两者高度吻合,说明缓冲区动态分配正在驱动 swap。
- 在 access_log 中加 $request_time $upstream_response_time $bytes_sent 字段,用日志分析工具(如 GoAccess 或 Loki 查询)筛选 request_time 高但 bytes_sent 小 的请求——这类请求大概率卡在缓冲区等待填满或超时,是内存积压信号
- 检查 error.log 是否频繁出现 "* upstream sent too big header" 或 "no live upstreams":前者说明 proxy_buffer_size 不足导致反复重试分配,后者可能是 worker 因 OOM 被 kernel 杀掉后未及时恢复
调优缓冲区配置避免 swap
核心原则:让缓冲区总容量可控、可预测,不随并发线性膨胀。禁用“按需无限分配”逻辑,改用静态上限+流式兜底。
- 限制单 worker 内存上限:在 events 块中加 worker_rlimit_core 2G;(配合 ulimit -c),并确保 /proc/sys/kernel/core_pattern 指向足够空间,便于 crash 后分析内存分布
- 降级中等响应处理方式:对已知大响应路径(如 /api/report),显式关闭缓冲:location /api/report { proxy_buffering off; },让数据边收边发,不占额外 buffer
- 收紧默认缓冲规模:将 proxy_buffers 改为 4 64k(共 256KB),proxy_buffer_size 保持 4k,proxy_busy_buffers_size 设为 128k;实测在 8GB 内存节点上,可支撑 3000+ 并发而不触发 swap
- 启用内存盘临时路径(备选):若业务必须保留 proxy_buffering on 且响应偏大,将 proxy_temp_path /dev/shm/nginx_temp 1 2;,避免磁盘 swap,但需确保 /dev/shm 有足够空间(建议挂载时指定 size=2G)
监控与兜底机制
仅靠配置不够,需建立可观测闭环:
- 用 Prometheus 抓取 process_resident_memory_bytes{job="nginx"},设置告警:连续 3 分钟 > 80% 节点内存
- 在 reload 配置前自动执行 nginx -t && ps aux --sort=-%mem | head -5,检查当前 worker 内存占用趋势
- 为关键 upstream 添加 proxy_next_upstream error timeout http_502,当某 worker 因内存紧张开始返回 502 时,快速切走流量,防止雪崩











