logrotate期间磁盘I/O暴增导致响应延迟,主因是同步写入、重命名及服务未及时reopen日志句柄;应禁用copytruncate,改用create+sharedscripts配合kill -USR1或graceful reload,并将日志与归档路径分置不同磁盘。

logrotate 期间磁盘 I/O 暴增导致响应延迟
logrotate 执行时若配置不当,会触发大量同步写入和重命名操作,尤其在高并发写日志场景下,copytruncate 或 create 模式都可能造成短暂但明显的请求阻塞。Apache、Nginx 或 PHP-FPM 进程在日志文件被移动或清空瞬间,若未及时 reopen 文件句柄,会出现 write 失败或 fallback 到 stderr,进一步拖慢处理链路。
- 避免使用
copytruncate:它看似安全(先拷贝再清空原文件),但清空操作本质是ftruncate(),在大日志文件上仍需等待磁盘刷盘;更糟的是,某些应用(如旧版 rsyslog)不会自动 reload 句柄,导致日志丢失或写入失败 - 优先用
create+sharedscripts:让 logrotate 创建新文件后,显式调用kill -USR1(Nginx)或systemctl reload apache2(Apache)来通知服务 reopen 日志,确保无中断 - 把日志路径和 rotate 目录放在不同磁盘分区:比如
/var/log/app.log在 SSD 分区,而/var/log/rotate/在另一块盘,减少 rotate 时的 I/O 竞争
PHP-FPM 写日志时被 logrotate 中断
PHP 默认通过 error_log 配置写入文件,该过程是同步阻塞的。当 logrotate 移动 php-error.log 后,PHP-FPM 不会自动检测文件消失,而是持续向已删除的 inode 写数据——这本身不报错,但内核 buffer 堆积,最终触发 write 系统调用超时或 fallback 到 syslog,间接拉高响应时间。
- 确认 PHP-FPM 的
error_log配置是否指向被 rotate 的文件路径;如果是,必须配合rotate脚本中的postrotate段 reload:例如systemctl reload php*-fpm - 不要依赖
tail -F类工具监控日志——它们会在文件被 rename 后卡住,占用 fd 并影响系统资源 - 对 debug 级别日志,直接关闭或改用异步方式(如
syslog协议发往rsyslog,由其统一 rotate)
access.log 切割引发 Apache 请求排队
Apache 使用 rotatelogs 或外部 logrotate 切割 access.log 时,若进程未及时 reopen,新请求的日志会暂存于内存 buffer,直到 buffer 满或超时 flush。buffer 满后,httpd worker 进程会阻塞在 write(),表现为 Requests Queued、mod_status 中 W(Sending Reply)状态堆积。
- 检查 Apache 是否启用
BufferedLogs:设为On可缓解,但不能根治;真正有效的是确保 rotate 后执行apachectl graceful(非 restart),让子进程平滑切换日志句柄 - 避免在业务高峰时段触发 rotate:用
daily+delaycompress+maxage 30组合,再配合 cron 时间偏移(如设为30 2 * * *而非整点)分散压力 - 如果用
rotatelogs内建切割,注意其-l(本地时区)参数缺失会导致时间戳错乱,间接影响日志分析节奏
MySQL 慢查询日志 rotate 导致锁表或 IO 尖峰
MySQL 的 slow_query_log_file 被 logrotate rename 后,若未正确 reload,mysqld 会继续往已 rename 的文件写入(Linux 允许),但该文件不再受 rotate 控制;更危险的是,某些配置下 MySQL 会尝试 fopen() 新路径失败后 fallback 到错误路径,甚至卡在 open 阶段。
- 必须在
postrotate中执行mysql -e "SET GLOBAL slow_query_log = OFF; SET GLOBAL slow_query_log = ON;",强制刷新日志句柄——比service mysql reload更轻量且可靠 - 禁止对
slow_query_log_file使用copytruncate:MySQL 不支持该模式,会导致日志写入中断或损坏 - 把
slow_query_log_file路径设为独立小分区(如/ssd/mysql-slow.log),避免和ibdata1或 binlog 争抢同一磁盘队列
关键点在于:所有日志 rotate 都不是“切完就完”,服务进程是否真正拿到了新文件句柄,比切割动作本身更重要。漏掉 reload 或 graceful 步骤,等于只做了半件事。


















