Nginx 日志切割后文件未释放空间仍占满磁盘怎么配置 logrotate

文章导读
Nginx 日志切割后磁盘空间未释放,是因为 Nginx 工作进程仍持有旧日志文件的文件描述符,导致 inode 未被清除。最推荐的处理方向是在 logrotate 配置文件的 postrotate 段落中调用 nginx -s reopen 命令,适用所有标准 Linux 发行版,风险边界在于配置错误可能导致日志写入中断或权限不足。
📋 目录
  1. 命令速用版
  2. 为什么会这样
  3. 分步处理
  4. 怎么验证是否生效
  5. 常见坑
  6. 常见问题
  7. 参考来源
A A

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 配置。

Nginx 日志切割后文件未释放空间仍占满磁盘怎么配置 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 确认是否有权限拒绝信号的错误。

Nginx 日志切割后文件未释放空间仍占满磁盘怎么配置 logrotate

常见坑

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 指令。

Nginx 日志切割后文件未释放空间仍占满磁盘怎么配置 logrotate

常见问题

为什么不能用 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