Nginx 日志切割不依赖文件名而依赖文件描述符(fd),重命名不影响写入;真正切换日志需先 mv 再发 SIGUSR1 信号,否则会丢日志或混写。

靠文件描述符(fd)机制,不是靠文件名。Nginx 启动时用 open() 打开日志文件,拿到一个内核分配的 fd,之后所有写入都通过这个 fd 进行——和文件名、路径完全无关。
为什么 mv 不丢日志
执行 mv /var/log/nginx/access.log /var/log/nginx/access.log-20260820 时,只是修改了目录项(dentry)指向的文件名,底层 inode 和数据块没变,Nginx 持有的 fd 仍有效,继续往同一位置写数据。
- Linux 写文件本质是向 fd 对应的 inode 写,不是向“名字”写
- 只要没关闭 fd 或进程退出,重命名、移动甚至删除文件名都不影响写入
- 可验证:切割后运行
ls -li /var/log/nginx/,新旧文件 inode 号一致
USR1 信号才是切换的关键
重命名只是准备动作;真正让 Nginx 停止写旧文件、开始写新文件的,是向 Master 进程发送 SIGUSR1(即 nginx -s reopen 或 kill -USR1 $(cat /var/run/nginx.pid))。
- Master 收到 USR1 后,按配置中
access_log指定的路径,以 worker 用户身份重新 open() 日志文件(创建新空文件或截断已有文件) - 再通知所有 worker 关闭旧 fd,并把新 fd 绑定到日志写入逻辑上
- 此时旧文件才真正“释放”,不再有进程持有其 fd,可安全压缩、归档或删除
漏掉任一环节就会丢日志
只重命名不发 USR1 → Nginx 继续往已改名的文件写,新文件始终为空;只发 USR1 不重命名 → 新旧文件同名,旧日志被覆盖或追加混杂,失去时间边界。
- 标准顺序必须是:重命名旧文件 → 发送 USR1 → 验证新文件有新增内容(如 curl 测试后
stat -c "%z %s" access.log) - 脚本中建议加锁、检查 pid 文件存在性、确认 nginx 进程用户对新路径有写权限
- 避免用
cp + truncate或copytruncate类操作,它们非原子,可能丢失正在写入的缓冲区数据


















