Nginx 日志轮转怎么做:从文件句柄查到定时任务

解释 Nginx 日志改名后为何仍写旧文件,配置 logrotate 与 USR1,核对大小阈值、保留份数、执行频率和容器日志的不同处理。

·8 minNginxlogrotateVPSLinux
把应用部署到土耳其|BRNCHOST · 土耳其 VDS
云服务器,积分可续期|雨云 · 国内外节点 · 积分兑换权益
低价年付,大流量 VPS|RackNerd · SSD 存储 · 1Gbps 端口
香港轻量,搭个小站|晚安云 · 香港云服务器
香港 VPS,大带宽可选|野草云 · BGP 直连
大陆访问,精品线路|搬瓦工 · CN2 GIA / CTGNet 套餐
资料归档,交给 AI 整理|WorkBuddy · 本地文件处理
建站起步,先看应用镜像|腾讯云 · 轻量应用服务器
CN2 GIA,中国方向优化|DMIT · Premium 网络
双 ISP 原生住宅 IP|丽萨主机 · 美国 9929 精品线路
高频 CPU,多地部署|Evoxt · 云服务器 · 每周异地备份
京东云轻量云主机:129元/年,新人专享,限购1台

把 access.log 改名为 access.log.1,再创建一个新的 access.log,Nginx 不一定会开始往新文件写。进程已经打开的文件描述符仍指向旧文件,路径换了,写入对象却可以保持不变。这正是日志目录看起来轮转成功,旧文件却继续增长的常见原因。

在直接安装 Nginx 的 Linux 服务器上,可以让 logrotate 管理改名、保留和压缩,再通知 Nginx 重新打开日志。下面围绕这一种部署说明;容器标准输出的处理放在后面单独讨论。

先确认是谁写日志、谁负责轮转

不要立即向 /etc/logrotate.d/ 新增文件。发行版安装包可能已经提供了 Nginx 规则,管理面板也可能自带切割任务。两套任务处理同一目录,会引入重复改名、状态冲突和找不到文件的问题。

先看 Nginx 的实际配置、进程和已有规则。以下命令用于检查,配置输出可能包含内部域名,分享给别人前应先处理敏感信息。

sudo nginx -T
ps -eo pid,ppid,user,args | grep '[n]ginx'
sudo ls -l /etc/logrotate.d/
systemctl list-timers --all

