Nginx 日志切割后磁盘空间未释放,是因为 Nginx 工作进程仍持有旧日志文件的文件描述符,导致 inode 未被清除。最推荐的处理方向是在 logrotate 配置文件的 postrotate 段落中调用 nginx -s reopen 命令,适用所有标准 Linux 发行版,风险边界在于配置错误可能导致日志写入中断或权限不足。
先说结论:必须通过 postrotate 脚本通知 Nginx 重新打开日志文件,否则旧文件空间无法回收。
- 适合:使用 logrotate 管理 Nginx 访问日志和错误日志的生产环境。
- 先准备:确认 Nginx 进程 PID 文件位置及 logrotate 配置权限。
- 验收:执行 logrotate -f 强制切割后,检查磁盘占用和文件描述符状态。
命令速用版
在/etc/logrotate.d/nginx 配置文件中,确保包含以下 postrotate 脚本片段,用于发送信号:
/var/log/nginx/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
prerotate
if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
run-parts /etc/logrotate.d/httpd-prerotate; \
fi \
endscript
postrotate
[ ! -f /var/run/nginx.pid ] || kill -USR1 `cat /var/run/nginx.pid`
endscript
}注意 postrotate 中的 PID 文件路径需与实际 Nginx 配置一致,通常为/var/run/nginx.pid 或/usr/local/nginx/logs/nginx.pid。
为什么会这样
Linux 文件删除机制依赖 inode 引用计数,进程持有文件描述符时删除文件不会释放空间。
当 logrotate 默认执行 move 操作重命名日志文件时,原文件路径消失但 inode 仍被 Nginx 进程占用。只有进程关闭文件描述符或重新打开新文件,操作系统才会回收磁盘块。Nginx 收到 USR1 信号后会关闭当前日志文件句柄并重新打开新文件,从而释放旧文件空间。
分步处理
第一步:编辑 logrotate 配置。
使用 vim 打开/etc/logrotate.d/nginx,检查 postrotate 段落是否存在且 PID 路径正确。适用场景为所有通过包管理器安装的 Nginx 环境,操作动作是修改配置文件,风险边界是语法错误会导致 logrotate 执行失败。
第二步:验证配置语法。
执行命令 logrotate -d /etc/logrotate.d/nginx 进行调试模式测试。验证结果是输出中无 ERROR 字样,风险边界是调试模式不会实际切割文件。
第三步:强制测试切割。
执行命令 logrotate -f /etc/logrotate.d/nginx 强制立即切割。操作动作是手动触发,验证结果是生成新日志文件且旧文件被压缩,风险边界是可能产生少量日志间隙。
怎么验证是否生效
使用 lsof 命令查看 deleted 文件,使用 df 命令查看磁盘使用率。
执行 lsof | grep nginx | grep deleted,若输出为空则表示无进程持有已删除文件。执行 df -h 查看对应挂载点使用率是否下降。若空间未释放,检查 Nginx 错误日志/var/log/nginx/error.log 确认是否有权限拒绝信号的错误。
常见坑
copytruncate 模式可能导致高并发下日志丢失。
部分配置使用 copytruncate 参数直接 trunc 原文件,虽能释放空间但会在复制和截断间隙丢失日志,生产环境建议优先使用 signal 方式。
权限不足导致 signal 发送失败。
logrotate 通常以 root 运行,但若 Nginx 启动用户特殊,需确保 kill 命令有权限发送信号给 Nginx 主进程。
PID 文件路径不一致。
不同发行版 PID 文件位置不同,Debian/Ubuntu 多在/var/run/nginx.pid,CentOS 可能在/var/run/nginx.pid 或编译自定义路径,需核对 nginx.conf 中 pid 指令。
常见问题
为什么不能用 kill -HUP?
HUP 信号会重载配置,reopen 信号仅重开日志,后者更安全。
发送 HUP 信号会导致 Nginx 重新读取配置文件,可能引发配置错误导致服务重启,而 USR1 信号专门用于日志重开,不影响业务配置。
手动如何释放空间?
找到进程 PID 后发送 USR1 信号即可触发日志重开。
执行 kill -USR1 `cat /var/run/nginx.pid` 可立即触发日志重开,适用于紧急止血场景,但长期仍需修复 logrotate 配置。
日志文件为何显示大小为 0?
新文件刚创建尚未写入数据,或权限配置错误导致 Nginx 无法写入。
检查 create 指令后的权限设置,确保 Nginx 工作进程用户有权写入新日志文件,否则新文件将为空且错误日志会记录 permission denied。
参考来源
- Nginx Official Documentation, "Controling nginx", https://nginx.org/en/docs/control.html
- Nginx Official Documentation, "Module ngx_http_log_module", https://nginx.org/en/docs/http/ngx_http_log_module.html
- Linux Man Pages, "logrotate(8)", https://man7.org/linux/man-pages/man8/logrotate.8.html