应排除动态日志路径并用--ignore-failed-read容错,配合USR1信号冻结或logrotate截断,再以nohup守护定时打包。

直接在定时任务里调用 tar 打包,却不排除动态日志文件(比如 access.log、error.log 或应用自建的 runtime/logs/),极易触发 “文件在读取时发生变化” 报错,导致整个打包流程中断——这不是 tar 崩溃,而是它主动中止以避免归档不一致。关键不是“怎么让它不报错”,而是“怎么让备份既可靠又安静地完成”。
明确要排除的动态日志路径
别靠猜测,先定位真实日志目录。常见位置包括:
- Web 服务:/www/wwwroot/example.com/logs/、/var/log/nginx/、/var/log/apache2/
- PHP 应用:/www/wwwroot/example.com/runtime/logs/、/storage/logs/
- Node.js 或 Java 服务:项目根目录下的
logs/、log/或通过配置指定的绝对路径
确认后,在 tar 命令中用 --exclude 显式剔除。注意写法:路径需相对于当前工作目录,且不加尾部斜杠(--exclude=logs ✅,--exclude=logs/ ❌ 可能失效)。
用 --ignore-failed-read 容忍瞬时变化
即使排除了大部分日志目录,某些残留小日志(如 systemd-journal 日志、临时 debug 文件)仍可能被其他进程写入。这时加上 --ignore-failed-read 参数,能让 tar 遇到“文件变化”类读取失败时跳过该文件,继续打包其余内容:
更稳妥:打包前做轻量级冻结
对要求强一致性的场景(如数据库配套日志、审计日志),光忽略不够。可搭配简单冻结策略:
- 对 Nginx/Apache:执行
kill -USR1 $(cat /var/run/nginx.pid)(重开日志文件,旧文件变只读) - 对自定义日志:用 logrotate 的
copytruncate模式或脚本先mv app.log app.log.bak && touch app.log - 打包完成后再清理旧日志(如
find /path/to/logs -name "*.bak" -mtime +7 -delete)
把 tar 放进 nohup + 定时任务组合
避免因 SSH 断连或终端退出导致进程终止。在 crontab 中这样写:
0 2 * * * cd /www/wwwroot/example.com && nohup tar -cf /www/backup/site_$(date +\%Y%m%d).tar --exclude=logs --exclude=cache --ignore-failed-read . > /dev/null 2>&1 &注意:nohup 必须和 tar 在同一行命令中启动,且确保目标备份路径(如 /www/backup/)有足够空间(建议预留源目录 1.5 倍容量)。

















