client_body_buffer_size超限仍写磁盘,因Nginx实际分配时自动加25%余量,且仅当真实请求体超出该余量值才落盘;需按P99大小×1.25向上取整配置,并确保与client_max_body_size同作用域且后者不小于前者。

client_body_buffer_size 超了为什么还会写磁盘?
它不是简单比大小就决定是否落盘。Nginx 实际分配缓冲区时会先加 25% 余量:size += size >> 2。比如你设 client_body_buffer_size 256k,真正尝试分配的是 320k;但若请求是已知长度(非 chunked),且 Content-Length 小于这个带余量的值,就改用 Content-Length 本身。只有真实数据超出最终分配大小,才把溢出部分写进 client_body_temp_path。
常见错误现象:
- 实测最大请求体是 255KB,设成
256k后仍看到write to temp file日志 - 压测时磁盘
write/s没降,iostat -x 1显示临时目录所在磁盘%util持续 >90%
解决办法:
- 按 P99 请求体大小 × 1.25 向上取整,比如 P99 是 300KB,建议设
512k而非384k(避免边界抖动) - 用
strace -p $(pgrep nginx) -e trace=openat,write确认上传时是否调用临时目录路径 - 禁用
client_body_in_file_only on(除非审计强需求),默认就是off
和 client_max_body_size 的关系搞混了会怎样?
client_body_buffer_size 控制内存驻留上限,client_max_body_size 才是最终拒绝阈值。两者不匹配,会导致“缓冲够大却直接 413”或“缓冲太小被迫落盘还被放行”。
典型问题场景:
- 在
http块设了client_body_buffer_size 1m,但在server块没重设client_max_body_size,沿用默认1m—— 表面看没问题,但一旦后端需要读完整 body,而 Nginx 已因缓冲不足写了一半到磁盘,就会出现读取不一致 - location 里只调大
client_max_body_size到500m,但client_body_buffer_size仍是默认8k,结果所有上传都落盘
必须同步检查:
- 两个指令必须放在同一作用域(
http、server或location),且client_max_body_size ≥ client_body_buffer_size - 用
nginx -T | grep -A2 -B2 "client_body"快速确认生效位置 - 确保
client_body_temp_path目录存在、worker 用户可写、磁盘空间 ≥ 2× 日均上传峰值体积
并发高时设太大反而拖垮服务?
每个 worker 进程为每个连接预留该缓冲区空间。设成 2m 在 2000 并发下,仅此一项就多占 4GB 内存——这不是浪费,是可能触发 OOM kill。
性能影响判断点:
- 调参后执行
ps aux | grep nginx,观察RSS是否异常增长(比如单 worker 从 80MB → 200MB) - 对比
ab -n 1000 -c 200 -p file.json http://host/api/前后延迟标准差:若抖动变大,说明内存压力已干扰事件循环 - 对纯 JSON API,
client_body_buffer_size 16k足够;含 Base64 图片的表单才需128k起步
更稳妥的做法:
- 按业务分层设置:API 接口用
16k,上传专用 location 用512k - 高并发小数据场景(如 IoT 心跳),反向调小到
4k,省下的内存可支撑更多连接 - 配合
client_body_timeout 30s,防慢速上传长期锁住缓冲区
怎么确认真的没写磁盘?
不能只信配置文件,得看运行态行为。最直接的证据来自三处:
- debug 日志里搜
client request body buffered in memory(成功走内存),而不是temp file或could not open temp file - 临时目录下无新增文件:
ls -lt /var/lib/nginx/body/ | head -5,连续上传 10 次应无变化 - 系统调用层面无落盘动作:
strace -p $(pgrep nginx) -e trace=openat,write 2>&1 | grep -i "body",上传期间不应出现对临时路径的openat
容易忽略的一点:
- 即使 buffer 足够,若后端(如 PHP-FPM)配置了
upload_tmp_dir,它自己还会再写一次磁盘——Nginx 缓冲只是第一关,后端接收方式也得匹配


















