一、问题描述
现象
线上服务器磁盘空间持续被占用,上服务器查询未发现有新增大文件,但是磁盘空间占用还在持续上升。- 通过
df -h
和du -sh
对比发现,磁盘占用与实际文件大小不符,存在大量已删除但未释放的文件句柄。 - 使用
lsof | grep delete
定位到Nginx进程持有已删除的临时文件(如proxy_temp
目录下的文件)。 - 观察磁盘的io情况,发现nginx的io时速很快,基本在100-300M/s,
- iotop工具:
- 尝试回收空间lsof +D 缓存目录
- sync #先同步缓存数据
- echo 1 > /proc/sys/vm/drop_caches:表示清除pagecache。
echo 2 > /proc/sys/vm/drop_caches:表示清除回收slab分配器中的对象(包括目录项缓存和inode缓存)。slab分配器是内核中管理内存的一种机制,其中很多缓存数据实现都是用的pagecache。
echo 3 > /proc/sys/vm/drop_caches:表示清除pagecache和slab分配器中的缓存对象。
- 空间均未释放,后尝试重启Nginx,磁盘空间迅速恢复释放200G。
- 重启后Nginx占用空间再次迅速上升,未释放进程也快速增加。
- 怀疑可能是日志问题,查看access.log和error.log均未发现异常。
- 尝试重启服务器,重启完启动Nginx,磁盘占用问题还是存在。
- 排查磁盘读写问题:
- time dd if=/dev/zero of=/data/nginx/data.txt bs=1024k count=10
- time dd if=/data/nginx/data.txt of=/dev/null bs=1024k count=10
- 读写速度均可以达到500M/s以上
- 排除磁盘问题
- 通过
根本原因
- 确定原因是nginx问题
- 尝试修改Nginx的配置项
# 设置临时文件目录(支持多级子目录)
proxy_temp_path /data/nginx/proxy_temp;proxy_buffering off;
# 可选:限制临时文件最大尺寸(默认1024MB)
# proxy_max_temp_file_size 50m;# client_body_buffer_size 128k;
# proxy_buffer_size 8k;
# 可选:控制单次写入的临时文件大小(默认8KB)
# proxy_temp_file_write_size 16k;#proxy_buffers 16 64k; # 缓冲区数量和单缓冲区大小
# proxy_buffer_size 128k; # 响应头缓冲区大小
# proxy_busy_buffers_size 256k; # 忙碌缓冲区大小# 调整临时文件参数
# proxy_max_temp_file_size 500m; # 临时文件最大 500MB
# proxy_temp_file_write_size 512k; # 每次写入 512KB挨个尝试后,在试到关闭缓存时,发现磁盘占用不上升。修改配置后上线观察。问题初步解决,后续待继续观察。
二、排查过程
定位占用文件
- 执行命令:
bash
lsof | grep '(deleted)'
- 发现Nginx进程(如PID 4765、4766)持有已删除的临时文件句柄,路径包括
/data/nginx/proxy_temp/
下的多个文件。
- 执行命令:
分析文件类型
- 通过
lsof
输出确认,占用空间最大的文件为proxy_temp
目录下的临时文件(如0000000052
、0000000059
等),大小均超过500MB。
- 通过
验证日志影响
- 检查
access.log
和error.log
,未发现明显异常
- 检查
三、解决方案
核心配置调整
- 关闭
proxy_buffering
:在Nginx配置中添加proxy_buffering off;
,禁止Nginx缓存响应数据到临时文件,直接写入后端服务器。此操作可消除临时文件占用磁盘的问题。nginx
location /api/ { proxy_pass http://backend; proxy_buffering off; }
- 关闭
辅助优化措施
- 日志自动轮转:
- 使用
logrotate
配置日志切割,保留14天历史日志并压缩归档。 - 示例配置(
/etc/logrotate.d/nginx
):bash
/var/log/nginx/*.log { daily rotate 14 compress missingok notifempty create 640 nginx adm sharedscripts postrotate [ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid` endscript }
- 使用
- 限制缓存与临时文件空间:
- 配置
proxy_temp_path
、client_body_temp_path
并设置最大空间(如1GB),避免临时文件无限增长。 - 配置
fastcgi_cache_path
限制缓存大小(如2GB)并设置过期时间。
- 配置
- 日志自动轮转:
系统级优化
- 监控与告警:使用
Prometheus + Grafana
监控磁盘使用率,设置80%阈值告警。 - 独立存储日志/缓存:将日志和缓存目录迁移至独立分区或SSD,避免主分区空间不足。
- 监控与告警:使用
四、实施效果
- 临时文件释放:关闭
proxy_buffering
后,Nginx不再生成临时文件,lsof
中无(deleted)
状态的文件句柄。 - 日志管理:日志轮转生效,历史日志被压缩归档,磁盘空间占用稳定。
- 服务稳定性:反向代理请求响应正常,未再出现502错误。
五、总结
关键结论
proxy_buffering off
通过禁用Nginx缓存机制,直接写入后端响应,从根本上解决了临时文件占用磁盘的问题。- 结合日志轮转、缓存限制和系统监控,可全面保障Nginx的稳定运行。
后续建议
- 定期检查Nginx进程的文件句柄使用情况,避免因代码或配置问题导致资源泄漏。
- 考虑使用Nginx Plus或企业版,其提供更高级的缓存管理和资源监控功能。