从输出里记下 access log、error log 和 PID 文件的真实路径。有的站点使用单独目录,有的将访问日志写到 syslog,还有的对某些 location 关闭日志。一个 /var/log/nginx/*.log 并不会覆盖所有情况。

同时确认运行身份。Nginx 主进程和工作进程可能由不同用户运行,日志目录又可能属于另一位用户。后续 create 的权限要按这套实际关系设置,而不是机械使用网上例子里的用户名。

改名后,用 USR1 重新打开日志

Nginx 官方说明的轮转过程是先改名,再向主进程发送 USR1。主进程与工作进程随后重新打开日志,旧文件才适合继续压缩和归档。HUP 用于重载配置,USR1 则直接对应重新打开日志,无需为了切日志重启服务。Nginx 进程控制文档列出了这些信号。

手工观察时,可以比较轮转前后的 inode,并查看进程打开了哪些文件。Linux 上 lsof 可辅助确认;如果旧文件已经删除但进程仍持有句柄,磁盘空间可能还没有释放。此时 du 和 df 看起来不同,并不一定是统计工具出错。

不要为了释放空间直接结束所有 Nginx 进程。先确认哪个进程持有哪些日志,检查重新打开是否成功。若问题涉及异常实例或权限,再制定相应处理。仅仅看目录中出现新文件,无法证明工作进程已经切过去。

一份规则应该写明适用条件

下面示例假定:日志位于 /var/log/nginx,主进程 PID 文件为 /run/nginx.pid,系统存在 www-data 与 adm,规则以 root 执行。你的系统不满足这些条件时,先改路径和身份。发行版已有规则则优先在原规则上调整,避免重叠。

/var/log/nginx/*.log {
    daily
    maxsize 100M
    rotate 14
    missingok
    notifempty
    compress
    delaycompress
    create 0640 www-data adm
    sharedscripts
    postrotate
        if [ -s /run/nginx.pid ]; then
            kill -USR1 "$(cat /run/nginx.pid)"
        fi
    endscript
}

create 指定新文件权限,sharedscripts 使这组日志的后置动作只执行一次。delaycompress 将刚轮转的那一份延后压缩,给读取旧日志的程序留出空间;它不能代替重新打开日志,也不会修好失败的信号发送。

还要知道一个限制:上面的脚本在 PID 文件缺失时不会发信号。因此正式运维中应确认服务在运行时 PID 文件可靠存在,并对异常缺失报警。如果一个目录由多个 Nginx 实例写入,单一 PID 就不够,需要分别制定规则。

各指令的准确含义和脚本错误行为可查 logrotate 手册。本例是一份需要按环境调整的配置,不是适用于所有发行版的安装脚本。

100M 是检查条件,不是硬容量上限

daily 配合 maxsize 100M,可以在到达每日周期之前,因文件过大而触发轮转。但 logrotate 必须先被执行,才会检查条件。每天运行一次的定时任务,无法让高速增长的日志在越过 100 MB 的瞬间切割。

假设一个服务每小时写入 80 MB 日志,任务一天只执行一次。即使写了 maxsize 100M,它仍可能在两次检查之间增长到接近 2 GB。若要更早切割,就要调整调用频率,并检查压缩耗时是否会与下一轮重叠。

rotate 14 表示保留轮转份数,不保证保留十四个自然日。每天切多次,覆盖的时间就会缩短。故障调查要求保留七天时,应按高峰日志量估算磁盘,再选择份数或集中日志存储策略。

估算时可以把活跃日志、未压缩归档、压缩归档及安全余量分别列出。压缩率受内容影响,不能预设一定缩小十倍。日志增长异常也可能来自重复报错或扫描请求,扩大磁盘之前,先看增长最快的是哪个文件、哪些记录。

若正在为博客或反向代理准备独立环境,可以从下面的配置入口挑选合适的磁盘容量。先把应用、备份和日志分别留出空间,再决定机器规格。

高防 / BGP,按需选线路|雨云云服务器 · 依地区与套餐提供

先干跑,再安排一次可观察的轮转

logrotate -d 用来查看判断过程,不实际改动日志,也不更新状态文件。它能帮助发现路径和配置问题,却不会替你验证脚本真的执行成功,更不能证明 Nginx 收到了信号。

sudo logrotate -d /etc/logrotate.conf

确认规则没有重叠后,可以在低流量时段,对目标规则安排一次强制轮转。-f 会执行真实操作,应先确认归档保留策略和磁盘空间;不要拿全系统规则作为首次实验对象。

sudo logrotate -v -f /etc/logrotate.d/nginx

轮转前发一个带独特路径标记的请求,轮转后再发另一个。检查前一个标记是否在旧日志,后一个是否进入新日志,同时检查 error log 和命令退出状态。测试地址应使用自己的站点,避免把一次外部请求成功误认作本机写入成功。

若请求经过 CDN,可能由缓存直接响应而没有抵达源站。此时应访问明确会到达这台 Nginx 的路径,或在授权范围内直接检查源站。验证动作和实际写日志的实例必须对应。

copytruncate 有什么代价

有些程序不能重新打开日志,于是会采用复制当前文件,再截断原文件的方式。logrotate 的 copytruncate 支持这种处理,但复制与截断之间存在时间窗口,期间写入的部分内容可能丢失。

Nginx 已经提供重新打开日志的机制,通常没有必要为了省一条信号命令改用这种方式。对正在排查偶发故障的系统,一小段缺失日志也可能很难解释。若确实因环境限制使用它,应把这个行为纳入日志完整性预期。

另一个常见混淆是清空文件等于轮转。清空可以腾空间,却不会自动保留旧记录,也没有解决后续增长和执行频率。紧急处理后仍要回到规则、调度和报警,避免几天后再遇到相同问题。

容器里的 Nginx 要换一个检查入口

如果 access log 指向标准输出,error log 指向标准错误,日志由容器运行时接收。此时主机上的 /var/log/nginx 可能与这些日志无关,复制一份宿主机 logrotate 规则不会产生预期效果。

Docker 的日志驱动决定存储与轮转方式。默认 json-file 若未配置大小限制,可能持续占用磁盘;也可以根据环境选择带轮转能力的驱动。修改守护进程默认值不会自动改变已创建容器的日志设置,需要按文档处理既有容器。Docker 日志配置解释了这些差异。

不要直接移动或截断 Docker 内部管理的日志文件,再期待运行时能够自行恢复。检查容器的日志驱动、配置和创建时间,通过受控重建应用新规则。若 Nginx 仍写入挂载目录中的普通文件,则继续按文件轮转处理,但要明确由哪个系统发送信号。

让第二天的自动执行也能被看见

手动强制轮转成功以后,最后一项检查是调度。使用 systemd timer 的机器查看执行记录和下一次时间;使用 cron 的环境查看实际任务与相关日志。精简容器里没有定时服务时,仅把配置文件复制进去不会自动运行。

还应给轮转失败、磁盘余量和 inode 用量设置观察点。保留一份最近成功执行的时间、归档数量和最大日志大小,后续就能区分“流量增长太快”与“任务三天没有执行”。

真正验收这项配置时,不妨隔一天再看同一组文件:新请求仍写入活跃日志,旧日志按预期压缩,保留窗口没有提前缩短,定时任务也留下了成功记录。一次强制执行只能证明那一次操作;持续运行需要这些记录一起说明。